Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support indenting lists #137

Merged
merged 1 commit into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ Clj-yaml makes use of SnakeYAML, please also refer to the https://bitbucket.org/
** Bump `org.flatland/ordered` to `1.15.12`
(https://github.com/clj-commons/clj-yaml/issues/123[#123])
(https://github.com/lread[@lread])
** Add `:indent-with-indicator` dumper option to support indenting lists
(https://github.com/clj-commons/clj-yaml/issues/136[#136])
(https://github.com/lread[@lread])

== v1.0.27 - 2023-08-11 [[v1.0.27]]

Expand Down
120 changes: 99 additions & 21 deletions doc/01-user-guide.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -223,15 +223,16 @@ SnakeYAML implementation (that clj-yaml uses for low-level encoding and decoding
==== Dumper Options [[dumper-options]]
Different flow styles (`:auto`, `:block`, `:flow`) allow customization of how YAML is rendered.

To demonstrate let's setup `some-data` to play with.
To demonstrate, let's setup `some-data` to play with.

[source,clojure]
----
(def some-yaml "
todo:
- name: Fix issue
responsible:
name: Rita
issues:
- name: Fix all the things
responsible:
name: Rita
")

(def some-data (yaml/parse-string some-yaml))
Expand All @@ -247,45 +248,120 @@ results in a string of YAML, that when printed:
[source,yaml]
----
todo:
- name: Fix issue
responsible:
name: Rita
issues:
- name: Fix all the things
responsible:
name: Rita
----

The same but with the `:flow` style results in:
[source,yaml]
----
{todo: [{name: Fix issue, responsible: {name: Rita}}]}
{todo: {issues: [{name: Fix all the things, responsible: {name: Rita}}]}}
----

And finally the `:auto` style (the default) renders:
[source,yaml]
----
todo:
- name: Fix issue
responsible: {name: Rita}
issues:
- name: Fix all the things
responsible: {name: Rita}
----

Use the `:indent` and `:indicator-indent` options to adjust indentation:
==== Controlling Indentation

Use `:indent` to control block indentation, to override the default block indent of `2` with `4`:

[source,clojure]
----
(yaml/generate-string some-data :dumper-options {:indent 6
:indicator-indent 3
(yaml/generate-string some-data :dumper-options {:indent 4
:flow-style :block})
----

results in:
[source,yaml]
----
todo:
- name: Fix issue
responsible:
issues:
- name: Fix all the things
responsible:
name: Rita
----
Notice that each block is now indented by `4`.

`:indent` must always be larger than `:indicator-indent`.
If it is only 1 higher, the indicator will be on a separate line:
Use `:indicator-indent` to change the indentation of the `-` indicator; by default, it is `0`; let's bump it up to `2`:

[source,clojure]
----
(yaml/generate-string some-data :dumper-options {:indent 4
:indicator-indent 2
:flow-style :block})
----

results in:
[source,yaml]
----
todo:
issues:
- name: Fix all the things
responsible:
name: Rita
----
Notice that the blocks are still indented by 4, but the `-` indicator is now indented by `2`.

Indenting the `-` indicator within the block `:indent` can be limiting.
Sometimes, you'll want to indent `-` blocks more than other blocks.
Specifying `:indent-with-indicator true` makes block indentation for `-` indicators additive; the indicator is still indented by `:indicator-indent`, but its block is indented by `:indent` + `:indicator-indent`.

[source,clojure]
----
(yaml/generate-string some-data :dumper-options {:indent 4
:indicator-indent 2
:indent-with-indicator true
:flow-style :block})
----

results in:
[source,yaml]
----
todo:
issues:
- name: Fix all the things
responsible:
name: Rita
----
You'll notice that the `-` indicator is indented by `2`, but its block is now indented by `6` (`4` + `2`).

A common usage of `indent-with-indicator true` is to indent arrays like so:

[source,clojure]
----
(yaml/generate-string some-data :dumper-options {:indent 2
:indicator-indent 2
:indent-with-indicator true
:flow-style :block})
----
results in:

[source,yaml]
----
todo:
issues:
- name: Fix all the things
responsible:
name: Rita
----
We now have:

* a block indentation of `2` by default
* an `-` indicator indentation of `2`
* a block indentation of `4` for `-` indicator content

[TIP]
====
Unless you are using `:indent-with-indicator`, `:indicator-indent` must always be less than `:indent`.
If `:ident-with-indicator` is 1 less than `:indent`, the `-` indicator will be on a separate line:

[source,clojure]
----
Expand All @@ -297,11 +373,13 @@ results in:
[source,yaml]
----
todo:
-
name: Fix issue
responsible:
name: Rita
issues:
-
name: Fix all the things
responsible:
name: Rita
----
====

[[keyword-args]]
=== Function Options as Keyword Args
Expand Down
12 changes: 9 additions & 3 deletions src/clojure/clj_yaml/core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,16 @@

Returns internal SnakeYAML dumper options.
See [[generate-string]] for description of options."
^DumperOptions [{:keys [flow-style indent indicator-indent]}]
^DumperOptions [{:keys [flow-style indent indicator-indent indent-with-indicator]}]
(let [dumper (default-dumper-options)]
(when flow-style
(.setDefaultFlowStyle dumper (flow-styles flow-style)))
(when indent
(.setIndent dumper indent))
(when indicator-indent
(.setIndicatorIndent dumper indicator-indent))
(when indent-with-indicator
(.setIndentWithIndicator dumper indent-with-indicator))
dumper))

(defn default-loader-options
Expand Down Expand Up @@ -258,8 +260,12 @@
- default: `:auto`
- `:indent` - spaces to block indent
- default: `2`
- `:indicator-indent` - spaces to indent after indicator
- default: `0`"
- `:indicator-indent` - spaces to indent `-` indicator
- default: `0`
- `:indent-with-indicator` -
- `true` - indent blocks for `-` indicator by `:indent` + `:indicator-indent`
- `false` - indent blocks for `-` indicator by `:indent`
- default: `false`"
[data & opts]
(.dump ^Yaml (apply make-yaml opts)
(encode data)))
Expand Down
41 changes: 33 additions & 8 deletions test/clj_yaml/core_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -372,20 +372,45 @@ lol: yolo")
(parse-stream (->stream multi-doc-yaml) :load-all true))))
)

(def indented-yaml "todo:
- name: Fix issue
responsible:
name: Rita
(def indent-yaml "todo:
issues:
- name: Fix all the things
responsible: {name: Rita}
")

(deftest indentation-test
(testing "Can use indicator-indent and indent to achieve desired indentation"
(is (not= indented-yaml (generate-string (parse-string indented-yaml)
:dumper-options {:flow-style :block})))
(is (= indented-yaml
(generate-string (parse-string indented-yaml)
(is (= (str "todo:\n"
;12
" issues:\n"
" - name: Fix all the things\n"
" responsible:\n"
" name: Rita\n")
(generate-string (parse-string indent-yaml)
:dumper-options {:flow-style :block})))

(is (= (str "todo:\n"
;12345
" issues:\n"
;; 12345
" - name: Fix all the things\n"
" responsible:\n"
" name: Rita\n")
(generate-string (parse-string indent-yaml)
:dumper-options {:indent 5
:indicator-indent 2
:flow-style :block})))
(is (= (str "todo:\n"
;12345
" issues:\n"
; 1234567
" - name: Fix all the things\n"
" responsible:\n"
" name: Rita\n")
(generate-string (parse-string indent-yaml)
:dumper-options {:indent 5
:indicator-indent 2
:indent-with-indicator true
:flow-style :block})))))

(def yaml-with-unknown-tags "---
Expand Down