@@ -125,6 +125,23 @@ double quotes on the third column."
125
125
:type 'boolean
126
126
:package-version '(clojure-ts-mode . " 0.2.4" ))
127
127
128
+ (defcustom clojure-ts-semantic-indent-rules nil
129
+ " Custom rules to extend default indentation rules for `semantic' style.
130
+
131
+ Each rule is an alist entry which looks like `(\" symbol-name\"
132
+ . (rule-type rule-value))', where rule-type is one either `:block' or
133
+ `:inner' and rule-value is an integer. The semantic is similar to
134
+ cljfmt indentation rules.
135
+
136
+ Default set of rules is defined in
137
+ `clojure-ts--semantic-indent-rules-defaults' ."
138
+ :safe #'listp
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))
143
+ :package-version '(clojure-ts-mode . " 0.2.4" ))
144
+
128
145
(defvar clojure-ts-mode-remappings
129
146
'((clojure-mode . clojure-ts-mode)
130
147
(clojurescript-mode . clojure-ts-clojurescript-mode)
@@ -182,7 +199,6 @@ Only intended for use at development time.")
182
199
table)
183
200
" Syntax table for `clojure-ts-mode' ." )
184
201
185
-
186
202
(defconst clojure-ts--builtin-dynamic-var-regexp
187
203
(eval-and-compile
188
204
(concat " ^"
@@ -746,34 +762,135 @@ The possible values for this variable are
746
762
((parent-is " list_lit" ) parent 1 )
747
763
((parent-is " set_lit" ) parent 2 ))))
748
764
749
- (defvar clojure-ts--symbols-with-body-expressions-regexp
750
- (eval-and-compile
751
- (rx (or
752
- ; ; Match def* symbols,
753
- ; ; we also explicitly do not match symbols beginning with
754
- ; ; "default" "deflate" and "defer", like cljfmt
755
- (and line-start " def" )
756
- ; ; Match with-* symbols
757
- (and line-start " with-" )
758
- ; ; Exact matches
759
- (and line-start
760
- (or " alt!" " alt!!" " are" " as->"
761
- " binding" " bound-fn"
762
- " case" " catch" " comment" " cond" " condp" " cond->" " cond->>"
763
- " delay" " do" " doseq" " dotimes" " doto"
764
- " extend" " extend-protocol" " extend-type"
765
- " fdef" " finally" " fn" " for" " future"
766
- " go" " go-loop"
767
- " if" " if-let" " if-not" " if-some"
768
- " let" " letfn" " locking" " loop"
769
- " match" " ns" " proxy" " reify" " struct-map"
770
- " testing" " thread" " try"
771
- " use-fixtures"
772
- " when" " when-first" " when-let" " when-not" " when-some" " while" )
773
- line-end))))
774
- " A regex to match symbols that are functions/macros with a body argument.
775
- Taken from cljfmt:
776
- https://github.com/weavejester/cljfmt/blob/fb26b22f569724b05c93eb2502592dfc2de898c3/cljfmt/resources/cljfmt/indents/clojure.clj" )
765
+ (defvar clojure-ts--semantic-indent-rules-defaults
766
+ '((" alt!" . (:block 0 ))
767
+ (" alt!!" . (:block 0 ))
768
+ (" comment" . (:block 0 ))
769
+ (" cond" . (:block 0 ))
770
+ (" delay" . (:block 0 ))
771
+ (" do" . (:block 0 ))
772
+ (" finally" . (:block 0 ))
773
+ (" future" . (:block 0 ))
774
+ (" go" . (:block 0 ))
775
+ (" thread" . (:block 0 ))
776
+ (" try" . (:block 0 ))
777
+ (" with-out-str" . (:block 0 ))
778
+ (" defprotocol" . (:block 1 ))
779
+ (" binding" . (:block 1 ))
780
+ (" defprotocol" . (:block 1 ))
781
+ (" binding" . (:block 1 ))
782
+ (" case" . (:block 1 ))
783
+ (" cond->" . (:block 1 ))
784
+ (" cond->>" . (:block 1 ))
785
+ (" doseq" . (:block 1 ))
786
+ (" dotimes" . (:block 1 ))
787
+ (" doto" . (:block 1 ))
788
+ (" extend" . (:block 1 ))
789
+ (" extend-protocol" . (:block 1 ))
790
+ (" extend-type" . (:block 1 ))
791
+ (" for" . (:block 1 ))
792
+ (" go-loop" . (:block 1 ))
793
+ (" if" . (:block 1 ))
794
+ (" if-let" . (:block 1 ))
795
+ (" if-not" . (:block 1 ))
796
+ (" if-some" . (:block 1 ))
797
+ (" let" . (:block 1 ))
798
+ (" letfn" . (:block 1 ))
799
+ (" locking" . (:block 1 ))
800
+ (" loop" . (:block 1 ))
801
+ (" match" . (:block 1 ))
802
+ (" ns" . (:block 1 ))
803
+ (" struct-map" . (:block 1 ))
804
+ (" testing" . (:block 1 ))
805
+ (" when" . (:block 1 ))
806
+ (" when-first" . (:block 1 ))
807
+ (" when-let" . (:block 1 ))
808
+ (" when-not" . (:block 1 ))
809
+ (" when-some" . (:block 1 ))
810
+ (" while" . (:block 1 ))
811
+ (" with-local-vars" . (:block 1 ))
812
+ (" with-open" . (:block 1 ))
813
+ (" with-precision" . (:block 1 ))
814
+ (" with-redefs" . (:block 1 ))
815
+ (" defrecord" . (:block 2 ))
816
+ (" deftype" . (:block 2 ))
817
+ (" are" . (:block 2 ))
818
+ (" as->" . (:block 2 ))
819
+ (" catch" . (:block 2 ))
820
+ (" condp" . (:block 2 ))
821
+ (" bound-fn" . (:inner 0 ))
822
+ (" def" . (:inner 0 ))
823
+ (" defmacro" . (:inner 0 ))
824
+ (" defmethod" . (:inner 0 ))
825
+ (" defmulti" . (:inner 0 ))
826
+ (" defn" . (:inner 0 ))
827
+ (" defn-" . (:inner 0 ))
828
+ (" defonce" . (:inner 0 ))
829
+ (" deftest" . (:inner 0 ))
830
+ (" fdef" . (:inner 0 ))
831
+ (" fn" . (:inner 0 ))
832
+ (" reify" . (:inner 0 ))
833
+ (" use-fixtures" . (:inner 0 )))
834
+ " Default semantic indentation rules.
835
+
836
+ The format reflects cljfmt indentation rules. All the default rules are
837
+ aligned with
838
+ https://github.com/weavejester/cljfmt/blob/0.13.0/cljfmt/resources/cljfmt/indents/clojure.clj" )
839
+
840
+ (defun clojure-ts--match-block-0-body (bol first-child )
841
+ " Match if expression body is not at the same line as FIRST-CHILD.
842
+
843
+ If there is no body, check that BOL is not at the same line."
844
+ (let* ((body-pos (if-let* ((body (treesit-node-next-sibling first-child)))
845
+ (treesit-node-start body)
846
+ bol)))
847
+ (< (line-number-at-pos (treesit-node-start first-child))
848
+ (line-number-at-pos body-pos))))
849
+
850
+ (defun clojure-ts--node-pos-match-block (node parent bol block )
851
+ " Return TRUE if NODE index in the PARENT matches requested BLOCK.
852
+
853
+ NODE might be nil (when we insert an empty line for example), in this
854
+ case we look for next available child node in the PARENT after BOL
855
+ position.
856
+
857
+ The first node in the expression is usually an opening paren, the last
858
+ node is usually a closing paren (unless some automatic parens mode is
859
+ not enabled). If requested BLOCK is 1, the NODE index should be at
860
+ least 3 (first node is opening paren, second node is matched symbol,
861
+ third node is first argument, and the rest is body which should be
862
+ indented.)"
863
+ (if node
864
+ (> (treesit-node-index node) (1+ block))
865
+ (when-let* ((node-after-bol (treesit-node-first-child-for-pos parent bol)))
866
+ (> (treesit-node-index node-after-bol) (1+ block)))))
867
+
868
+ (defun clojure-ts--match-form-body (node parent bol )
869
+ " Match if NODE has to be indented as a for body.
870
+
871
+ PARENT not should be a list. If first symbol in the expression has an
872
+ indentation rule in `clojure-ts--semantic-indent-rules-defaults' or
873
+ `clojure-ts-semantic-indent-rules' check if NODE should be indented
874
+ according to the rule. If NODE is nil, use next node after BOL."
875
+ (and (clojure-ts--list-node-p parent)
876
+ (let ((first-child (clojure-ts--node-child-skip-metadata parent 0 )))
877
+ (when-let* ((rule (alist-get (clojure-ts--named-node-text first-child)
878
+ (seq-union clojure-ts-semantic-indent-rules
879
+ clojure-ts--semantic-indent-rules-defaults
880
+ (lambda (e1 e2 ) (equal (car e1) (car e2))))
881
+ nil
882
+ nil
883
+ #'equal )))
884
+ (and (not (clojure-ts--match-with-metadata node))
885
+ (let ((rule-type (car rule))
886
+ (rule-value (cadr rule)))
887
+ (if (equal rule-type :block )
888
+ (if (zerop rule-value)
889
+ ; ; Special treatment for block 0 rule.
890
+ (clojure-ts--match-block-0-body bol first-child)
891
+ (clojure-ts--node-pos-match-block node parent bol rule-value))
892
+ ; ; Return true for any inner rule.
893
+ t )))))))
777
894
778
895
(defun clojure-ts--match-function-call-arg (node parent _bol )
779
896
" Match NODE if PARENT is a list expressing a function or macro call."
@@ -787,24 +904,6 @@ https://github.com/weavejester/cljfmt/blob/fb26b22f569724b05c93eb2502592dfc2de89
787
904
(clojure-ts--keyword-node-p first-child)
788
905
(clojure-ts--var-node-p first-child)))))
789
906
790
- (defun clojure-ts--match-expression-in-body (node parent _bol )
791
- " Match NODE if it is an expression used in a body argument.
792
- PARENT is expected to be a list literal.
793
- See `treesit-simple-indent-rules' ."
794
- (and
795
- (clojure-ts--list-node-p parent)
796
- (let ((first-child (clojure-ts--node-child-skip-metadata parent 0 )))
797
- (and
798
- (not
799
- (clojure-ts--symbol-matches-p
800
- ; ; Symbols starting with this are false positives
801
- (rx line-start (or " default" " deflate" " defer" ))
802
- first-child))
803
- (not (clojure-ts--match-with-metadata node))
804
- (clojure-ts--symbol-matches-p
805
- clojure-ts--symbols-with-body-expressions-regexp
806
- first-child)))))
807
-
808
907
(defun clojure-ts--match-method-body (_node parent _bol )
809
908
" Matches a `NODE' in the body of a `PARENT' method implementation.
810
909
A method implementation referes to concrete implementations being defined in
@@ -885,7 +984,7 @@ forms like deftype, defrecord, reify, proxy, etc."
885
984
(clojure-ts--match-docstring parent 0 )
886
985
; ; https://guide.clojure.style/#body-indentation
887
986
(clojure-ts--match-method-body parent 2 )
888
- (clojure-ts--match-expression-in -body parent 2 )
987
+ (clojure-ts--match-form -body parent 2 )
889
988
; ; https://guide.clojure.style/#threading-macros-alignment
890
989
(clojure-ts--match-threading-macro-arg prev-sibling 0 )
891
990
; ; https://guide.clojure.style/#vertically-align-fn-args
0 commit comments