Skip to content

Commit

Permalink
Add support for zprint/cursive indentation
Browse files Browse the repository at this point in the history
Add a new configuration option, :function-arguments-indentation, that
can be one of: :community, :cursive or :zprint. This controls the
behavior described in: https://guide.clojure.style/#one-space-indent

When set to :community (the default) it follows the Clojure style guide.
When set to :cursive or :zprint, it follows the conventions used by
those tools.

Also add a --function-arguments-indentation option to update this at the
command line.
  • Loading branch information
miridius committed Dec 4, 2023
1 parent fb26b22 commit d84bd41
Show file tree
Hide file tree
Showing 4 changed files with 432 additions and 49 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,21 @@ In order to load the standard configuration file from Leiningen, add the
other references in the `ns` forms at the top of your namespaces.
Defaults to false.

* `:function-arguments-indentation` -
- `:community` if cljfmt should follow the [community style recommendation][]
to indent function/macro arguments by a single space when there
are no arguments on the same line as the function name.
- `:cursive` if two spaces should be used instead, unless the first
thing in the list (not counting metadata) is a data structure
literal. This should replicate Cursive's default behaviour.
- `:zprint` if two spaces should be used instead if the first thing
in the list is a symbol or keyword. This should replicate zprint's
default behaviour.

Defaults to `:community`

[indents.md]: docs/INDENTS.md
[community style recommendation]: https://guide.clojure.style/#one-space-indent

### Runtime Options

Expand Down
72 changes: 49 additions & 23 deletions cljfmt/src/cljfmt/core.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,28 @@
(count)
(dec)))

(defn- list-indent [zloc]
(defn- skip-meta [zloc]
(if (#{:meta :meta*} (z/tag zloc))
(-> zloc z/down z/right)
zloc))

(defn- cursive-two-space-list-indent? [zloc]
(-> zloc z/leftmost* skip-meta z/tag #{:vector :map :list :set} not))

(defn- zprint-two-space-list-indent? [zloc]
(-> zloc z/leftmost* z/tag #{:token :list}))

(defn two-space-list-indent? [zloc context]
(case (:function-arguments-indentation context)
:community false
:cursive (cursive-two-space-list-indent? zloc)
:zprint (zprint-two-space-list-indent? zloc)))

(defn- list-indent [zloc context]
(if (> (index-of zloc) 1)
(-> zloc z/leftmost* z/right margin)
(coll-indent zloc)))
(cond-> (coll-indent zloc)
(two-space-list-indent? zloc context) inc)))

(def indent-size 2)

Expand Down Expand Up @@ -288,13 +306,27 @@
(if (and (or (nil? zloc-after-idx) (first-form-in-line? zloc-after-idx))
(> (index-of zloc) idx))
(inner-indent zloc key 0 nil context)
(list-indent zloc)))))
(list-indent zloc context)))))

(def default-indents
(merge (read-resource "cljfmt/indents/clojure.clj")
(read-resource "cljfmt/indents/compojure.clj")
(read-resource "cljfmt/indents/fuzzy.clj")))

(def default-options
{:indentation? true
:insert-missing-whitespace? true
:remove-consecutive-blank-lines? true
:remove-multiple-non-indenting-spaces? false
:remove-surrounding-whitespace? true
:remove-trailing-whitespace? true
:split-keypairs-over-multiple-lines? false
:sort-ns-references? false
:function-arguments-indentation :community
:indents default-indents
:extra-indents {}
:alias-map {}})

(defmulti ^:private indenter-fn
(fn [_sym _context [type & _args]] type))

Expand All @@ -315,12 +347,12 @@

(defn- custom-indent [zloc indents context]
(if (empty? indents)
(list-indent zloc)
(list-indent zloc context)
(let [indenter (->> indents
(map #(make-indenter % context))
(apply some-fn))]
(or (indenter zloc)
(list-indent zloc)))))
(list-indent zloc context)))))

(defn- indent-amount [zloc indents context]
(let [tag (-> zloc z/up z/tag)
Expand All @@ -346,11 +378,15 @@
([form indents]
(indent form indents {}))
([form indents alias-map]
(indent form indents alias-map default-options))
([form indents alias-map opts]
(let [ns-name (find-namespace (z/of-node form))
sorted-indents (sort-by indent-order indents)]
sorted-indents (sort-by indent-order indents)
context (merge (select-keys opts [:function-arguments-indentation])
{:alias-map alias-map
:ns-name ns-name})]
(transform form edit-all should-indent?
#(indent-line % sorted-indents {:alias-map alias-map
:ns-name ns-name})))))
#(indent-line % sorted-indents context)))))

(defn- map-key? [zloc]
(and (z/map? (z/up zloc))
Expand Down Expand Up @@ -381,7 +417,9 @@
([form indents]
(indent (unindent form) indents))
([form indents alias-map]
(indent (unindent form) indents alias-map)))
(indent (unindent form) indents alias-map))
([form indents alias-map opts]
(indent (unindent form) indents alias-map opts)))

(defn final? [zloc]
(and (nil? (z/right* zloc)) (root? (z/up* zloc))))
Expand Down Expand Up @@ -486,19 +524,6 @@
(defn sort-ns-references [form]
(transform form edit-all ns-reference? sort-arguments))

(def default-options
{:indentation? true
:insert-missing-whitespace? true
:remove-consecutive-blank-lines? true
:remove-multiple-non-indenting-spaces? false
:remove-surrounding-whitespace? true
:remove-trailing-whitespace? true
:split-keypairs-over-multiple-lines? false
:sort-ns-references? false
:indents default-indents
:extra-indents {}
:alias-map {}})

(defn reformat-form
([form]
(reformat-form form {}))
Expand All @@ -519,7 +544,8 @@
remove-multiple-non-indenting-spaces)
(cond-> (:indentation? opts)
(reindent (merge (:indents opts) (:extra-indents opts))
(:alias-map opts)))
(:alias-map opts)
opts))
(cond-> (:remove-trailing-whitespace? opts)
remove-trailing-whitespace)))))

Expand Down
10 changes: 9 additions & 1 deletion cljfmt/src/cljfmt/main.clj
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,15 @@
:id :split-keypairs-over-multiple-lines?]
[nil "--[no-]sort-ns-references"
:default (:sort-ns-references? defaults)
:id :sort-ns-references?]])
:id :sort-ns-references?]
[nil "--function-arguments-indentation STYLE"
"STYLE may be community, cursive, or zprint"
:default (:function-arguments-indentation defaults)
:default-desc (name (:function-arguments-indentation defaults))
:parse-fn keyword
:validate [#{:community :cursive :zprint}
"Must be one of community, cursive, or zprint"]
:id :function-arguments-indentation]])

(defn- abort [& msg]
(binding [*out* *err*]
Expand Down
Loading

0 comments on commit d84bd41

Please sign in to comment.