branch: elpa/clojure-ts-mode
commit 31f12ea1e386fe0e8eb3641e8b55bd0103eeb111
Author: Roman Rudakov <[email protected]>
Commit: Bozhidar Batsov <[email protected]>
[#124] Correctly indent keyword-initial lists in 'fixed' style
When using the 'fixed' indentation style, lists where the first
element is a keyword (e.g., `(:foo ...)`) should have their children
indented by a single space, per the style description.
---
CHANGELOG.md | 2 +
clojure-ts-mode.el | 9 +--
test/clojure-ts-mode-indentation-test.el | 122 +++++++++++++++++++------------
3 files changed, 83 insertions(+), 50 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3bf23ec015d..d24c7ec992e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,8 @@
- [#118](https://github.com/clojure-emacs/clojure-ts-mode/pull/118): Add some
ns manipulation functions from `clojure-mode`.
- Fix a bug in `clojure-ts-add-arity` when body has more than one expression.
- [#120](https://github.com/clojure-emacs/clojure-ts-mode/issues/120): Fix a
bug when symbols with metadata were not listed in imenu.
+- [#124](https://github.com/clojure-emacs/clojure-ts-mode/issues/124):
Correctly indent lists that start with a keyword when using the
+ `fixed` indentation style.
## 0.5.1 (2025-06-17)
diff --git a/clojure-ts-mode.el b/clojure-ts-mode.el
index c35b357e303..2dd73ad4209 100644
--- a/clojure-ts-mode.el
+++ b/clojure-ts-mode.el
@@ -1003,9 +1003,9 @@ If there is no namespace, returns nil."
(defun clojure-ts--node-child-skip-metadata (node n)
"Return the Nth child of NODE like `treesit-node-child', sans metadata.
Skip the optional metadata node at pos 0 if present."
- (let ((value-nodes (thread-last (treesit-node-children node t)
- (seq-filter (lambda (child)
- (string=
(treesit-node-field-name child) "value"))))))
+ (let ((value-nodes (seq-filter (lambda (child)
+ (string= (treesit-node-field-name child)
"value"))
+ (treesit-node-children node t))))
(seq-elt value-nodes n)))
(defun clojure-ts--first-value-child (node)
@@ -1213,8 +1213,7 @@ The possible values for this variable are
(and (clojure-ts--list-node-p parent)
;; Should we also check for keyword first child, as in (:k map)
calls?
(let ((first-child (treesit-node-child parent 0 t)))
- (or (clojure-ts--symbol-node-p first-child)
- (clojure-ts--keyword-node-p first-child)))))
+ (clojure-ts--symbol-node-p first-child))))
parent 2)
((parent-is "vec_lit") parent 1)
((parent-is "map_lit") parent 1)
diff --git a/test/clojure-ts-mode-indentation-test.el
b/test/clojure-ts-mode-indentation-test.el
index d158ed8469b..abe06ff7c88 100644
--- a/test/clojure-ts-mode-indentation-test.el
+++ b/test/clojure-ts-mode-indentation-test.el
@@ -24,6 +24,7 @@
(require 'clojure-ts-mode)
(require 'cl-lib)
(require 'buttercup)
+(require 'test-helper "test/test-helper")
(require 's nil t) ;Don't burp if it's missing during
compilation.
@@ -74,6 +75,25 @@ DESCRIPTION is a string with the description of the spec."
(expect (buffer-string) :to-equal ,(concat "\n" form))))
forms))))
+(defmacro when-indenting-fixed-it (description &rest forms)
+ "Return a buttercup spec.
+
+Check that all FORMS correspond to properly indented sexps.
+
+DESCRIPTION is a string with the description of the spec.
+
+Sets `clojure-ts-indent-style' to `fixed'."
+ (declare (indent 1))
+ `(it ,description
+ (progn
+ ,@(mapcar (lambda (form)
+ `(with-temp-buffer
+ (let ((clojure-ts-indent-style 'fixed))
+ (clojure-ts-mode)
+ (insert "\n" ,form);,(replace-regexp-in-string "\n +"
"\n " form))
+ (indent-region (point-min) (point-max))
+ (expect (buffer-string) :to-equal ,(concat "\n"
form)))))
+ forms))))
(defmacro when-aligning-it (description &rest forms)
"Return a buttercup spec.
@@ -179,32 +199,32 @@ DESCRIPTION is a string with the description of the spec."
[_foo]
(+ 1 1))")
-(when-indenting-it "should support function calls via vars"
- "
+ (when-indenting-it "should support function calls via vars"
+ "
(#'foo 5
6)")
-(when-indenting-it "should support function literals"
- "
+ (when-indenting-it "should support function literals"
+ "
#(or true
false
%)")
-(when-indenting-it "should support block-0 expressions"
- "
+ (when-indenting-it "should support block-0 expressions"
+ "
(do (aligned)
(vertically))"
- "
+ "
(do
(indented)
(with-2-spaces))"
- "
+ "
(future
(body is indented))"
- "
+ "
(try
(something)
;; A bit of block 2 rule
@@ -214,108 +234,112 @@ DESCRIPTION is a string with the description of the
spec."
e-info
\"Second argument is aligned vertically with the first one.\"))")
-(when-indenting-it "should support block-1 expressions"
- "
+ (when-indenting-it "should support block-1 expressions"
+ "
(case x
2 (print 2)
3 (print 3)
(print \"Default\"))"
- "
+ "
(cond-> {}
:always (assoc :hello \"World\")
false (do nothing))"
- "
+ "
(with-precision 32
(/ (bigdec 20) (bigdec 30)))"
- "
+ "
(testing \"Something should work\"
(is (something-working?)))")
-(when-indenting-it "should support block-2 expressions"
- "
+ (when-indenting-it "should support block-2 expressions"
+ "
(are [x y]
(= x y)
2 3
4 5
6 6)"
- "
+ "
(as-> {} $
(assoc $ :hello \"World\"))"
- "
+ "
(as-> {}
my-map
(assoc my-map :hello \"World\"))"
- "
+ "
(defrecord MyThingR []
IProto
(foo [this x] x))")
-(when-indenting-it "should support inner-0 expressions"
- "
+ (when-indenting-it "should support inner-0 expressions"
+ "
(fn named-lambda [x]
(+ x x))"
- "
+ "
(defmethod hello :world
[arg1 arg2]
(+ arg1 arg2))"
- "
+ "
(reify
AutoCloseable
(close
[this]
(is properly indented)))")
-(it "should prioritize custom semantic indentation rules"
- (with-clojure-ts-buffer "
+ (it "should prioritize custom semantic indentation rules"
+ (with-clojure-ts-buffer "
(are [x y]
(= x y)
2 3
4 5
6 6)"
- (setopt clojure-ts-semantic-indent-rules '(("are" . ((:block 1)))))
- (indent-region (point-min) (point-max))
- (expect (buffer-string) :to-equal "
+ (setopt clojure-ts-semantic-indent-rules '(("are" . ((:block 1)))))
+ (indent-region (point-min) (point-max))
+ (prog1
+ (expect (buffer-string) :to-equal "
(are [x y]
(= x y)
2 3
4 5
- 6 6)")))
+ 6 6)")
+ ;; `setopt' cannot set variable locally so we need to restore it's
+ ;; original value.
+ (setopt clojure-ts-semantic-indent-rules nil))))
-(it "should indent collections elements with metadata correctly"
- "
+ (it "should indent collections elements with metadata correctly"
+ "
(def x
[a b [c ^:foo
d
e]])"
- "
+ "
#{x
y ^:foo
z}"
- "
+ "
{:hello ^:foo
\"world\"
:foo
\"bar\"}")
-(it "should indent body of special forms correctly considering metadata"
- "
+ (it "should indent body of special forms correctly considering metadata"
+ "
(let [result ^long
(if true
1
2)])")
-(it "should pick up dynamic indentation rules from
clojure-ts-get-indent-function"
- (with-clojure-ts-buffer "
+ (it "should pick up dynamic indentation rules from
clojure-ts-get-indent-function"
+ (with-clojure-ts-buffer "
(defmacro my-with-in-str
\"[DOCSTRING]\"
{:style/indent 1}
@@ -324,9 +348,9 @@ DESCRIPTION is a string with the description of the spec."
(my-with-in-str \"34\"
(prompt \"How old are you?\"))"
- (setq-local clojure-ts-get-indent-function #'cider--get-symbol-indent-mock)
- (indent-region (point-min) (point-max))
- (expect (buffer-string) :to-equal "
+ (setq-local clojure-ts-get-indent-function
#'cider--get-symbol-indent-mock)
+ (indent-region (point-min) (point-max))
+ (expect (buffer-string) :to-equal "
(defmacro my-with-in-str
\"[DOCSTRING]\"
{:style/indent 1}
@@ -336,7 +360,7 @@ DESCRIPTION is a string with the description of the spec."
(my-with-in-str \"34\"
(prompt \"How old are you?\"))"))
- (with-clojure-ts-buffer "
+ (with-clojure-ts-buffer "
(defmacro my-letfn
\"[DOCSTRING]\"
{:style/indent [1 [[:defn]] :form]}
@@ -349,9 +373,9 @@ DESCRIPTION is a string with the description of the spec."
(* (twice y) 3))]
(println \"Twice 15 =\" (twice 15))
(println \"Six times 15 =\" (six-times 15)))"
- (setq-local clojure-ts-get-indent-function #'cider--get-symbol-indent-mock)
- (indent-region (point-min) (point-max))
- (expect (buffer-string) :to-equal "
+ (setq-local clojure-ts-get-indent-function
#'cider--get-symbol-indent-mock)
+ (indent-region (point-min) (point-max))
+ (expect (buffer-string) :to-equal "
(defmacro my-letfn
\"[DOCSTRING]\"
{:style/indent [1 [[:defn]] :form]}
@@ -363,7 +387,15 @@ DESCRIPTION is a string with the description of the spec."
(six-times [y]
(* (twice y) 3))]
(println \"Twice 15 =\" (twice 15))
- (println \"Six times 15 =\" (six-times 15)))"))))
+ (println \"Six times 15 =\" (six-times 15)))")))
+
+ (when-indenting-fixed-it "should indent children of a list with 2 spaces if
first node is a symbol"
+ "(ns indentation
+ (:require
+ [clojure.string :as str])
+ (:import
+ (java.util Date
+ UUID)))"))
(describe "clojure-ts-align"
(it "should handle improperly indented content"