GNU bug report logs - #77255
Treesit font-lock override for embed ranges

Previous Next

Package: emacs;

Reported by: Juri Linkov <juri <at> linkov.net>

Date: Tue, 25 Mar 2025 18:30:02 UTC

Severity: normal

Fixed in version 31.0.50

Done: Juri Linkov <juri <at> linkov.net>

Bug is archived. No further changes may be made.

Full log


View this message in rfc822 format

From: Vincenzo Pupillo <v.pupillo <at> gmail.com>
To: 77255 <at> debbugs.gnu.org, Juri Linkov <juri <at> linkov.net>
Cc: Yuan Fu <casouri <at> gmail.com>
Subject: bug#77255: Treesit font-lock override for embed ranges
Date: Wed, 26 Mar 2025 17:07:58 +0100
Caio Juri,

In data mercoledì 26 marzo 2025 08:27:14 Ora standard dell’Europa centrale, 
Juri Linkov ha scritto:
> > It looks like we need a new keyword like ':override t' for
> > 'treesit-range-rules' that would override host font-lock rules.
> 
> Or maybe not.  I managed to do this without any changes in core.
> Also not sure if such functions as treesit-merge-font-lock-feature-list
> and treesit-replace-font-lock-feature-settings could be used here.
> 
treesit-replace-font-lock-feature-settings works reliably only if the 
replacement is done for rules of the same language. So something like:

#+begin_src emacs-lisp
(setq-local liquid-ts-mode--font-lock-feature-list (treesit-replace-font-lock-
feature-settings
		 (treesit-font-lock-rules
		  :language 'html
		  :override t
		  :feature 'string
		  `((attribute
		     (attribute_name) @_name
		     (:pred mhtml-ts-mode--not-match @_name)
		     (quoted_attribute_value) @font-lock-string-face)))

		 html-ts-mode--treesit-font-lock-settings)
#+end_src

Then:
 
(defvar mhtml-ts-mode--treesit-font-lock-feature-list
  (treesit-merge-font-lock-feature-list
   liquid-ts-mode--treesit-font-lock-feature-list
   (treesit-merge-font-lock-feature-list
    js--treesit-font-lock-feature-list
    css--treesit-font-lock-feature-list))
  "Settings for `treesit-font-lock-feature-list'.")

However, we could modify treesit-replace-font-lock-feature-settings to check 
the language in addition to the feature.

Vincenzo


> The solution below works simply by replacing the html rule with
> another rule that matches only HTML attributes that don't contain
> js code:
> 
> #+begin_src emacs-lisp
>     (setq-local treesit-range-settings
>                 (append treesit-range-settings
>                         (treesit-range-rules
> 
>                          :embed 'javascript
>                          :host 'html
>                          :local t
> 
>                          `((attribute
>                             (attribute_name) @_name
>                             (:match ,(rx (or "x-data" "x-bind" "x-text"))
> @_name) (quoted_attribute_value
>                              (attribute_value) @cap))))))
> 
>     (setq-local treesit-font-lock-settings
>                 (mapcar (lambda (s)
>                           (if (and (eq (treesit-query-language
>                                         (treesit-font-lock-setting-query s))
> 'html)
>                                    (eq (treesit-font-lock-setting-feature s)
> 'string))
>                               (car (treesit-font-lock-rules
> 
>                                     :language 'html
>                                     :override t
>                                     :feature 'string
> 
>                                     `((attribute
>                                        (attribute_name) @_name
>                                        ;; (:match (not ,(rx (or "x-data"
> "x-bind" "x-text"))) @_name) ;; (:pred (lambda (node)
>                                        ;;           (not (string-match-p (rx
> (or "x-data" "x-bind" "x-text")) ;;                 (treesit-node-text node
> t)))) ;;        @_name)
>                                        (:pred mhtml-ts-mode--not-match
> @_name) (quoted_attribute_value) @font-lock-string-face)))) s))
>                         treesit-font-lock-settings))
> #+end_src
> 
> The commented out code shows attempts to use a negated :match
> that is not supported.  Also it seems a lambda for :pred is
> also not supported.  So needed to add a separate function:
> 
> #+begin_src emacs-lisp
> (defun mhtml-ts-mode--not-match (node)
>   (not (string-match-p (rx (or "x-data" "x-bind" "x-text"))
>                        (treesit-node-text node t))))
> #+end_src
> 
> Then everything works: all HTML attributes are highlighted
> except those that should highlight js code in them.








This bug report was last modified 92 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.