]> git.eshelyaron.com Git - emacs.git/commitdiff
New treesit generic mode 'liquid-generic-ts-mode' (bug#77255)
authorJuri Linkov <juri@linkov.net>
Tue, 1 Apr 2025 17:17:17 +0000 (20:17 +0300)
committerEshel Yaron <me@eshelyaron.com>
Thu, 3 Apr 2025 16:50:14 +0000 (18:50 +0200)
* lisp/treesit.el (treesit-replace-font-lock-feature-settings):
Check the query language in addition to checking the feature.
(treesit-font-lock-fontify-region): Use treesit-font-lock-setting-*
accessors.

* lisp/treesit-x.el (treesit-generic-mode-setup): Append new
font-lock rules to an existing treesit-font-lock-settings
possibly inherited from the parent.
(treesit-generic-mode-setup): Use treesit-merge-font-lock-feature-list
to merge with an existing feature list inherited from the parent.
(liquid-generic-ts-mode): New treesit generic mode.
(alpinejs-generic-ts-setup): New treesit generic setup.

(cherry picked from commit 87da719b6c4a53a31c67f3a9646b68cb15a1ffe7)

lisp/treesit-x.el
lisp/treesit.el

index 881e11e4e7a7a122b6c45d394c8489044e007310..5989bb898503ec085e92d3c6cd878ed1961100cc 100644 (file)
@@ -147,11 +147,15 @@ of `define-treesit-generic-mode'.
 
     (when-let* ((query (treesit-generic-mode-font-lock-query lang)))
       (setq-local treesit-font-lock-settings
-                  (treesit-font-lock-rules
-                   :language lang
-                   :feature 'highlights
-                   query))
-      (setq-local treesit-font-lock-feature-list '((highlights))))))
+                  (append treesit-font-lock-settings
+                          (treesit-font-lock-rules
+                           :language lang
+                           :feature 'highlights
+                           query)))
+      (setq-local treesit-font-lock-feature-list
+                  (treesit-merge-font-lock-feature-list
+                   treesit-font-lock-feature-list
+                   '((highlights)))))))
 
 ;;; Generic font-lock handling
 
@@ -202,6 +206,112 @@ of `define-treesit-generic-mode'.
   (setq-local comment-start "# ")
   (setq-local comment-end ""))
 
+(define-treesit-generic-mode liquid-generic-ts-mode
+  "Tree-sitter generic mode for Liquid templates."
+  :lang 'liquid
+  :source "https://github.com/hankthetank27/tree-sitter-liquid"
+  :auto-mode "\\.liquid\\'"
+  :name "Liquid"
+  :parent mhtml-ts-mode
+
+  (setq-local treesit-range-settings
+              (append treesit-range-settings
+                      (treesit-range-rules
+                       :embed 'html
+                       :host 'liquid
+                       '(((template_content) @cap)))))
+
+  (setq-local treesit-thing-settings
+              (append treesit-thing-settings
+                      `((liquid (sexp (not ,(rx bos "program" eos)))
+                                (list ,(rx bos (or "range"
+                                                   "if_statement"
+                                                   "for_loop_statement"
+                                                   "case_statement"
+                                                   "unless_statement"
+                                                   "capture_statement"
+                                                   "form_statement"
+                                                   "tablerow_statement"
+                                                   "paginate_statement")
+                                           eos))))))
+
+  (setq-local treesit-aggregated-outline-predicate
+              (append treesit-aggregated-outline-predicate
+                      `((liquid . ,(rx bos (or "if_statement"
+                                               "for_loop_statement")
+                                       eos)))))
+
+  (when (treesit-ready-p 'yaml t)
+    (defvar yaml-ts-mode--font-lock-settings)
+    (require 'yaml-ts-mode)
+    (setq-local treesit-range-settings
+                (append treesit-range-settings
+                        (treesit-range-rules
+                         :embed 'yaml
+                         :host 'liquid
+                         :local t
+                         '(((front_matter) @cap)))))
+    (setq-local treesit-font-lock-settings
+                (append treesit-font-lock-settings
+                        yaml-ts-mode--font-lock-settings))))
+
+(defvar alpinejs-generic-ts-attr-regexp
+  (rx bos (or "x-" ":" "@"))
+  "Regexp for HTML attributes handled by Alpine.js")
+
+(defun alpinejs-generic-ts-attr-not-match (node)
+  (not (string-match-p alpinejs-generic-ts-attr-regexp
+                       (treesit-node-text node t))))
+
+(defun alpinejs-generic-ts-setup ()
+  "Tree-sitter generic setup for Alpine.js framework.
+It uses JavaScript highlighting inside a limited set of HTML attributes.
+Intended to be used in combination with such major modes as
+`mhtml-ts-mode' and `liquid-generic-ts-mode'.  For example:
+
+\(add-hook \\='mhtml-ts-mode-hook \\='alpinejs-generic-ts-setup)
+\(add-hook \\='liquid-generic-ts-mode-hook \\='alpinejs-generic-ts-setup)"
+
+  ;; Use JavaScript highlighting for Alpinejs HTML attributes
+  (setq-local treesit-range-settings
+              (append treesit-range-settings
+                      (treesit-range-rules
+                       :embed 'javascript
+                       :host 'html
+                       :local t
+                       `((attribute
+                          (attribute_name) @_name
+                          (:match ,alpinejs-generic-ts-attr-regexp @_name)
+                          (quoted_attribute_value
+                           (attribute_value) @cap))))))
+
+  ;; Highlight only non-Alpinejs HTML attributes
+  (setq-local treesit-font-lock-settings
+              (treesit-replace-font-lock-feature-settings
+               (treesit-font-lock-rules
+                :language 'html
+                :override t
+                :feature 'string
+                `((attribute
+                   (attribute_name) @_name
+                   (:pred alpinejs-generic-ts-attr-not-match @_name)
+                   (quoted_attribute_value) @font-lock-string-face)))
+               treesit-font-lock-settings))
+
+  ;; Highlight only quotes for Alpinejs HTML attributes
+  (setq-local treesit-font-lock-settings
+              (append treesit-font-lock-settings
+                      (treesit-font-lock-rules
+                       :language 'html
+                       :override t
+                       :feature 'string
+                       `((attribute
+                          (attribute_name) @_name
+                          (:match ,alpinejs-generic-ts-attr-regexp @_name)
+                          (quoted_attribute_value "\"" @font-lock-string-face))))))
+
+  (treesit-major-mode-setup))
+
 (provide 'treesit-x)
 
 ;;; treesit-x.el ends here
index cf8db3d3bc0f3e082e062fdc29ddee0c21483f12..6db95bd07dbe00fb61f2ee2bf3812920dd041982 100644 (file)
@@ -1632,12 +1632,16 @@ Both SETTINGS and NEW-SETTINGS must be a value suitable for
 Return a value suitable for `treesit-font-lock-settings'"
   (let ((result nil))
     (dolist (new-setting new-settings)
-      (let ((new-feature (treesit-font-lock-setting-feature new-setting)))
-       (dolist (setting settings)
-         (let ((feature (treesit-font-lock-setting-feature setting)))
-           (if (eq new-feature feature)
-               (push new-setting result)
-             (push setting result))))))
+      (let ((new-feature (treesit-font-lock-setting-feature new-setting))
+            (new-lang (treesit-query-language
+                       (treesit-font-lock-setting-query new-setting))))
+        (dolist (setting settings)
+          (let ((feature (treesit-font-lock-setting-feature setting))
+                (lang (treesit-query-language
+                       (treesit-font-lock-setting-query setting))))
+            (if (and (eq new-lang lang) (eq new-feature feature))
+                (push new-setting result)
+              (push setting result))))))
     (nreverse result)))
 
 (defun treesit-add-font-lock-rules (rules &optional how feature)
@@ -1877,9 +1881,9 @@ If LOUDLY is non-nil, display some debugging information."
     ;; 1ms in xdisp.c, and 0.3ms in a small C file (for typing a single
     ;; character), not worth it.  --yuan
     (dolist (setting treesit-font-lock-settings)
-      (let* ((query (nth 0 setting))
-             (enable (nth 1 setting))
-             (override (nth 3 setting))
+      (let* ((query (treesit-font-lock-setting-query setting))
+             (enable (treesit-font-lock-setting-enable setting))
+             (override (treesit-font-lock-setting-override setting))
              (language (treesit-query-language query))
              (root-nodes (cl-remove-if-not
                           (lambda (node)