]> git.eshelyaron.com Git - emacs.git/commitdiff
Embed elixir in heex as well as elixir->heex->elixir (bug#76788).
authorJuri Linkov <juri@linkov.net>
Fri, 18 Apr 2025 16:52:19 +0000 (19:52 +0300)
committerEshel Yaron <me@eshelyaron.com>
Mon, 21 Apr 2025 20:36:26 +0000 (22:36 +0200)
* lisp/progmodes/elixir-ts-mode.el (elixir-ts--range-rules):
Rename to a shorter name from 'elixir-ts--treesit-range-rules'.
(elixir-ts--font-lock-feature-list, elixir-ts--thing-settings)
(elixir-ts--range-rules): New variables with default values
extracted from 'elixir-ts-mode'.
(elixir-ts-mode): Use 'elixir-ts--font-lock-feature-list',
'elixir-ts--thing-settings', 'elixir-ts--range-rules'
and 'heex-ts--range-rules'.
Use 'treesit-merge-font-lock-feature-list' to merge
'heex-ts--font-lock-feature-list'.

* lisp/progmodes/heex-ts-mode.el
(heex-ts--font-lock-feature-list, heex-ts--range-rules):
New variables.
(heex-ts-mode): Use 'heex-ts--font-lock-feature-list',
'heex-ts--range-rules'.  Merge 'elixir-ts--font-lock-settings',
'elixir-ts--font-lock-feature-list', 'elixir-ts--thing-settings'
for embedding elixir in heex.  Enable the 'sexp' navigation
by default with 'treesit-cycle-sexp-type'.

* lisp/progmodes/c-ts-mode.el (c-ts-mode): Append
'treesit-range-rules' to possibly already existing list in
'treesit-range-settings'.

* lisp/treesit.el (treesit-language-at-point-default):
Optimize to use 'when-let*'.

(cherry picked from commit d56e37c83c721c5bcffcf434138b27482b7e3fa6)

lisp/progmodes/c-ts-mode.el
lisp/progmodes/elixir-ts-mode.el
lisp/progmodes/heex-ts-mode.el
lisp/treesit.el

index fd255d68a578e2b7de188f4cc6103f2fcfeac15f..8d4b6f587d51127fe724c9045606c739f1d3defd 100644 (file)
@@ -1516,13 +1516,14 @@ in your init files."
                      treesit-font-lock-settings
                      c-ts-mode-doxygen-comment-font-lock-settings))
         (setq-local treesit-range-settings
-                    (treesit-range-rules
-                     :embed 'doxygen
-                     :host 'c
-                     :local t
-                     `(((comment) @cap
-                        (:match
-                         ,c-ts-mode--doxygen-comment-regex @cap)))))))))
+                    (append treesit-range-settings
+                            (treesit-range-rules
+                             :embed 'doxygen
+                             :host 'c
+                             :local t
+                             `(((comment) @cap
+                                (:match
+                                 ,c-ts-mode--doxygen-comment-regex @cap))))))))))
 
 (derived-mode-add-parents 'c-ts-mode '(c-mode))
 
index 2a0a388a4e4b5f08635be2ea323bb09dcc53fa97..3a136894454515bdc8f28c86dea6adc38c3f023d 100644 (file)
 
   "Tree-sitter font-lock settings.")
 
-(defvar elixir-ts--treesit-range-rules
-  (when (treesit-available-p)
-    (treesit-range-rules
-     :embed 'heex
-     :host 'elixir
-     '((sigil (sigil_name) @_name
-              (:match "^[HF]$" @_name)
-              (quoted_content) @heex)))))
-
+(defvar elixir-ts--font-lock-feature-list
+  '(( elixir-comment elixir-doc elixir-definition)
+    ( elixir-string elixir-keyword elixir-data-type)
+    ( elixir-sigil elixir-builtin elixir-string-escape)
+    ( elixir-function-call elixir-variable elixir-operator elixir-number ))
+  "Tree-sitter font-lock feature list.")
+
+(defvar elixir-ts--thing-settings
+  `((sexp (not (or (and named
+                        ,(rx bos (or "source" "comment") eos))
+                   (and anonymous
+                        ,(rx (or "{" "}" "[" "]" "(" ")"
+                                 "do" "end"))))))
+    (list
+     (or (and "\\`arguments\\'" ,#'elixir-ts--with-parens-0-p)
+         (and "\\`unary_operator\\'" ,#'elixir-ts--with-parens-1-p)
+         ,(rx bos (or "block"
+                      "quoted_atom"
+                      "string"
+                      "interpolation"
+                      "sigil"
+                      "quoted_keyword"
+                      "list"
+                      "tuple"
+                      "bitstring"
+                      "map"
+                      "do_block"
+                      "anonymous_function")
+              eos)))
+    (sexp-default
+     ;; For `C-M-f' in "&|(a)"
+     ("(" . ,(lambda (node)
+               (equal (treesit-node-type (treesit-node-parent node))
+                      "unary_operator"))))
+    (sentence
+     ,(rx bos (or "call") eos))
+    (text
+     ,(rx bos (or "string" "sigil" "comment") eos)))
+  "`treesit-thing-settings' for Elixir.")
+
+(defvar elixir-ts--range-rules
+  (treesit-range-rules
+   :embed 'heex
+   :host 'elixir
+   '((sigil (sigil_name) @_name
+            (:match "^[HF]$" @_name)
+            (quoted_content) @heex))))
+
+(defvar heex-ts--range-rules)
 (defvar heex-ts--thing-settings)
 (defvar heex-ts--indent-rules)
 (defvar heex-ts--font-lock-settings)
+(defvar heex-ts--font-lock-feature-list)
 
 (defun elixir-ts--treesit-anchor-grand-parent-bol (_n parent &rest _)
   "Return the beginning of non-space characters for the parent node of PARENT."
@@ -693,11 +734,7 @@ Return nil if NODE is not a defun node or doesn't have a name."
     ;; Font-lock.
     (setq-local treesit-font-lock-settings elixir-ts--font-lock-settings)
     (setq-local treesit-font-lock-feature-list
-                '(( elixir-comment elixir-doc elixir-definition)
-                  ( elixir-string elixir-keyword elixir-data-type)
-                  ( elixir-sigil elixir-builtin elixir-string-escape)
-                  ( elixir-function-call elixir-variable elixir-operator elixir-number )))
-
+                elixir-ts--font-lock-feature-list)
 
     ;; Imenu.
     (setq-local treesit-simple-imenu-settings
@@ -708,37 +745,7 @@ Return nil if NODE is not a defun node or doesn't have a name."
 
     ;; Navigation.
     (setq-local treesit-thing-settings
-                `((elixir
-                   (sexp (not (or (and named
-                                       ,(rx bos (or "source" "comment") eos))
-                                  (and anonymous
-                                       ,(rx (or "{" "}" "[" "]" "(" ")"
-                                                "do" "end"))))))
-                   (list
-                    (or (and "\\`arguments\\'" ,#'elixir-ts--with-parens-0-p)
-                        (and "\\`unary_operator\\'" ,#'elixir-ts--with-parens-1-p)
-                        ,(rx bos (or "block"
-                                     "quoted_atom"
-                                     "string"
-                                     "interpolation"
-                                     "sigil"
-                                     "quoted_keyword"
-                                     "list"
-                                     "tuple"
-                                     "bitstring"
-                                     "map"
-                                     "do_block"
-                                     "anonymous_function")
-                             eos)))
-                   (sexp-default
-                    ;; For `C-M-f' in "&|(a)"
-                    ("(" . ,(lambda (node)
-                              (equal (treesit-node-type (treesit-node-parent node))
-                                     "unary_operator"))))
-                   (sentence
-                    ,(rx bos (or "call") eos))
-                   (text
-                    ,(rx bos (or "string" "sigil" "comment") eos)))
+                `((elixir ,@elixir-ts--thing-settings)
                   (heex ,@heex-ts--thing-settings)))
     (setq-local treesit-defun-type-regexp
                 '("call" . elixir-ts--defun-p))
@@ -747,7 +754,12 @@ Return nil if NODE is not a defun node or doesn't have a name."
 
     ;; Embedded Heex.
     (when (treesit-ensure-installed 'heex)
-      (setq-local treesit-range-settings elixir-ts--treesit-range-rules)
+      (setq-local treesit-range-settings
+                  (append elixir-ts--range-rules
+                          ;; Leave only local parsers from heex
+                          ;; for elixir->heex->elixir embedding.
+                          (seq-filter (lambda (r) (nth 2 r))
+                                      heex-ts--range-rules)))
 
       (setq-local treesit-font-lock-settings
                   (append treesit-font-lock-settings
@@ -758,12 +770,9 @@ Return nil if NODE is not a defun node or doesn't have a name."
                           heex-ts--indent-rules))
 
       (setq-local treesit-font-lock-feature-list
-                  '(( elixir-comment elixir-doc elixir-definition
-                      heex-comment heex-keyword heex-doctype )
-                    ( elixir-string elixir-keyword elixir-data-type
-                      heex-component heex-tag heex-attribute heex-string )
-                    ( elixir-sigil elixir-builtin elixir-string-escape)
-                    ( elixir-function-call elixir-variable elixir-operator elixir-number ))))
+                  (treesit-merge-font-lock-feature-list
+                   treesit-font-lock-feature-list
+                   heex-ts--font-lock-feature-list)))
 
     (treesit-major-mode-setup)
     (setq-local syntax-propertize-function #'elixir-ts--syntax-propertize)
index 38d75e6924387db4cecc18c373d302857efba002..e5a4fe196acfecac526c1ce5ea766133423b9348 100644 (file)
         ])))
   "Tree-sitter font-lock settings.")
 
+(defvar heex-ts--font-lock-feature-list
+  '(( heex-comment heex-keyword heex-doctype )
+    ( heex-component heex-tag heex-attribute heex-string )
+    () ())
+  "Tree-sitter font-lock feature list.")
+
 (defun heex-ts--defun-name (node)
   "Return the name of the defun NODE.
 Return nil if NODE is not a defun node or doesn't have a name."
@@ -166,6 +172,24 @@ Return nil if NODE is not a defun node or doesn't have a name."
      ,(rx bos (or "comment" "text") eos)))
   "`treesit-thing-settings' for HEEx.")
 
+(defvar heex-ts--range-rules
+  (treesit-range-rules
+   :embed 'elixir
+   :host 'heex
+   '((directive [(partial_expression_value)
+                 (ending_expression_value)]
+                @cap))
+
+   :embed 'elixir
+   :host 'heex
+   :local t
+   '((directive (expression_value) @cap)
+     (expression (expression_value) @cap))))
+
+(defvar elixir-ts--font-lock-settings)
+(defvar elixir-ts--font-lock-feature-list)
+(defvar elixir-ts--thing-settings)
+
 ;;;###autoload
 (define-derived-mode heex-ts-mode html-mode "HEEx"
   "Major mode for editing HEEx, powered by tree-sitter."
@@ -204,11 +228,29 @@ Return nil if NODE is not a defun node or doesn't have a name."
     (setq-local treesit-simple-indent-rules heex-ts--indent-rules)
 
     (setq-local treesit-font-lock-feature-list
-                '(( heex-comment heex-keyword heex-doctype )
-                  ( heex-component heex-tag heex-attribute heex-string )
-                  () ()))
+                heex-ts--font-lock-feature-list)
+
+    (when (treesit-ready-p 'elixir)
+      (require 'elixir-ts-mode)
+      (treesit-parser-create 'elixir)
+
+      (setq-local treesit-range-settings heex-ts--range-rules)
+
+      (setq-local treesit-font-lock-settings
+                  (append treesit-font-lock-settings
+                          elixir-ts--font-lock-settings))
+      (setq-local treesit-font-lock-feature-list
+                  (treesit-merge-font-lock-feature-list
+                   treesit-font-lock-feature-list
+                   elixir-ts--font-lock-feature-list))
+
+      (setq-local treesit-thing-settings
+                  (append treesit-thing-settings
+                          `((elixir ,@elixir-ts--thing-settings)))))
 
-    (treesit-major-mode-setup)))
+    (treesit-major-mode-setup)
+    ;; Enable the 'sexp' navigation by default
+    (treesit-cycle-sexp-type)))
 
 (derived-mode-add-parents 'heex-ts-mode '(heex-mode))
 
index a0fef8d083a41974ea277c719a04fe663d533b6c..669d01cf1813c00d7803fdd62bdcb505d4a46bf3 100644 (file)
@@ -195,9 +195,8 @@ Returns the language at POSITION, or nil if there's no parser in the
 buffer.  When there are multiple parsers that cover POSITION, use the
 parser with the deepest embed level as it's the \"most relevant\" parser
 at POSITION."
-  (let ((parser (car (treesit-parsers-at position))))
-    (when parser
-      (treesit-parser-language parser))))
+  (when-let* ((parser (car (treesit-parsers-at position))))
+    (treesit-parser-language parser)))
 
 ;;; Node API supplement