@@ -125,6 +125,22 @@ 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
+ :type '(alist :key-type string
139
+ :value-type (list (choice (const :tag " Block indentation rule" :block )
140
+ (const :tag " Inner indentation rule" :inner ))
141
+ integer))
142
+ :package-version '(clojure-ts-mode . " 0.2.4" ))
143
+
128
144
(defvar clojure-ts-mode-remappings
129
145
'((clojure-mode . clojure-ts-mode)
130
146
(clojurescript-mode . clojure-ts-clojurescript-mode)
@@ -182,7 +198,6 @@ Only intended for use at development time.")
182
198
table)
183
199
" Syntax table for `clojure-ts-mode' ." )
184
200
185
-
186
201
(defconst clojure-ts--builtin-dynamic-var-regexp
187
202
(eval-and-compile
188
203
(concat " ^"
@@ -746,34 +761,129 @@ The possible values for this variable are
746
761
((parent-is " list_lit" ) parent 1 )
747
762
((parent-is " set_lit" ) parent 2 ))))
748
763
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" )
764
+ (defvar clojure-ts--semantic-indent-rules-defaults
765
+ '((" alt!" . (:block 0 ))
766
+ (" alt!!" . (:block 0 ))
767
+ (" comment" . (:block 0 ))
768
+ (" cond" . (:block 0 ))
769
+ (" delay" . (:block 0 ))
770
+ (" do" . (:block 0 ))
771
+ (" finally" . (:block 0 ))
772
+ (" future" . (:block 0 ))
773
+ (" go" . (:block 0 ))
774
+ (" thread" . (:block 0 ))
775
+ (" try" . (:block 0 ))
776
+ (" with-out-str" . (:block 0 ))
777
+ (" defprotocol" . (:block 1 ))
778
+ (" binding" . (:block 1 ))
779
+ (" defprotocol" . (:block 1 ))
780
+ (" binding" . (:block 1 ))
781
+ (" case" . (:block 1 ))
782
+ (" cond->" . (:block 1 ))
783
+ (" cond->>" . (:block 1 ))
784
+ (" doseq" . (:block 1 ))
785
+ (" dotimes" . (:block 1 ))
786
+ (" doto" . (:block 1 ))
787
+ (" extend" . (:block 1 ))
788
+ (" extend-protocol" . (:block 1 ))
789
+ (" extend-type" . (:block 1 ))
790
+ (" for" . (:block 1 ))
791
+ (" go-loop" . (:block 1 ))
792
+ (" if" . (:block 1 ))
793
+ (" if-let" . (:block 1 ))
794
+ (" if-not" . (:block 1 ))
795
+ (" if-some" . (:block 1 ))
796
+ (" let" . (:block 1 ))
797
+ (" letfn" . (:block 1 ))
798
+ (" locking" . (:block 1 ))
799
+ (" loop" . (:block 1 ))
800
+ (" match" . (:block 1 ))
801
+ (" ns" . (:block 1 ))
802
+ (" struct-map" . (:block 1 ))
803
+ (" testing" . (:block 1 ))
804
+ (" when" . (:block 1 ))
805
+ (" when-first" . (:block 1 ))
806
+ (" when-let" . (:block 1 ))
807
+ (" when-not" . (:block 1 ))
808
+ (" when-some" . (:block 1 ))
809
+ (" while" . (:block 1 ))
810
+ (" with-local-vars" . (:block 1 ))
811
+ (" with-open" . (:block 1 ))
812
+ (" with-precision" . (:block 1 ))
813
+ (" with-redefs" . (:block 1 ))
814
+ (" defrecord" . (:block 2 ))
815
+ (" deftype" . (:block 2 ))
816
+ (" are" . (:block 2 ))
817
+ (" as->" . (:block 2 ))
818
+ (" catch" . (:block 2 ))
819
+ (" condp" . (:block 2 ))
820
+ (" bound-fn" . (:inner 0 ))
821
+ (" def" . (:inner 0 ))
822
+ (" defmacro" . (:inner 0 ))
823
+ (" defmethod" . (:inner 0 ))
824
+ (" defmulti" . (:inner 0 ))
825
+ (" defn" . (:inner 0 ))
826
+ (" defn-" . (:inner 0 ))
827
+ (" defonce" . (:inner 0 ))
828
+ (" deftest" . (:inner 0 ))
829
+ (" fdef" . (:inner 0 ))
830
+ (" fn" . (:inner 0 ))
831
+ (" reify" . (:inner 0 ))
832
+ (" use-fixtures" . (:inner 0 )))
833
+ " Default semantic indentation rules.
834
+
835
+ The format reflects cljfmt indentation rules. All the default rules are
836
+ aligned with
837
+ https://github.com/weavejester/cljfmt/blob/0.13.0/cljfmt/resources/cljfmt/indents/clojure.clj" )
838
+
839
+ (defun clojure-ts--match-block-0-body (bol first-child )
840
+ " Match if expression body is not at the same line as FIRST-CHILD.
841
+
842
+ If there is no body, check that BOL is not at the same line."
843
+ (let* ((body-pos (if-let* ((body (treesit-node-next-sibling first-child)))
844
+ (treesit-node-start body)
845
+ bol)))
846
+ (< (line-number-at-pos (treesit-node-start first-child))
847
+ (line-number-at-pos body-pos))))
848
+
849
+ (defun clojure-ts--node-pos-match-block (node parent bol block )
850
+ " Return TRUE if NODE index in the PARENT matches requested BLOCK.
851
+
852
+ NODE might be nil (when we insert an empty line for example), in this
853
+ case we look for next available child node in the PARENT after BOL
854
+ position.
855
+
856
+ The first node in the expression is usually an opening paren, the last
857
+ node is usually a closing paren (unless some automatic parens mode is
858
+ not enabled). If requested BLOCK is 1, the NODE index should be at
859
+ least 3 (first node is opening paren, second node is matched symbol,
860
+ third node is first argument, and the rest is body which should be
861
+ indented.)"
862
+ (if node
863
+ (> (treesit-node-index node) (1+ block))
864
+ (when-let* ((node-after-bol (treesit-node-first-child-for-pos parent bol)))
865
+ (> (treesit-node-index node-after-bol) (1+ block)))))
866
+
867
+ (defun clojure-ts--match-form-body (node parent bol )
868
+ (and (clojure-ts--list-node-p parent)
869
+ (let ((first-child (clojure-ts--node-child-skip-metadata parent 0 )))
870
+ (when-let* ((rule (alist-get (clojure-ts--named-node-text first-child)
871
+ (seq-union clojure-ts-semantic-indent-rules
872
+ clojure-ts--semantic-indent-rules-defaults
873
+ (lambda (e1 e2 ) (equal (car e1) (car e2))))
874
+ nil
875
+ nil
876
+ #'equal )))
877
+ (and (not (clojure-ts--match-with-metadata node))
878
+ (let ((rule-type (car rule))
879
+ (rule-value (cadr rule)))
880
+ (if (equal rule-type :block )
881
+ (if (zerop rule-value)
882
+ ; ; Special treatment for block 0 rule.
883
+ (clojure-ts--match-block-0-body bol first-child)
884
+ (clojure-ts--node-pos-match-block node parent bol rule-value))
885
+ ; ; Return true for any inner rule.
886
+ t )))))))
777
887
778
888
(defun clojure-ts--match-function-call-arg (node parent _bol )
779
889
" Match NODE if PARENT is a list expressing a function or macro call."
@@ -787,24 +897,6 @@ https://github.com/weavejester/cljfmt/blob/fb26b22f569724b05c93eb2502592dfc2de89
787
897
(clojure-ts--keyword-node-p first-child)
788
898
(clojure-ts--var-node-p first-child)))))
789
899
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
900
(defun clojure-ts--match-method-body (_node parent _bol )
809
901
" Matches a `NODE' in the body of a `PARENT' method implementation.
810
902
A method implementation referes to concrete implementations being defined in
@@ -885,7 +977,7 @@ forms like deftype, defrecord, reify, proxy, etc."
885
977
(clojure-ts--match-docstring parent 0 )
886
978
; ; https://guide.clojure.style/#body-indentation
887
979
(clojure-ts--match-method-body parent 2 )
888
- (clojure-ts--match-expression-in -body parent 2 )
980
+ (clojure-ts--match-form -body parent 2 )
889
981
; ; https://guide.clojure.style/#threading-macros-alignment
890
982
(clojure-ts--match-threading-macro-arg prev-sibling 0 )
891
983
; ; https://guide.clojure.style/#vertically-align-fn-args
0 commit comments