diff --git a/CHANGELOG.md b/CHANGELOG.md index 600eabd..5a6b385 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ - [#91](https://github.com/clojure-emacs/clojure-ts-mode/pull/91): Introduce `clojure-ts-cycle-keyword-string`. - [#92](https://github.com/clojure-emacs/clojure-ts-mode/pull/92): Add commands to convert between collections types. - [#93](https://github.com/clojure-emacs/clojure-ts-mode/pull/93): Introduce `clojure-ts-add-arity`. +- [#94](https://github.com/clojure-emacs/clojure-ts-mode/pull/94): Add indentation rules and `clojure-ts-align` support for namespaced maps. ## 0.3.0 (2025-04-15) diff --git a/clojure-ts-mode.el b/clojure-ts-mode.el index 56fcd07..f69082e 100644 --- a/clojure-ts-mode.el +++ b/clojure-ts-mode.el @@ -1410,17 +1410,23 @@ if NODE has metadata and its parent has type NODE-TYPE." (clojure-ts--node-child-skip-metadata parent n)))) (defun clojure-ts--semantic-indent-rules () - "Return a list of indentation rules for `treesit-simple-indent-rules'." + "Return a list of indentation rules for `treesit-simple-indent-rules'. + +NOTE: All built-in matchers (such as `parent-is' etc) expect a node type +regex. Therefore, if the string map_lit is used, it will incorrectly +match both map_lit and ns_map_lit. To prevent this, more precise +regexes with anchors matching the beginning and end of the line are +used." `((clojure - ((parent-is "source") parent-bol 0) + ((parent-is "^source$") parent-bol 0) (clojure-ts--match-docstring parent 0) ;; Collections items with metadata. ;; ;; This should be before `clojure-ts--match-with-metadata', otherwise they ;; will never be matched. - (,(clojure-ts--match-collection-item-with-metadata "vec_lit") grand-parent 1) - (,(clojure-ts--match-collection-item-with-metadata "map_lit") grand-parent 1) - (,(clojure-ts--match-collection-item-with-metadata "set_lit") grand-parent 2) + (,(clojure-ts--match-collection-item-with-metadata "^vec_lit$") grand-parent 1) + (,(clojure-ts--match-collection-item-with-metadata "^map_lit$") grand-parent 1) + (,(clojure-ts--match-collection-item-with-metadata "^set_lit$") grand-parent 2) ;; ;; If we enable this rule for lists, it will break many things. ;; (,(clojure-ts--match-collection-item-with-metadata "list_lit") grand-parent 1) @@ -1428,12 +1434,13 @@ if NODE has metadata and its parent has type NODE-TYPE." ;; All other forms with metadata. (clojure-ts--match-with-metadata parent 0) ;; Literal Sequences - ((parent-is "vec_lit") parent 1) ;; https://guide.clojure.style/#bindings-alignment - ((parent-is "map_lit") parent 1) ;; https://guide.clojure.style/#map-keys-alignment - ((parent-is "set_lit") parent 2) - ((parent-is "splicing_read_cond_lit") parent 4) - ((parent-is "read_cond_lit") parent 3) - ((parent-is "tagged_or_ctor_lit") parent 0) + ((parent-is "^vec_lit$") parent 1) ;; https://guide.clojure.style/#bindings-alignment + ((parent-is "^map_lit$") parent 1) ;; https://guide.clojure.style/#map-keys-alignment + ((parent-is "^set_lit$") parent 2) + ((parent-is "^splicing_read_cond_lit$") parent 4) + ((parent-is "^read_cond_lit$") parent 3) + ((parent-is "^tagged_or_ctor_lit$") parent 0) + ((parent-is "^ns_map_lit$") (nth-sibling 2) 1) ;; https://guide.clojure.style/#body-indentation (clojure-ts--match-form-body clojure-ts--anchor-parent-opening-paren 2) ;; https://guide.clojure.style/#threading-macros-alignment @@ -1441,7 +1448,7 @@ if NODE has metadata and its parent has type NODE-TYPE." ;; https://guide.clojure.style/#vertically-align-fn-args (clojure-ts--match-function-call-arg ,(clojure-ts--anchor-nth-sibling 1) 0) ;; https://guide.clojure.style/#one-space-indent - ((parent-is "list_lit") parent 1)))) + ((parent-is "^list_lit$") parent 1)))) (defun clojure-ts--configured-indent-rules () "Gets the configured choice of indent rules." @@ -1505,7 +1512,8 @@ function literal." "var_quoting_lit" "sym_val_lit" "evaling_lit" "tagged_or_ctor_lit" "splicing_read_cond_lit" "derefing_lit" "quoting_lit" "syn_quoting_lit" - "unquote_splicing_lit" "unquoting_lit") + "unquote_splicing_lit" "unquoting_lit" + "dis_expr") "A regular expression that matches nodes that can be treated as s-expressions.") (defconst clojure-ts--list-nodes @@ -1639,6 +1647,7 @@ have changed." (query (treesit-query-compile 'clojure (append `(((map_lit) @map) + ((ns_map_lit) @ns-map) ((list_lit ((sym_lit) @sym (:match ,(clojure-ts-symbol-regexp clojure-ts-align-binding-forms) @sym)) @@ -1685,6 +1694,10 @@ subsequent special arguments based on block indentation rules." (goto-char (treesit-node-start node)) (when-let* ((cur-sexp (treesit-node-first-child-for-pos node (point) t))) (goto-char (treesit-node-start cur-sexp)) + ;; For namespaced maps we need to skip the namespace, which is the first + ;; nested sexp. + (when (equal sexp-type 'ns-map) + (treesit-beginning-of-thing 'sexp -1 'nested)) ;; For cond forms we need to skip first n + 1 nodes according to block ;; indentation rules. First node to skip is the symbol itself. (when (equal sexp-type 'cond) diff --git a/test/clojure-ts-mode-indentation-test.el b/test/clojure-ts-mode-indentation-test.el index 942175a..bda3538 100644 --- a/test/clojure-ts-mode-indentation-test.el +++ b/test/clojure-ts-mode-indentation-test.el @@ -596,4 +596,17 @@ b |20])" :a (let [a 1 aa (+ a 1)] aa); comment - :aa 2)")) + :aa 2)") + + (when-aligning-it "should work correctly when there are ignored forms" + "{:map \"with\" + :some #_\"ignored\" \"form\"}" + + "{:map \"with\" + :multiple \"ignored\" + #_#_:forms \"foo\"}") + + (when-aligning-it "should support namespaced maps" + "#:hello {:world true + :foo \"bar\" + :some-very-long \"value\"}")) diff --git a/test/samples/align.clj b/test/samples/align.clj index f70e767..b7933f3 100644 --- a/test/samples/align.clj +++ b/test/samples/align.clj @@ -55,3 +55,10 @@ aa (+ a 1)] aa); comment :aa 2) + +{:map "with" + :some #_"ignored" "form"} + +{:map "with" + :multiple "ignored" + #_#_:forms "foo"} diff --git a/test/samples/refactoring.clj b/test/samples/refactoring.clj index 641e3c5..c7547bf 100644 --- a/test/samples/refactoring.clj +++ b/test/samples/refactoring.clj @@ -89,10 +89,12 @@ [1 2 3] -;; TODO: Define indentation rule for `ns_map_lit` -#:hello{:name "Roma" - :world true} +#:hello {:world true + :foo "bar" + :some-very-long "value"} +{:name "Roma" + :foo true} (reify java.io.FileFilter