]> git.eshelyaron.com Git - emacs.git/commitdiff
Make tree-sitter font-lock support decoration levels
authorYuan Fu <casouri@gmail.com>
Sun, 9 Oct 2022 22:17:11 +0000 (15:17 -0700)
committerYuan Fu <casouri@gmail.com>
Mon, 10 Oct 2022 00:20:28 +0000 (17:20 -0700)
* admin/notes/tree-sitter/html-manual/Parser_002dbased-Font-Lock.html:
Update.
* admin/notes/tree-sitter/html-manual/Parsing-Program-Source.html:
Update.
* doc/lispref/modes.texi: Mention the new :level option.
* lisp/treesit.el (treesit-font-lock-settings): Update docstring.
(treesit-font-lock-rules): Support :level.  Relayout the let form.
(treesit-font-lock-fontify-region): Support :level.

admin/notes/tree-sitter/html-manual/Parser_002dbased-Font-Lock.html
admin/notes/tree-sitter/html-manual/Parsing-Program-Source.html
doc/lispref/modes.texi
lisp/treesit.el

index 246ebf05193a261fa0cbe1a77075cb788ac05f67..c91152edc0e768002360dafb7554fba4d112bdf2 100644 (file)
@@ -117,8 +117,17 @@ every query must specify the language.  Other keywords are optional:
 <tr><td width="15%"></td><td width="15%"><code>keep</code></td><td width="60%">Fill-in regions without an existing face</td></tr>
 <tr><td width="15%"><code>:toggle</code></td><td width="15%"><var>symbol</var></td><td width="60%">If non-nil, its value should be a variable name.  The variable&rsquo;s value
 (nil/non-nil) disables/enables the query during fontification.</td></tr>
+<tr><td width="15%"></td><td width="15%">nil</td><td width="60%">Always enable this query.</td></tr>
+<tr><td width="15%"><code>:level</code></td><td width="15%"><var>integer</var></td><td width="60%">If non-nil, its value should be the decoration level for this query.
+Decoration level is controlled by <code>font-lock-maximum-decoration</code>.</td></tr>
+<tr><td width="15%"></td><td width="15%">nil</td><td width="60%">Always enable this query.</td></tr>
 </table>
 
+<p>Note that a query is applied only when both <code>:toggle</code> and
+<code>:level</code> permit it.  <code>:level</code> is used for global,
+coarse-grained control, whereas <code>:toggle</code> is for local,
+fine-grained control.
+</p>
 <p>Capture names in <var>query</var> should be face names like
 <code>font-lock-keyword-face</code>.  The captured node will be fontified
 with that face.  Capture names can also be function names, in which
index 7b6e51468a6a92ad1c8be5a5d406e42a5014a483..81b42f7f52602cbc89b0fd876a84300f55c90628 100644 (file)
@@ -94,6 +94,10 @@ for this Emacs instance.
 see <a href="Parser_002dbased-Font-Lock.html">Parser-based Font Lock</a>, <a href="Parser_002dbased-Indentation.html">Parser-based Indentation</a>, and
 <a href="List-Motion.html">Moving over Balanced Expressions</a>.
 </p>
+<p>About naming convention: use &ldquo;tree-sitter&rdquo; when referring to it as a
+noun, like <code>python-use-tree-sitter</code>, but use &ldquo;treesit&rdquo; for
+prefixes, like <code>python-treesit-indent-function</code>.
+</p>
 <p>To access the syntax tree of the text in a buffer, we need to first
 load a language definition and create a parser with it.  Next, we can
 query the parser for specific nodes in the syntax tree.  Then, we can
index dcc0b2958d57b70f7e3addb02253621a6af18b81..b1287c6ad050860df43de62a240ad7977fbe3174 100644 (file)
@@ -3935,8 +3935,18 @@ every query must specify the language.  Other keywords are optional:
 @item @code{:toggle} @tab @var{symbol} @tab
 If non-nil, its value should be a variable name.  The variable's value
 (nil/non-nil) disables/enables the query during fontification.
+@item @tab nil @tab Always enable this query.
+@item @code{:level} @tab @var{integer} @tab
+If non-nil, its value should be the decoration level for this query.
+Decoration level is controlled by @code{font-lock-maximum-decoration}.
+@item @tab nil @tab Always enable this query.
 @end multitable
 
+Note that a query is applied only when both @code{:toggle} and
+@code{:level} permit it.  @code{:level} is used for global,
+coarse-grained control, whereas @code{:toggle} is for local,
+fine-grained control.
+
 Capture names in @var{query} should be face names like
 @code{font-lock-keyword-face}.  The captured node will be fontified
 with that face.  Capture names can also be function names, in which
index db96a899750267f06383d22733f2cf548c144515..7132f1d5ee6cab9a3ff34c9bc9438ce7c2f6f3a6 100644 (file)
@@ -289,7 +289,7 @@ should always use `treesit-font-lock-rules' to set this variable.
 
 Each SETTING is of form
 
-    (LANGUAGE QUERY OVERRIDE TOGGLE)
+    (LANGUAGE QUERY OVERRIDE TOGGLE LEVEL)
 
 Each SETTING controls one parser (often of different language).
 LANGUAGE is the language symbol.  See Info node `(elisp)Language
@@ -308,7 +308,11 @@ t, nil, append, prepend, keep.  See more in
 
 TOGGLE should be a variable (symbol) or nil.  The variable's
 value (nil/non-nil) controls whether to activate the query during
-fontification.  If TOGGLE is nil, the query is always activated.")
+fontification.  If TOGGLE is nil, the query is always activated.
+
+LEVEL is the decoration level of this query or nil.  Decoration
+level is controlled by `font-lock-maximum-decoration'.  If LEVEL
+is nil, the query is always activated.")
 
 (defun treesit-font-lock-rules (&rest args)
   "Return a value suitable for `treesit-font-lock-settings'.
@@ -344,6 +348,15 @@ include:
                       The value of that variable (non-nil/nil)
                       activates/deactivates the query during
                       fontification.
+             nil      Always activate this query.
+  :level     <integer>If non-nil, the value is the decoration
+                      level of this query.
+                      (See `font-lock-maximum-decoration'.)
+             nil      Always activate this query.
+
+Note that a query is applied only when both :toggle and :level
+permit it.  :level is used for global, coarse-grained control,
+whereas :toggle is for local, fine-grained control.
 
 Capture names in QUERY should be face names like
 `font-lock-keyword-face'.  The captured node will be fontified
@@ -356,18 +369,16 @@ a capture name is not a face name nor a function name, it is
 ignored.
 
 \(fn :KEYWORD VALUE QUERY...)"
-  (let (;; Tracks the current language that following queries will
-        ;; apply to.
-        (current-language nil)
-        ;; Tracks :override flag.
-        (current-override nil)
-        ;; Track :toggle flag.
-        (current-toggle t)
+  (let (;; Tracks the current :language/:override/:toggle/:level value
+        ;; that following queries will apply to.
+        current-language current-override
+        current-toggle current-level
         ;; The list this function returns.
         (result nil))
     (while args
       (let ((token (pop args)))
         (pcase token
+          ;; (1) Process keywords.
           (:language
            (let ((lang (pop args)))
              (when (or (not (symbolp lang)) (null lang))
@@ -393,6 +404,14 @@ ignored.
                        `("Value of :toggle should be a variable name"
                          ,var)))
              (setq current-toggle var)))
+          (:level
+           (let ((level (pop args)))
+             (when (not (and (integerp level) (> level 0)))
+               (signal 'treesit-font-lock-error
+                       `("Value of :level should be a positive integer"
+                         ,level)))
+             (setq current-level level)))
+          ;; (2) Process query.
           ((pred treesit-query-p)
            (when (null current-language)
              (signal 'treesit-font-lock-error
@@ -402,12 +421,14 @@ ignored.
              (push `(,current-language
                      ,(treesit-query-compile current-language token)
                      ,current-override
-                     ,current-toggle)
+                     ,current-toggle
+                     ,current-level)
                    result))
            ;; Clears any configurations set for this query.
            (setq current-language nil
                  current-override nil
-                 current-toggle nil))
+                 current-toggle nil
+                 current-level nil))
           (_ (signal 'treesit-font-lock-error
                      `("Unexpected value" token))))))
     (nreverse result)))
@@ -423,10 +444,20 @@ If LOUDLY is non-nil, message some debugging information."
            (match-pattern (nth 1 setting))
            (override (nth 2 setting))
            (toggle (nth 3 setting))
+           (level (nth 4 setting))
            (parser (treesit-parser-create language)))
       (when-let ((node (treesit-node-on start end parser))
-                 (activate (or (null toggle)
-                               (symbol-value toggle))))
+                 ;; Only activate this query if both :toggle and
+                 ;; :level permit it.
+                 (activate
+                  (and (or (null toggle)
+                           (symbol-value toggle))
+                       (or (null level)
+                           (pcase (font-lock-value-in-major-mode
+                                   font-lock-maximum-decoration)
+                             ('t t)
+                             ('nil (eq level 1))
+                             (lvl (<= level lvl)))))))
         (ignore activate)
         (let ((captures (treesit-query-capture
                          node match-pattern