branch: elpa/clojure-ts-mode
commit 83d1aed86b385d39b06fc5daf5c32d07960e23e9
Author: Roman Rudakov <rruda...@fastmail.com>
Commit: Bozhidar Batsov <bozhi...@batsov.dev>

    Better handling of namespaced maps
---
 CHANGELOG.md                             |  3 +--
 clojure-ts-mode.el                       | 36 +++++++++++++++++++++-----------
 test/clojure-ts-mode-indentation-test.el |  7 ++++++-
 test/samples/refactoring.clj             |  8 ++++---
 4 files changed, 36 insertions(+), 18 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 189cfb9c61..5a6b385df2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,8 +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`.
-- Fix an issue where `clojure-ts-align` would hang when called within an
-  expression containing ignored forms.
+- [#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 cc10a65069..f69082e6bf 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."
@@ -1640,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))
@@ -1686,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 2f6d4e3d8f..bda3538b9e 100644
--- a/test/clojure-ts-mode-indentation-test.el
+++ b/test/clojure-ts-mode-indentation-test.el
@@ -604,4 +604,9 @@ b |20])"
 
     "{:map      \"with\"
  :multiple \"ignored\"
- #_#_:forms \"foo\"}"))
+ #_#_:forms \"foo\"}")
+
+  (when-aligning-it "should support namespaced maps"
+    "#:hello {:world          true
+         :foo            \"bar\"
+         :some-very-long \"value\"}"))
diff --git a/test/samples/refactoring.clj b/test/samples/refactoring.clj
index 641e3c56d1..c7547bfd16 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

Reply via email to