@@ -497,6 +497,24 @@ Includes a dispatch value when applicable (defmethods)."
497
497
By default `treesit-defun-name-function' is used to extract definition names.
498
498
See `clojure-ts--standard-definition-node-name' for the implementation used." )
499
499
500
+ (defcustom clojure-ts-indent-style 'semantic
501
+ " Automatic indentation style to use when mode clojure-ts-mode is run
502
+
503
+ The possible values for this variable are
504
+ `semantic' - Tries to follow the same rules as the clojure style guide.
505
+ See: https://guide.clojure.style/
506
+ `fixed' - A simpler set of indentation rules that can be summarized as
507
+ 1. Multi-line lists that start with a symbol are always indented with
508
+ two spaces.
509
+ 2. Other multi-line lists, vectors, maps and sets are aligned with the
510
+ first element (1 or 2 spaces).
511
+ See: https://tonsky.me/blog/clojurefmt/"
512
+ :safe #'symbolp
513
+ :type
514
+ '(choice (const :tag " Semantic indent rules, matching clojure style guide." semantic)
515
+ (const :tag " Simple fixed indent rules." fixed ))
516
+ :package-version '(clojure-ts-mode . " 0.2.0" ))
517
+
500
518
(defvar clojure-ts--fixed-indent-rules
501
519
; ; This is in contrast to semantic
502
520
; ; fixed-indent-rules come from https://tonsky.me/blog/clojurefmt/
@@ -536,6 +554,99 @@ See `clojure-ts--standard-definition-node-name' for the implementation used.")
536
554
((sexp ,(regexp-opt clojure-ts--sexp-nodes))
537
555
(text ,(regexp-opt '(" comment" )))))))
538
556
557
+ (defvar clojure-ts--symbols-with-body-expressions-regexp
558
+ (eval-and-compile
559
+ (rx (or
560
+ ; ; Match def* symbols,
561
+ ; ; we also explicitly do not match symbols beginning with
562
+ ; ; "default" "deflate" and "defer", like cljfmt
563
+ (and line-start " def" )
564
+ ; ; Match with-* symbols
565
+ (and line-start " with-" )
566
+ ; ; Exact matches
567
+ (and line-start
568
+ (or " alt!" " alt!!" " are" " as->"
569
+ " binding" " bound-fn"
570
+ " case" " catch" " comment" " cond" " condp" " cond->" " cond->>"
571
+ " delay" " do" " doseq" " dotimes" " doto"
572
+ " extend" " extend-protocol" " extend-type"
573
+ " fdef" " finally" " fn" " for" " future"
574
+ " go" " go-loop"
575
+ " if" " if-let" " if-not" " if-some"
576
+ " let" " letfn" " locking" " loop"
577
+ " match" " ns" " proxy" " reify" " struct-map"
578
+ " testing" " thread" " try"
579
+ " use-fixtures"
580
+ " when" " when-first" " when-let" " when-not" " when-some" " while" )
581
+ line-end))))
582
+ " A regex to match symbols that are functions/macros with a body argument.
583
+ Taken from cljfmt:
584
+ https://github.com/weavejester/cljfmt/blob/fb26b22f569724b05c93eb2502592dfc2de898c3/cljfmt/resources/cljfmt/indents/clojure.clj" )
585
+
586
+ (defun clojure-ts--symbols-with-body-expressions-p (node )
587
+ " Return non-nil if NODE is a function/macro symbol with a body argument."
588
+ (and
589
+ (not
590
+ (clojure-ts--symbol-matches-p
591
+ ; ; Symbols starting with this are false positives
592
+ (rx line-start (or " default" " deflate" " defer" ))
593
+ node))
594
+ (clojure-ts--symbol-matches-p
595
+ clojure-ts--symbols-with-body-expressions-regexp
596
+ node)))
597
+
598
+ (defvar clojure-ts--threading-macro
599
+ (eval-and-compile
600
+ (rx (and " ->" (? " >" ) line-end)))
601
+ " A regular expression matching a threading macro." )
602
+
603
+ (defun clojure-ts--threading-macro-p (node )
604
+ " Return non-nil if NODE is a threading macro symbol like ->>."
605
+ (clojure-ts--symbol-matches-p clojure-ts--threading-macro node))
606
+
607
+ (defvar clojure-ts--semantic-indent-rules
608
+ `((clojure
609
+ ((parent-is " source" ) parent-bol 0 )
610
+ ((lambda (node parent _ ) ; ; https://guide.clojure.style/#body-indentation
611
+ (and (clojure-ts--list-node-p parent)
612
+ (let ((first-child (treesit-node-child parent 0 t )))
613
+ (clojure-ts--symbols-with-body-expressions-p first-child))))
614
+ parent 2 )
615
+ ; ; ;; We want threading macros to indent 2 only if the ->> is on it's own line.
616
+ ; ; ;; If not, then align functoin args.
617
+ ; ; ((lambda (node parent _)
618
+ ; ; (and (clojure-ts--list-node-p parent)
619
+ ; ; (let ((first-child (treesit-node-child parent 0 t))
620
+ ; ; (second-child (treesit-node-child parent 1 t)))
621
+ ; ; (clojure-ts--debug "Second-child %S" (treesit-node))
622
+ ; ; (clojure-ts--threading-macro-p first-child))))
623
+ ; ; parent 2)
624
+ ((lambda (node parent _ ) ; ; https://guide.clojure.style/#vertically-align-fn-args
625
+ (and (clojure-ts--list-node-p parent)
626
+ ; ; Can the following two clauses be replaced by checking indexes?
627
+ ; ; Does the second child exist, and is it not equal to the current node?
628
+ (treesit-node-child parent 1 t )
629
+ (not (treesit-node-eq (treesit-node-child parent 1 t ) node))
630
+ (let ((first-child (treesit-node-child parent 0 t )))
631
+ (or (clojure-ts--symbol-node-p first-child)
632
+ (clojure-ts--keyword-node-p first-child)))))
633
+ (nth-sibling 2 nil ) 0 )
634
+ ; ; Literal Sequences
635
+ ((parent-is " list_lit" ) parent 1 ) ; ; https://guide.clojure.style/#one-space-indent
636
+ ((parent-is " vec_lit" ) parent 1 ) ; ; https://guide.clojure.style/#bindings-alignment
637
+ ((parent-is " map_lit" ) parent 1 ) ; ; https://guide.clojure.style/#map-keys-alignment
638
+ ((parent-is " set_lit" ) parent 2 ))))
639
+
640
+ (defun clojure-ts--configured-indent-rules ()
641
+ " Gets the configured choice of indent rules."
642
+ (cond
643
+ ((eq clojure-ts-indent-style 'semantic ) clojure-ts--semantic-indent-rules)
644
+ ((eq clojure-ts-indent-style 'fixed ) clojure-ts--fixed-indent-rules)
645
+ (t (error
646
+ (format
647
+ " Invalid value for clojure-ts-indent-style. Valid values are 'semantic or 'fixed. Found %S"
648
+ clojure-ts-indent-style)))))
649
+
539
650
(defvar clojure-ts-mode-map
540
651
(let ((map (make-sparse-keymap )))
541
652
; (set-keymap-parent map clojure-mode-map)
@@ -581,7 +692,7 @@ See `clojure-ts--standard-definition-node-name' for the implementation used.")
581
692
treesit-defun-prefer-top-level t
582
693
treesit-defun-tactic 'top-level
583
694
treesit-defun-type-regexp (rx (or " list_lit" " vec_lit" " map_lit" ))
584
- treesit-simple-indent-rules clojure-ts--fixed -indent-rules
695
+ treesit-simple-indent-rules ( clojure-ts--configured -indent-rules)
585
696
treesit-defun-name-function #'clojure-ts--standard-definition-node-name
586
697
treesit-simple-imenu-settings clojure-ts--imenu-settings
587
698
treesit-font-lock-feature-list
0 commit comments