]> git.eshelyaron.com Git - emacs.git/commitdiff
Allow treesit-simple-indent's rule to be a single function
authorYuan Fu <casouri@gmail.com>
Fri, 29 Nov 2024 22:10:45 +0000 (14:10 -0800)
committerEshel Yaron <me@eshelyaron.com>
Wed, 4 Dec 2024 17:02:49 +0000 (18:02 +0100)
* lisp/treesit.el (treesit-simple-indent-rules): Allow the rule
to be a single function.  Also replace cl-loop with dolist plus
catch-throw.
(treesit--indent-rules-optimize): Handle the case when a rule is
a function.
* doc/lispref/modes.texi (Parser-based Indentation): Update
manuel.

(cherry picked from commit 1e44c63fcadeb89a9a9c9208f221970e6fcc774c)

doc/lispref/modes.texi
lisp/treesit.el

index d7909e783845e8431fe72575d84e520f3179a64a..5ef3de665d94428839ab3b8e8c348c7ece8be80a 100644 (file)
@@ -5207,11 +5207,13 @@ more complex indentation engines.
 @cindex indentation rules, for parser-based indentation
 
 @defvar treesit-simple-indent-rules
-This local variable stores indentation rules for every language.  It
-is an alist with elements of the form @w{@code{(@var{language}
-. @var{rules})}}, where @var{language} is a language symbol, and
-@var{rules} is a list with elements of the form
-@w{@code{(@var{matcher} @var{anchor} @var{offset})}}.
+This local variable stores indentation rules for every language.  It is
+an list of elements of the form @w{@code{(@var{language}
+@var{rule}...)}}, where @var{language} is a language symbol, and each
+@var{rule} is either a list with elements of the form
+@w{@code{(@var{matcher} @var{anchor} @var{offset})}}, or a function. Let
+'s focus on the list variant first, we'll come back to the function
+variant later.
 
 First, Emacs passes the smallest tree-sitter node at the beginning of
 the current line to @var{matcher}; if it returns non-@code{nil}, this
@@ -5241,6 +5243,15 @@ and @var{anchor} should return a buffer position.
 or a function that returns an integer.  If it is a function, it is
 passed @var{node}, @var{parent}, and @var{bol}, like matchers and
 anchors.
+
+Remember that @var{rule} can also be a function.  This is for the
+complex cases where a rule needs to consider the matching rule and
+anchor together.  If @var{rule} is a function, it's passed the same
+argument as @var{matcher}: @var{node}, @var{parent}, and @var{bol}.  If
+it matches, @var{rule} should return a cons @w{@code{(@var{anchor-pos}
+. @var{offset})}}, where @var{anchor-pos} is a buffer position, and
+@var{offset} is the indent offset.  If @var{rule} does't match, it
+should return @code{nil}.
 @end defvar
 
 @defvar treesit-simple-indent-presets
index d3413d1590fdbcec36ff0b7a27e968194238bc3f..be6df5a576b8bf29bd3af230c05edba7374762c0 100644 (file)
@@ -1555,13 +1555,13 @@ START and END mark the current to-be-propertized region."
 
 (defvar-local treesit-simple-indent-rules nil
   "A list of indent rule settings.
-Each indent rule setting should be (LANGUAGE . RULES),
-where LANGUAGE is a language symbol, and RULES is a list of
+Each indent rule setting should be (LANGUAGE RULE...), where LANGUAGE is
+a language symbol, and each RULE is of the form
 
-    (MATCHER ANCHOR OFFSET).
+    (MATCHER ANCHOR OFFSET)
 
-MATCHER determines whether this rule applies, ANCHOR and OFFSET
-together determines which column to indent to.
+MATCHER determines whether this rule applies, ANCHOR and
+OFFSET together determines which column to indent to.
 
 A MATCHER is a function that takes three arguments (NODE PARENT
 BOL).  BOL is the point where we are indenting: the beginning of
@@ -1578,7 +1578,12 @@ ANCHOR and adds OFFSET to it, and indents to that column.  OFFSET
 can be an integer or a variable whose value is an integer.
 
 For MATCHER and ANCHOR, Emacs provides some convenient presets.
-See `treesit-simple-indent-presets'.")
+See `treesit-simple-indent-presets'.
+
+For complex cases, a RULE can also be a single function.  This function
+should take the same argument as MATCHER or ANCHOR.  If it matches,
+return a cons (ANCHOR-POS . OFFSET), where ANCHOR-POS is a position and
+OFFSET is the indent offset; if it doesn't match, return nil.")
 
 (defvar treesit-simple-indent-presets
   (list (cons 'match
@@ -2113,31 +2118,37 @@ OFFSET."
     (let* ((language (treesit-node-language parent))
            (rules (alist-get language
                              treesit-simple-indent-rules)))
-      (cl-loop for rule in rules
-               for pred = (nth 0 rule)
-               for anchor = (nth 1 rule)
-               for offset = (nth 2 rule)
-               if (treesit--simple-indent-eval
-                   (list pred node parent bol))
-               do (when treesit--indent-verbose
+      (catch 'match
+        (dolist (rule rules)
+          (if (functionp rule)
+              (let ((result (funcall rule node parent bol)))
+                (when result
+                  (when treesit--indent-verbose
                     (message "Matched rule: %S" rule))
-               and
-               return
-               (let ((anchor-pos
-                      (treesit--simple-indent-eval
-                       (list anchor node parent bol)))
-                     (offset-val
-                      (cond ((numberp offset) offset)
-                            ((and (symbolp offset)
-                                  (boundp offset))
-                             (symbol-value offset))
-                            (t (treesit--simple-indent-eval
-                                (list offset node parent bol))))))
-                 (cons anchor-pos offset-val))
-               finally return
-               (progn (when treesit--indent-verbose
-                        (message "No matched rule"))
-                      (cons nil nil))))))
+                  (throw 'match result)))
+            (let ((pred (nth 0 rule))
+                  (anchor (nth 1 rule))
+                  (offset (nth 2 rule)))
+              ;; Found a match.
+              (when (treesit--simple-indent-eval
+                     (list pred node parent bol))
+                (when treesit--indent-verbose
+                  (message "Matched rule: %S" rule))
+                (let ((anchor-pos
+                       (treesit--simple-indent-eval
+                        (list anchor node parent bol)))
+                      (offset-val
+                       (cond ((numberp offset) offset)
+                             ((and (symbolp offset)
+                                   (boundp offset))
+                              (symbol-value offset))
+                             (t (treesit--simple-indent-eval
+                                 (list offset node parent bol))))))
+                  (throw 'match (cons anchor-pos offset-val)))))))
+        ;; Didn't find any match.
+        (when treesit--indent-verbose
+          (message "No matched rule"))
+        (cons nil nil)))))
 
 (defun treesit--read-major-mode ()
   "Read a major mode using completion.
@@ -2193,12 +2204,14 @@ RULES."
                     (_ func)))
                 ;; Optimize a rule (MATCHER ANCHOR OFFSET).
                 (optimize-rule (rule)
-                  (let ((matcher (nth 0 rule))
-                        (anchor (nth 1 rule))
-                        (offset (nth 2 rule)))
-                    (list (optimize-func matcher)
-                          (optimize-func anchor)
-                          offset))))
+                  (if (functionp rule)
+                      rule
+                    (let ((matcher (nth 0 rule))
+                          (anchor (nth 1 rule))
+                          (offset (nth 2 rule)))
+                      (list (optimize-func matcher)
+                            (optimize-func anchor)
+                            offset)))))
              (cons lang (mapcar #'optimize-rule indent-rules)))))
 
 ;;; Search