Skip to content

Commit ab74c04

Browse files
committed
Speedup align-forms by introducing indentation rules caching
1 parent 31f12ea commit ab74c04

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 (seq-filter (lambda (child)
1007-
(string= (treesit-node-field-name child) "value"))
1008-
(treesit-node-children node t))))
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
@@ -1435,17 +1439,34 @@ If NS is defined, then the fully qualified symbol is passed to
14351439
(seq-sort (lambda (spec1 _spec2)
14361440
(equal (car spec1) :block)))))))))
14371441

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

14501471
(defun clojure-ts--find-semantic-rule (node parent current-depth)
14511472
"Return a suitable indentation rule for NODE, considering the CURRENT-DEPTH.
@@ -1457,7 +1478,8 @@ increasing the CURRENT-DEPTH. If a rule is not found upon reaching the
14571478
root of the syntax tree, it returns nil. A rule is considered a match
14581479
only if the CURRENT-DEPTH matches the rule's required depth."
14591480
(let* ((idx (- (treesit-node-index node) 2)))
1460-
(if-let* ((rule-set (clojure-ts--find-semantic-rules-for-node parent)))
1481+
(if-let* ((rule-set (clojure-ts--find-semantic-rules-for-node parent))
1482+
((not (equal rule-set :not-found))))
14611483
(if (zerop current-depth)
14621484
(let ((rule (car rule-set)))
14631485
(if (equal (car rule) :block)
@@ -1912,9 +1934,11 @@ between BEG and END."
19121934
(end (clojure-ts--end-of-defun-pos)))
19131935
(list start end))))))
19141936
(setq end (copy-marker end))
1937+
(clrhash clojure-ts--dynamic-indent-for-symbol-cache)
19151938
(let* ((sexps-to-align (clojure-ts--get-nodes-to-align beg (marker-position end)))
19161939
;; We have to disable it here to avoid endless recursion.
1917-
(clojure-ts-align-forms-automatically nil))
1940+
(clojure-ts-align-forms-automatically nil)
1941+
(clojure-ts--dynamic-indent-for-symbol-cache-p t))
19181942
(save-excursion
19191943
(indent-region beg (marker-position end))
19201944
(dolist (sexp sexps-to-align)
@@ -2566,6 +2590,28 @@ before DELIM-OPEN."
25662590
(goto-char pos))
25672591
(user-error "Must be invoked inside a list")))
25682592

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