Skip to content

Commit

Permalink
Support indenting lists (#137)
Browse files Browse the repository at this point in the history
Add `:indent-with-indicator` dumper option to support indenting of lists

Closes #136
  • Loading branch information
lread authored Sep 9, 2024
1 parent 55130d1 commit 78861f9
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 32 deletions.
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

0 comments on commit 78861f9

Please sign in to comment.