diff --git a/README.md b/README.md index a0c6eaa5..29bb5078 100644 --- a/README.md +++ b/README.md @@ -305,6 +305,10 @@ In order to load the standard configuration file from Leiningen, add the true if cljfmt should correct the indentation of your code. Defaults to true. +* `:indent-rich-comments?` - + true if cljfmt should indent the closing parenthesis of `(comment ...)` + forms. Defaults to true. + * `:indents` - a map of var symbols to indentation rules, i.e. `{symbol [& rules]}`. See [INDENTS.md][] for a complete explanation. This will **replace** diff --git a/cljfmt/src/cljfmt/core.cljc b/cljfmt/src/cljfmt/core.cljc index f96da0c7..667bfa69 100644 --- a/cljfmt/src/cljfmt/core.cljc +++ b/cljfmt/src/cljfmt/core.cljc @@ -42,6 +42,17 @@ (defn- top? [zloc] (some-> zloc z/up root?)) +(defn- token? [zloc] + (= (z/tag zloc) :token)) + +(defn- comment-token? [zloc] + (and (token? zloc) + (= 'comment (z/sexpr zloc)))) + +(defn- comment-form? [zloc] + (and (= (z/tag zloc) :list) + (some-> zloc z/down comment-token?))) + (defn- root [zloc] (if (root? zloc) zloc (recur (z/up zloc)))) @@ -71,8 +82,26 @@ (not (comment? (z/right* zloc)))) (nil? (z/skip z/right* clojure-whitespace? zloc))))) -(defn remove-surrounding-whitespace [form] - (transform form edit-all surrounding-whitespace? z/remove*)) +(defn- indent-rich-comment-closing-paren? [zloc opts] + (and (:indent-rich-comments? opts) + (z/linebreak? zloc) + (nil? (z/skip z/right* clojure-whitespace? zloc)) + (comment-form? (z/up* zloc)))) + +(defn- insert-rich-comment-newlines [form opts] + (transform form edit-all + #(and (:indent-rich-comments? opts) + (comment-form? %) + (let [children (n/children (z/node %))] + (and (> (count (remove (some-fn n/comment? n/whitespace?) children)) 1) + (not (n/linebreak? (last children)))))) + #(z/append-child % (n/newlines 1)))) + +(defn remove-surrounding-whitespace [form opts] + (transform form edit-all + #(and (surrounding-whitespace? %) + (not (indent-rich-comment-closing-paren? % opts))) + z/remove*)) (defn- element? [zloc] (and zloc (not (z/whitespace-or-comment? zloc)))) @@ -159,13 +188,20 @@ (and (comment? znext) (not (line-comment? znext))))) (defn- should-indent? [zloc opts] - (and (line-break? zloc) - (if (:indent-line-comments? opts) - (not (comment-next-other-than-line-comment? zloc)) - (not (comment-next? zloc))))) + (or (and (:indent-rich-comments? opts) + (z/linebreak? zloc) + (nil? (z/skip z/right* clojure-whitespace? zloc)) + (comment-form? (z/up* zloc))) + (and (line-break? zloc) + (if (:indent-line-comments? opts) + (not (comment-next-other-than-line-comment? zloc)) + (not (comment-next? zloc)))))) (defn- should-unindent? [zloc opts] (and (indentation? zloc) + (not (and (:indent-rich-comments? opts) + (nil? (z/skip z/right* clojure-whitespace? zloc)) + (comment-form? (z/up* zloc)))) (if (:indent-line-comments? opts) (not (comment-next-other-than-line-comment? zloc)) (not (comment-next? zloc))))) @@ -259,9 +295,6 @@ (take-while (complement root?)) last))) -(defn- token? [zloc] - (= (z/tag zloc) :token)) - (defn- ns-token? [zloc] (and (token? zloc) (= 'ns (z/sexpr zloc)))) @@ -379,6 +412,7 @@ :extra-indents {} :function-arguments-indentation :community :indent-line-comments? false + :indent-rich-comments? true :indentation? true :indents default-indents :insert-missing-whitespace? true @@ -429,10 +463,22 @@ (let [tag (-> zloc z/up z/tag) gp (-> zloc z/up z/up)] (cond - (reader-conditional? gp) (coll-indent zloc) - (#{:list :fn} tag) (custom-indent zloc indents context) - (= :meta tag) (indent-amount (z/up zloc) indents context) - :else (coll-indent zloc)))) + (reader-conditional? gp) + (coll-indent zloc) + + (#{:list :fn} tag) + (custom-indent zloc indents context) + + (= :meta tag) + (indent-amount (z/up zloc) indents context) + + (and (:indent-rich-comments? context) + (nil? (z/skip z/right* clojure-whitespace? zloc)) + (comment-form? (z/up* zloc))) + (+ (margin (z/up* zloc)) indent-size) + + :else + (coll-indent zloc)))) (defn- indent-line [zloc indents context] (let [width (indent-amount zloc indents context)] @@ -453,7 +499,8 @@ ([form indents alias-map opts] (let [ns-name (find-namespace (z/of-node form)) sorted-indents (sort-by indent-order indents) - context (merge (select-keys opts [:function-arguments-indentation]) + context (merge (select-keys opts [:function-arguments-indentation + :indent-rich-comments?]) {:alias-map alias-map :ns-name ns-name})] (transform form edit-all #(should-indent? % opts) @@ -821,7 +868,9 @@ (cond-> (:remove-consecutive-blank-lines? opts) remove-consecutive-blank-lines) (cond-> (:remove-surrounding-whitespace? opts) - remove-surrounding-whitespace) + (remove-surrounding-whitespace opts)) + (cond-> (:indent-rich-comments? opts) + (insert-rich-comment-newlines opts)) (cond-> (:insert-missing-whitespace? opts) insert-missing-whitespace) (cond-> (:remove-multiple-non-indenting-spaces? opts) diff --git a/cljfmt/src/cljfmt/main.clj b/cljfmt/src/cljfmt/main.clj index 2b81ba2a..f39a41c6 100644 --- a/cljfmt/src/cljfmt/main.clj +++ b/cljfmt/src/cljfmt/main.clj @@ -44,6 +44,9 @@ [nil "--[no-]indent-line-comments" :default (:indent-line-comments? defaults) :id :indent-line-comments?] + [nil "--[no-]indent-rich-comments" + :default (:indent-rich-comments? defaults) + :id :indent-rich-comments?] [nil "--[no-]insert-missing-whitespace" :default (:insert-missing-whitespace? defaults) :id :insert-missing-whitespace?] diff --git a/cljfmt/test/cljfmt/core_test.cljc b/cljfmt/test/cljfmt/core_test.cljc index 5307ca36..d5e94616 100644 --- a/cljfmt/test/cljfmt/core_test.cljc +++ b/cljfmt/test/cljfmt/core_test.cljc @@ -1041,6 +1041,38 @@ ["#?@(:cljs[foo bar] :clj[baz quux])"] ["#?@(:cljs [foo bar] :clj [baz quux])"])))) +(deftest test-indent-rich-comments + (testing "indent-rich-comments?" + (is (reformats-to? + ["(comment" + " (range 5" + " )" + " (interpose '* (range 5))" + " (->> (range 5) (interpose '*))" + " (= *1 *2)" + " )"] + ["(comment" + " (range 5)" + " (interpose '* (range 5))" + " (->> (range 5) (interpose '*))" + " (= *1 *2)" + " )"] + {:indent-rich-comments? true})) + (is (reformats-to? + ["(comment" + " (foo)" + " )"] + ["(comment" + " (foo))"] + {:indent-rich-comments? false})) + (is (reformats-to? + ["(comment" + " (foo))"] + ["(comment" + " (foo)" + " )"] + {:indent-rich-comments? true})))) + (deftest test-consecutive-blank-lines (is (reformats-to? ["(foo)"