Skip to content

Commit 64e1af2

Browse files
committed
Speedup align-forms by introducing indentation rules caching
1 parent 08b1c3b commit 64e1af2

File tree

2 files changed

+58
-12
lines changed

2 files changed

+58
-12
lines changed

clojure-ts-mode.el

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,9 +1003,9 @@ If there is no namespace, returns nil."
10031003
(defun clojure-ts--node-child-skip-metadata (node n)
10041004
"Return the Nth child of NODE like `treesit-node-child', sans metadata.
10051005
Skip the optional metadata node at pos 0 if present."
1006-
(let ((value-nodes (thread-last (treesit-node-children node t)
1007-
(seq-filter (lambda (child)
1008-
(string= (treesit-node-field-name child) "value"))))))
1006+
(let ((value-nodes (treesit-filter-child node
1007+
#'clojure-ts--value-type-node-p
1008+
t)))
10091009
(seq-elt value-nodes n)))
10101010

10111011
(defun clojure-ts--first-value-child (node)
@@ -1147,6 +1147,10 @@ Includes a dispatch value when applicable (defmethods)."
11471147
"Return non-nil if NODE represents a protocol or interface definition."
11481148
(clojure-ts--definition-node-match-p clojure-ts--interface-type-regexp node))
11491149

1150+
(defun clojure-ts--value-type-node-p (node)
1151+
"Return non-nil if field name of the NODE is value."
1152+
(string= (treesit-node-field-name node) "value"))
1153+
11501154
(defvar clojure-ts--imenu-settings
11511155
`(("Namespace" "list_lit" clojure-ts--ns-node-p)
11521156
("Function" "list_lit" clojure-ts--function-node-p
@@ -1436,17 +1440,34 @@ If NS is defined, then the fully qualified symbol is passed to
14361440
(seq-sort (lambda (spec1 _spec2)
14371441
(equal (car spec1) :block)))))))))
14381442

1439-
(defun clojure-ts--find-semantic-rules-for-node (node)
1440-
"Return a list of semantic rules for NODE."
1441-
(let* ((first-child (clojure-ts--node-child-skip-metadata node 0))
1442-
(symbol-name (clojure-ts--named-node-text first-child))
1443-
(symbol-namespace (clojure-ts--node-namespace-text first-child)))
1443+
(defvar clojure-ts--dynamic-indent-for-symbol-cache
1444+
(make-hash-table :test 'equal))
1445+
1446+
(defvar clojure-ts--dynamic-indent-for-symbol-cache-p nil
1447+
"If set to nil, do not use cache for dynamic indentation rules.")
1448+
1449+
(defun clojure-ts--find-semantic-rules-for-symbol (node)
1450+
"Return a list of semantic rules for symbol NODE.
1451+
1452+
If rules are not found return :not-found symbol."
1453+
(let ((symbol-name (clojure-ts--named-node-text node))
1454+
(symbol-namespace (clojure-ts--node-namespace-text node)))
14441455
(or (clojure-ts--dynamic-indent-for-symbol symbol-name symbol-namespace)
14451456
(alist-get symbol-name
14461457
clojure-ts--semantic-indent-rules-cache
14471458
nil
14481459
nil
1449-
#'equal))))
1460+
#'equal)
1461+
:not-found)))
1462+
1463+
(defun clojure-ts--find-semantic-rules-for-node (node)
1464+
"Return a list of semantic rules for NODE."
1465+
(let* ((first-child (clojure-ts--first-value-child node))
1466+
(symbol-full-name (treesit-node-text first-child)))
1467+
(if clojure-ts--dynamic-indent-for-symbol-cache-p
1468+
(with-memoization (gethash symbol-full-name clojure-ts--dynamic-indent-for-symbol-cache)
1469+
(clojure-ts--find-semantic-rules-for-symbol first-child))
1470+
(clojure-ts--find-semantic-rules-for-symbol first-child))))
14501471

14511472
(defun clojure-ts--find-semantic-rule (node parent current-depth)
14521473
"Return a suitable indentation rule for NODE, considering the CURRENT-DEPTH.
@@ -1458,7 +1479,8 @@ increasing the CURRENT-DEPTH. If a rule is not found upon reaching the
14581479
root of the syntax tree, it returns nil. A rule is considered a match
14591480
only if the CURRENT-DEPTH matches the rule's required depth."
14601481
(let* ((idx (- (treesit-node-index node) 2)))
1461-
(if-let* ((rule-set (clojure-ts--find-semantic-rules-for-node parent)))
1482+
(if-let* ((rule-set (clojure-ts--find-semantic-rules-for-node parent))
1483+
((not (equal rule-set :not-found))))
14621484
(if (zerop current-depth)
14631485
(let ((rule (car rule-set)))
14641486
(if (equal (car rule) :block)
@@ -1913,9 +1935,11 @@ between BEG and END."
19131935
(end (clojure-ts--end-of-defun-pos)))
19141936
(list start end))))))
19151937
(setq end (copy-marker end))
1938+
(clrhash clojure-ts--dynamic-indent-for-symbol-cache)
19161939
(let* ((sexps-to-align (clojure-ts--get-nodes-to-align beg (marker-position end)))
19171940
;; We have to disable it here to avoid endless recursion.
1918-
(clojure-ts-align-forms-automatically nil))
1941+
(clojure-ts-align-forms-automatically nil)
1942+
(clojure-ts--dynamic-indent-for-symbol-cache-p t))
19191943
(save-excursion
19201944
(indent-region beg (marker-position end))
19211945
(dolist (sexp sexps-to-align)
@@ -2567,6 +2591,28 @@ before DELIM-OPEN."
25672591
(goto-char pos))
25682592
(user-error "Must be invoked inside a list")))
25692593

2594+
(defun clojure-ts--toggle-ignore-next-sexp (&optional n)
2595+
"Insert or delete N `#_' ignore macros at the current point.
2596+
2597+
Point must be directly before a sexp or the #_ characters. When acting
2598+
on a top level form, insert #_ on a new line preceding the form to
2599+
prevent indentation changes."
2600+
2601+
(dotimes (_ (or n 1)) (insert-before-markers "#_")))
2602+
2603+
(defun clojure-ts-toggle-ignore (&optional n)
2604+
"Toggle the #_ ignore reader form for the sexp at point.
2605+
2606+
With the numeric argument, toggle N number of #_ forms at the same point.
2607+
2608+
e.g. with N = 2:
2609+
|a b c => #_#_a b c"
2610+
(interactive "p")
2611+
(let ((sexp (treesit-thing-at-point 'sexp 'nested)))
2612+
(goto-char (treesit-node-start sexp))
2613+
(clojure-ts--toggle-ignore-next-sexp n)
2614+
))
2615+
25702616
(defvar clojure-ts-refactor-map
25712617
(let ((map (make-sparse-keymap)))
25722618
(keymap-set map "C-t" #'clojure-ts-thread)

test/samples/refactoring.clj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@
141141
false)
142142

143143
(when-not true
144-
(println "Hello world"))
144+
(println #_#_"Hello world" "again"))
145145

146146
(extend-protocol prepare/SettableParameter
147147
clojure.lang.IPersistentMap

0 commit comments

Comments
 (0)