emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 1e44c63fcad 03/11: Allow treesit-simple-indent's rule to be a sin


From: Yuan Fu
Subject: master 1e44c63fcad 03/11: Allow treesit-simple-indent's rule to be a single function
Date: Sun, 1 Dec 2024 21:10:22 -0500 (EST)

branch: master
commit 1e44c63fcadeb89a9a9c9208f221970e6fcc774c
Author: Yuan Fu <casouri@gmail.com>
Commit: Yuan Fu <casouri@gmail.com>

    Allow treesit-simple-indent's rule to be a single function
    
    * 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.
---
 doc/lispref/modes.texi | 21 ++++++++++---
 lisp/treesit.el        | 85 +++++++++++++++++++++++++++++---------------------
 2 files changed, 65 insertions(+), 41 deletions(-)

diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi
index 87c6347eaa7..f32d5a89bca 100644
--- a/doc/lispref/modes.texi
+++ b/doc/lispref/modes.texi
@@ -5243,11 +5243,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
@@ -5277,6 +5279,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
diff --git a/lisp/treesit.el b/lisp/treesit.el
index 5d57b9e8e3e..64b08857f4a 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -1559,13 +1559,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
@@ -1582,7 +1582,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
@@ -2121,31 +2126,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.
@@ -2201,12 +2212,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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]