@@ -137,9 +137,12 @@ Default set of rules is defined in
137
137
`clojure-ts--semantic-indent-rules-defaults' ."
138
138
:safe #'listp
139
139
:type '(alist :key-type string
140
- :value-type (list (choice (const :tag " Block indentation rule" :block )
141
- (const :tag " Inner indentation rule" :inner ))
142
- integer))
140
+ :value-type (repeat (choice (list (choice (const :tag " Block indentation rule" :block )
141
+ (const :tag " Inner indentation rule" :inner ))
142
+ integer)
143
+ (list (const :tag " Inner indentation rule" :inner )
144
+ integer
145
+ integer))))
143
146
:package-version '(clojure-ts-mode . " 0.2.4" ))
144
147
145
148
(defvar clojure-ts-mode-remappings
@@ -769,74 +772,73 @@ The possible values for this variable are
769
772
((parent-is " set_lit" ) parent 2 ))))
770
773
771
774
(defvar clojure-ts--semantic-indent-rules-defaults
772
- '((" alt!" . (:block 0 ))
773
- (" alt!!" . (:block 0 ))
774
- (" comment" . (:block 0 ))
775
- (" cond" . (:block 0 ))
776
- (" delay" . (:block 0 ))
777
- (" do" . (:block 0 ))
778
- (" finally" . (:block 0 ))
779
- (" future" . (:block 0 ))
780
- (" go" . (:block 0 ))
781
- (" thread" . (:block 0 ))
782
- (" try" . (:block 0 ))
783
- (" with-out-str" . (:block 0 ))
784
- (" defprotocol" . (:block 1 ))
785
- (" binding" . (:block 1 ))
786
- (" defprotocol" . (:block 1 ))
787
- (" binding" . (:block 1 ))
788
- (" case" . (:block 1 ))
789
- (" cond->" . (:block 1 ))
790
- (" cond->>" . (:block 1 ))
791
- (" doseq" . (:block 1 ))
792
- (" dotimes" . (:block 1 ))
793
- (" doto" . (:block 1 ))
794
- (" extend" . (:block 1 ))
795
- (" extend-protocol" . (:block 1 ))
796
- (" extend-type" . (:block 1 ))
797
- (" for" . (:block 1 ))
798
- (" go-loop" . (:block 1 ))
799
- (" if" . (:block 1 ))
800
- (" if-let" . (:block 1 ))
801
- (" if-not" . (:block 1 ))
802
- (" if-some" . (:block 1 ))
803
- (" let" . (:block 1 ))
804
- (" letfn" . (:block 1 ))
805
- (" locking" . (:block 1 ))
806
- (" loop" . (:block 1 ))
807
- (" match" . (:block 1 ))
808
- (" ns" . (:block 1 ))
809
- (" struct-map" . (:block 1 ))
810
- (" testing" . (:block 1 ))
811
- (" when" . (:block 1 ))
812
- (" when-first" . (:block 1 ))
813
- (" when-let" . (:block 1 ))
814
- (" when-not" . (:block 1 ))
815
- (" when-some" . (:block 1 ))
816
- (" while" . (:block 1 ))
817
- (" with-local-vars" . (:block 1 ))
818
- (" with-open" . (:block 1 ))
819
- (" with-precision" . (:block 1 ))
820
- (" with-redefs" . (:block 1 ))
821
- (" defrecord" . (:block 2 ))
822
- (" deftype" . (:block 2 ))
823
- (" are" . (:block 2 ))
824
- (" as->" . (:block 2 ))
825
- (" catch" . (:block 2 ))
826
- (" condp" . (:block 2 ))
827
- (" bound-fn" . (:inner 0 ))
828
- (" def" . (:inner 0 ))
829
- (" defmacro" . (:inner 0 ))
830
- (" defmethod" . (:inner 0 ))
831
- (" defmulti" . (:inner 0 ))
832
- (" defn" . (:inner 0 ))
833
- (" defn-" . (:inner 0 ))
834
- (" defonce" . (:inner 0 ))
835
- (" deftest" . (:inner 0 ))
836
- (" fdef" . (:inner 0 ))
837
- (" fn" . (:inner 0 ))
838
- (" reify" . (:inner 0 ))
839
- (" use-fixtures" . (:inner 0 )))
775
+ '((" alt!" . ((:block 0 )))
776
+ (" alt!!" . ((:block 0 )))
777
+ (" comment" . ((:block 0 )))
778
+ (" cond" . ((:block 0 )))
779
+ (" delay" . ((:block 0 )))
780
+ (" do" . ((:block 0 )))
781
+ (" finally" . ((:block 0 )))
782
+ (" future" . ((:block 0 )))
783
+ (" go" . ((:block 0 )))
784
+ (" thread" . ((:block 0 )))
785
+ (" try" . ((:block 0 )))
786
+ (" with-out-str" . ((:block 0 )))
787
+ (" defprotocol" . ((:block 1 ) (:inner 1 )))
788
+ (" binding" . ((:block 1 )))
789
+ (" case" . ((:block 1 )))
790
+ (" cond->" . ((:block 1 )))
791
+ (" cond->>" . ((:block 1 )))
792
+ (" doseq" . ((:block 1 )))
793
+ (" dotimes" . ((:block 1 )))
794
+ (" doto" . ((:block 1 )))
795
+ (" extend" . ((:block 1 )))
796
+ (" extend-protocol" . ((:block 1 ) (:inner 1 )))
797
+ (" extend-type" . ((:block 1 ) (:inner 1 )))
798
+ (" for" . ((:block 1 )))
799
+ (" go-loop" . ((:block 1 )))
800
+ (" if" . ((:block 1 )))
801
+ (" if-let" . ((:block 1 )))
802
+ (" if-not" . ((:block 1 )))
803
+ (" if-some" . ((:block 1 )))
804
+ (" let" . ((:block 1 )))
805
+ (" letfn" . ((:block 1 ) (:inner 2 0 )))
806
+ (" locking" . ((:block 1 )))
807
+ (" loop" . ((:block 1 )))
808
+ (" match" . ((:block 1 )))
809
+ (" ns" . ((:block 1 )))
810
+ (" struct-map" . ((:block 1 )))
811
+ (" testing" . ((:block 1 )))
812
+ (" when" . ((:block 1 )))
813
+ (" when-first" . ((:block 1 )))
814
+ (" when-let" . ((:block 1 )))
815
+ (" when-not" . ((:block 1 )))
816
+ (" when-some" . ((:block 1 )))
817
+ (" while" . ((:block 1 )))
818
+ (" with-local-vars" . ((:block 1 )))
819
+ (" with-open" . ((:block 1 )))
820
+ (" with-precision" . ((:block 1 )))
821
+ (" with-redefs" . ((:block 1 )))
822
+ (" defrecord" . ((:block 2 ) (:inner 1 )))
823
+ (" deftype" . ((:block 2 ) (:inner 1 )))
824
+ (" are" . ((:block 2 )))
825
+ (" as->" . ((:block 2 )))
826
+ (" catch" . ((:block 2 )))
827
+ (" condp" . ((:block 2 )))
828
+ (" bound-fn" . ((:inner 0 )))
829
+ (" def" . ((:inner 0 )))
830
+ (" defmacro" . ((:inner 0 )))
831
+ (" defmethod" . ((:inner 0 )))
832
+ (" defmulti" . ((:inner 0 )))
833
+ (" defn" . ((:inner 0 )))
834
+ (" defn-" . ((:inner 0 )))
835
+ (" defonce" . ((:inner 0 )))
836
+ (" deftest" . ((:inner 0 )))
837
+ (" fdef" . ((:inner 0 )))
838
+ (" fn" . ((:inner 0 )))
839
+ (" reify" . ((:inner 0 ) (:inner 1 )))
840
+ (" proxy" . ((:block 2 ) (:inner 1 )))
841
+ (" use-fixtures" . ((:inner 0 ))))
840
842
" Default semantic indentation rules.
841
843
842
844
The format reflects cljfmt indentation rules. All the default rules are
@@ -882,22 +884,87 @@ The returned value is expected to be the same as
882
884
`clojure-get-indent-function' from `clojure-mode' for compatibility
883
885
reasons." )
884
886
887
+ (defun clojure-ts--unwrap-dynamic-spec (spec current-depth )
888
+ " Recursively unwrap SPEC, incrementally increasing the CURRENT-DEPTH.
889
+
890
+ This function accepts a list SPEC, like ((:defn)) and produce a proper
891
+ indent rule. For example, ((:defn)) is converted to (:inner 2),
892
+ and (:defn) is converted to (:inner 1)."
893
+ (if (consp spec)
894
+ (clojure-ts--unwrap-dynamic-spec (car spec) (1+ current-depth))
895
+ (cond
896
+ ((equal spec :defn ) (list :inner current-depth))
897
+ (t nil ))))
898
+
885
899
(defun clojure-ts--dynamic-indent-for-symbol (symbol-name )
886
- " Return dynamic indentation spec for SYMBOL-NAME if found.
900
+ " Returns the dynamic indentation specification for SYMBOL-NAME, if found.
901
+
902
+ If the function `clojure-ts-get-indent-function' is defined, call it and
903
+ produce a valid indentation specification from its return value.
887
904
888
- If function `clojure-ts-get-indent-function' is not nil, call it and
889
- produce a valid indentation spec from the returned value.
905
+ The `clojure-ts-get-indent-function' should return an indentation
906
+ specification compatible with `clojure-mode' , which will then be
907
+ converted to a suitable `clojure-ts-mode' specification.
890
908
891
- The indentation rules for `clojure-ts-mode' are simpler than for
892
- `clojure-mode' so we only take the first integer N and produce `(:block
893
- N)' rule. If an integer cannot be found, this function returns nil and
894
- the default rule is used."
909
+ For example, (1 ((:defn)) nil) is converted to ((:block 1) (:inner 2))."
895
910
(when (functionp clojure-ts-get-indent-function)
896
911
(let ((spec (funcall clojure-ts-get-indent-function symbol-name)))
897
- (if (consp spec)
898
- `(:block ,(car spec))
899
- (when (integerp spec)
900
- `(:block , spec ))))))
912
+ (if (integerp spec)
913
+ (list (list :block spec))
914
+ (when (sequencep spec)
915
+ (thread-last spec
916
+ (seq-map (lambda (el )
917
+ (cond
918
+ ((integerp el) (list :block el))
919
+ ((equal el :defn ) (list :inner 0 ))
920
+ ((consp el) (clojure-ts--unwrap-dynamic-spec el 0 ))
921
+ (t nil ))))
922
+ (seq-remove #'null )
923
+ ; ; Always put `:block' to the beginning.
924
+ (seq-sort (lambda (spec1 _spec2 )
925
+ (equal (car spec1) :block )))))))))
926
+
927
+ (defun clojure-ts--find-semantic-rule (node parent current-depth )
928
+ " Returns a suitable indentation rule for NODE, considering the CURRENT-DEPTH.
929
+
930
+ Attempts to find an indentation rule by examining the symbol name of the
931
+ PARENT's first child. If a rule is not found, it navigates up the
932
+ syntax tree and recursively attempts to find a rule, incrementally
933
+ increasing the CURRENT-DEPTH. If a rule is not found upon reaching the
934
+ root of the syntax tree, it returns nil. A rule is considered a match
935
+ only if the CURRENT-DEPTH matches the rule's required depth."
936
+ (let* ((first-child (clojure-ts--node-child-skip-metadata parent 0 ))
937
+ (symbol-name (clojure-ts--named-node-text first-child))
938
+ (idx (- (treesit-node-index node) 2 )))
939
+ (if-let* ((rule-set (or (clojure-ts--dynamic-indent-for-symbol symbol-name)
940
+ (alist-get symbol-name
941
+ (seq-union clojure-ts-semantic-indent-rules
942
+ clojure-ts--semantic-indent-rules-defaults
943
+ (lambda (e1 e2 ) (equal (car e1) (car e2))))
944
+ nil
945
+ nil
946
+ #'equal ))))
947
+ (if (zerop current-depth)
948
+ (let ((rule (car rule-set)))
949
+ (if (equal (car rule) :block )
950
+ rule
951
+ (pcase-let ((`(, _ , rule-depth , rule-idx ) rule))
952
+ (when (and (equal rule-depth current-depth)
953
+ (or (null rule-idx)
954
+ (equal rule-idx idx)))
955
+ rule))))
956
+ (thread-last rule-set
957
+ (seq-filter (lambda (rule )
958
+ (pcase-let ((`(, rule-type , rule-depth , rule-idx ) rule))
959
+ (and (equal rule-type :inner )
960
+ (equal rule-depth current-depth)
961
+ (or (null rule-idx)
962
+ (equal rule-idx idx))))))
963
+ (seq-first)))
964
+ (when-let* ((new-parent (treesit-node-parent parent)))
965
+ (clojure-ts--find-semantic-rule parent
966
+ new-parent
967
+ (1+ current-depth))))))
901
968
902
969
(defun clojure-ts--match-form-body (node parent bol )
903
970
" Match if NODE has to be indented as a for body.
@@ -907,16 +974,8 @@ indentation rule in `clojure-ts--semantic-indent-rules-defaults' or
907
974
`clojure-ts-semantic-indent-rules' check if NODE should be indented
908
975
according to the rule. If NODE is nil, use next node after BOL."
909
976
(and (clojure-ts--list-node-p parent)
910
- (let* ((first-child (clojure-ts--node-child-skip-metadata parent 0 ))
911
- (symbol-name (clojure-ts--named-node-text first-child)))
912
- (when-let* ((rule (or (clojure-ts--dynamic-indent-for-symbol symbol-name)
913
- (alist-get symbol-name
914
- (seq-union clojure-ts-semantic-indent-rules
915
- clojure-ts--semantic-indent-rules-defaults
916
- (lambda (e1 e2 ) (equal (car e1) (car e2))))
917
- nil
918
- nil
919
- #'equal ))))
977
+ (let* ((first-child (clojure-ts--node-child-skip-metadata parent 0 )))
978
+ (when-let* ((rule (clojure-ts--find-semantic-rule node parent 0 )))
920
979
(and (not (clojure-ts--match-with-metadata node))
921
980
(let ((rule-type (car rule))
922
981
(rule-value (cadr rule)))
@@ -940,19 +999,6 @@ according to the rule. If NODE is nil, use next node after BOL."
940
999
(clojure-ts--keyword-node-p first-child)
941
1000
(clojure-ts--var-node-p first-child)))))
942
1001
943
- (defun clojure-ts--match-method-body (_node parent _bol )
944
- " Matches a `NODE' in the body of a `PARENT' method implementation.
945
- A method implementation referes to concrete implementations being defined in
946
- forms like deftype, defrecord, reify, proxy, etc."
947
- (and
948
- (clojure-ts--list-node-p parent)
949
- (let* ((grandparent (treesit-node-parent parent))
950
- ; ; auncle: gender neutral sibling of parent, aka child of grandparent
951
- (first-auncle (treesit-node-child grandparent 0 t )))
952
- (and (clojure-ts--list-node-p grandparent)
953
- (clojure-ts--symbol-matches-p clojure-ts--type-symbol-regexp
954
- first-auncle)))))
955
-
956
1002
(defvar clojure-ts--threading-macro
957
1003
(eval-and-compile
958
1004
(rx (and " ->" (? " >" ) line-end)))
@@ -1043,7 +1089,6 @@ if NODE has metadata and its parent has type NODE-TYPE."
1043
1089
((parent-is " source" ) parent-bol 0 )
1044
1090
(clojure-ts--match-docstring parent 0 )
1045
1091
; ; https://guide.clojure.style/#body-indentation
1046
- (clojure-ts--match-method-body parent 2 )
1047
1092
(clojure-ts--match-form-body clojure-ts--anchor-parent-skip-metadata 2 )
1048
1093
; ; https://guide.clojure.style/#threading-macros-alignment
1049
1094
(clojure-ts--match-threading-macro-arg prev-sibling 0 )
0 commit comments