]> git.eshelyaron.com Git - emacs.git/commitdiff
New command 'treesit-toggle-sexp-mode' (bug#76676).
authorJuri Linkov <juri@linkov.net>
Wed, 9 Apr 2025 18:21:53 +0000 (21:21 +0300)
committerEshel Yaron <me@eshelyaron.com>
Fri, 11 Apr 2025 11:32:18 +0000 (13:32 +0200)
* lisp/treesit.el (treesit-forward-sexp): Don't use
'treesit-sexp-type-regexp' reserved for list commands
to override their default 'list' thing.
(treesit-down-list, treesit-up-list): Use
'treesit-sexp-type-regexp' instead of 'list'
when it's non-nil.
(treesit-toggle-sexp-mode): New command.

* lisp/progmodes/c-ts-mode.el (c-ts-mode--thing-settings):
Improve 'sexp' thing settings to exclude the top-level
"translation_unit" that just moves to EOF and also "comment".

* lisp/progmodes/elixir-ts-mode.el (elixir-ts--sexp-regexp): Remove.
(elixir-ts--forward-sexp): Remove to use the default 'sexp' navigation.
(elixir-ts--with-parens-0-p, elixir-ts--with-parens-1-p):
New internal functions.
(elixir-ts-mode): Add 'treesit-thing-settings'
instead of 'forward-sexp-function' (bug#76788).

* lisp/progmodes/heex-ts-mode.el (heex-ts--sexp-regexp): Remove.
(heex-ts--forward-sexp): Remove to use the default 'sexp' navigation.
(heex-ts--thing-settings): New variable.
(heex-ts-mode): Use 'heex-ts--thing-settings'
instead of 'forward-sexp-function'.

* lisp/progmodes/java-ts-mode.el (java-ts-mode):
Improve 'sexp' thing to use settings like in c-ts-mode.

* lisp/progmodes/php-ts-mode.el (php-ts-mode):
Improve 'sexp' thing settings to exclude the top-level
"program" that just moves to EOF and also "comment".

* lisp/progmodes/ruby-ts-mode.el (ruby-ts-mode):
Improve 'sexp' thing to use settings like in c-ts-mode.

* lisp/textmodes/css-mode.el (css--treesit-thing-settings):
Add 'sexp' thing.  Add "string_value" to 'text' thing.

* lisp/textmodes/html-ts-mode.el (html-ts-mode--treesit-things-settings):
Improve 'sexp' thing to use settings like in c-ts-mode.
Add "doctype" to the 'list' thing.

(cherry picked from commit 99a2cb05a41c66565d417e11e60f4324aaa5c5b5)

lisp/progmodes/c-ts-mode.el
lisp/progmodes/elixir-ts-mode.el
lisp/progmodes/heex-ts-mode.el
lisp/progmodes/java-ts-mode.el
lisp/progmodes/php-ts-mode.el
lisp/progmodes/ruby-ts-mode.el
lisp/textmodes/css-mode.el
lisp/textmodes/html-ts-mode.el
lisp/treesit.el

index c49e928884a649b64592fb4f01889eb7ee7a4287..a9af2eb679a93070fed68c3a075214b27c9e430d 100644 (file)
@@ -1194,7 +1194,11 @@ if `c-ts-mode-emacs-sources-support' is non-nil."
 (defvar c-ts-mode--thing-settings
   `(;; It's more useful to include semicolons as sexp so
     ;; that users can move to the end of a statement.
-    (sexp (not ,(rx (or "{" "}" "[" "]" "(" ")" ","))))
+    (sexp (not (or (and named
+                        ,(rx bos (or "translation_unit" "comment") eos))
+                   (and anonymous
+                        ,(rx (or "{" "}" "[" "]"
+                                 "(" ")" ","))))))
     (list
      ,(regexp-opt '("preproc_params"
                     "preproc_if"
index 9a0418eaf29c8f56f024d0f490c8c9881e35d701..9d938e10fde4a73965e5c960ca0adb93eabf0ad6 100644 (file)
   "Face used for attributes in Elixir files."
   :group 'elixir-ts)
 
-(defconst elixir-ts--sexp-regexp
-  (rx bol
-      (or "call" "stab_clause" "binary_operator" "list" "tuple" "map" "pair"
-          "sigil" "string" "atom" "alias" "arguments" "identifier"
-          "boolean" "quoted_content" "bitstring")
-      eol))
-
 (defconst elixir-ts--test-definition-keywords
   '("describe" "test"))
 
               (:match "^[HF]$" @_name)
               (quoted_content) @heex)))))
 
-(defvar heex-ts--sexp-regexp)
+(defvar heex-ts--thing-settings)
 (defvar heex-ts--indent-rules)
 (defvar heex-ts--font-lock-settings)
 
-(defun elixir-ts--forward-sexp (&optional arg)
-  "Move forward across one balanced expression (sexp).
-With ARG, do it many times.  Negative ARG means move backward."
-  (or arg (setq arg 1))
-  (funcall
-   (if (> arg 0) #'treesit-end-of-thing #'treesit-beginning-of-thing)
-   (if (eq (treesit-language-at (point)) 'heex)
-       heex-ts--sexp-regexp
-     elixir-ts--sexp-regexp)
-   (abs arg)))
-
 (defun elixir-ts--treesit-anchor-grand-parent-bol (_n parent &rest _)
   "Return the beginning of non-space characters for the parent node of PARENT."
   (save-excursion
@@ -624,6 +606,14 @@ Return nil if NODE is not a defun node or doesn't have a name."
                 (_ nil))))
     (_ nil)))
 
+(defun elixir-ts--with-parens-0-p (node)
+  (equal (treesit-node-type (treesit-node-child node 0))
+         "("))
+
+(defun elixir-ts--with-parens-1-p (node)
+  (equal (treesit-node-type (treesit-node-child node 1))
+         "("))
+
 (defvar elixir-ts--syntax-propertize-query
   (when (treesit-available-p)
     (treesit-query-compile
@@ -707,7 +697,34 @@ Return nil if NODE is not a defun node or doesn't have a name."
     (setq-local treesit-simple-indent-rules elixir-ts--indent-rules)
 
     ;; Navigation.
-    (setq-local forward-sexp-function #'elixir-ts--forward-sexp)
+    (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)))
+                   (sentence
+                    ,(rx bos (or "call") eos))
+                   (text
+                    ,(rx bos (or "string" "sigil" "comment") eos)))
+                  (heex ,@heex-ts--thing-settings)))
     (setq-local treesit-defun-type-regexp
                 '("call" . elixir-ts--defun-p))
 
index 65aaa0d488d7e21c694525d29f223e69c094d70f..93b87d3a29dd4430888b75e5d67a4edbfe2cc237 100644 (file)
   :safe 'integerp
   :group 'heex-ts)
 
-(defconst heex-ts--sexp-regexp
-  (rx bol
-      (or "directive" "tag" "component" "slot"
-          "attribute" "attribute_value" "quoted_attribute_value" "expression")
-      eol))
-
 ;; There seems to be no parent directive block for tree-sitter-heex,
 ;; so we ignore them for now until we learn how to query them.
 ;; https://github.com/phoenixframework/tree-sitter-heex/issues/28
@@ -139,14 +133,29 @@ Return nil if NODE is not a defun node or doesn't have a name."
        (treesit-node-child (treesit-node-child node 0) 1) nil)))
     (_ nil)))
 
-(defun heex-ts--forward-sexp (&optional arg)
-  "Move forward across one balanced expression (sexp).
-With ARG, do it many times.  Negative ARG means move backward."
-  (or arg (setq arg 1))
-  (funcall
-   (if (> arg 0) #'treesit-end-of-thing #'treesit-beginning-of-thing)
-   heex-ts--sexp-regexp
-   (abs arg)))
+(defvar heex-ts--thing-settings
+  `((sexp
+     (not (or (and named
+                   ,(rx bos (or "fragment" "comment") eos))
+              (and anonymous
+                   ,(rx (or "<!" "<" ">" "{" "}"))))))
+    (list
+     ,(rx bos (or "doctype"
+                  "tag"
+                  "component"
+                  "slot"
+                  "expression"
+                  "directive"
+                  "comment")
+          eos))
+    (sentence
+     ,(rx bos (or "tag_name"
+                  "component_name"
+                  "attribute")
+          eos))
+    (text
+     ,(rx bos (or "comment" "text") eos)))
+  "`treesit-thing-settings' for HEEx.")
 
 ;;;###autoload
 (define-derived-mode heex-ts-mode html-mode "HEEx"
@@ -158,10 +167,7 @@ With ARG, do it many times.  Negative ARG means move backward."
 
     ;; Comments
     (setq-local treesit-thing-settings
-                `((heex
-                   (text ,(regexp-opt '("comment" "text"))))))
-
-    (setq-local forward-sexp-function #'heex-ts--forward-sexp)
+                `((heex ,@heex-ts--thing-settings)))
 
     ;; Navigation.
     (setq-local treesit-defun-type-regexp
index a36ea4f62ab6f5e8b1fd5ded9a4ee0fdf1954771..e1de96febd0379baf8f63d8d7ab5af6ee50e2289 100644 (file)
@@ -444,19 +444,15 @@ Return nil if there is no name or if NODE is not a defun node."
 
     (setq-local treesit-thing-settings
                 `((java
-                   (sexp ,(rx (or "annotation"
-                                  "parenthesized_expression"
-                                  "argument_list"
-                                  "identifier"
-                                  "modifiers"
-                                  "block"
-                                  "body"
-                                  "literal"
-                                  "access"
-                                  "reference"
-                                  "_type"
-                                  "true"
-                                  "false")))
+                   (sexp (not (or (and named
+                                       ,(rx bos (or "program"
+                                                    "line_comment"
+                                                    "block_comment")
+                                            eos))
+                                  (and anonymous
+                                       ,(rx (or "{" "}" "[" "]"
+                                                "(" ")" "<" ">"
+                                                ","))))))
                    (list ,(rx bos (or "inferred_parameters"
                                       "parenthesized_expression"
                                       "argument_list"
index cc5f02a74c2c2c5a0f2a44910267f56b577e084b..1a0b7707034f4633e737972805c20b429c7d39b2 100644 (file)
@@ -1454,7 +1454,14 @@ Depends on `c-ts-common-comment-setup'."
     (setq-local treesit-thing-settings
                 `((php
                    (defun ,treesit-defun-type-regexp)
-                   (sexp (not ,(rx (or "{" "}" "[" "]" "(" ")" ","))))
+                   (sexp (not (or (and named
+                                       ,(rx bos (or "program"
+                                                    "comment")
+                                            eos))
+                                  (and anonymous
+                                       ,(rx bos (or "{" "}" "[" "]"
+                                                    "(" ")" ",")
+                                            eos)))))
                    (list
                     ,(rx bos (or "namespace_use_group"
                                  "enum_declaration_list"
index 6fb71a75a58c6a4b9c9edc4087d39791fa0369ef..f646e5e9385fb2d1177a91b72a691af2e372bc1f 100644 (file)
@@ -1167,52 +1167,18 @@ leading double colon is not added."
 
   (setq-local treesit-thing-settings
               `((ruby
-                 (sexp ,(cons (rx
-                               bos
-                               (or
-                                "class"
-                                "singleton_class"
-                                "module"
-                                "method"
-                                "singleton_method"
-                                "array"
-                                "hash"
-                                "parenthesized_statements"
-                                "method_parameters"
-                                "array_pattern"
-                                "hash_pattern"
-                                "if"
-                                "else"
-                                "then"
-                                "unless"
-                                "case"
-                                "case_match"
-                                "when"
-                                "while"
-                                "until"
-                                "for"
-                                "block"
-                                "do_block"
-                                "begin"
-                                "integer"
-                                "identifier"
-                                "self"
-                                "super"
-                                "constant"
-                                "simple_symbol"
-                                "hash_key_symbol"
-                                "symbol_array"
-                                "string"
-                                "string_array"
-                                "heredoc_body"
-                                "regex"
-                                "argument_list"
-                                "interpolation"
-                                "instance_variable"
-                                "global_variable"
-                                )
-                               eos)
-                              #'ruby-ts--sexp-p))
+                 (sexp (not (or (and named
+                                     ,(rx bos (or "program"
+                                                  "body_statement"
+                                                  "comment"
+                                                  "then")
+                                          eos))
+                                (and anonymous
+                                     ,(rx (or "do" "begin"
+                                              "if" "unless"
+                                              "def" "end"
+                                              "(" ")" "[" "]"
+                                              "{" "}" "|" "," ";"))))))
                  (list ,(cons (rx
                                bos
                                (or
index 17da056f41edee4c3e0ef5d8cdf1ced71c9197bb..e715a11a03b536fc42ffd9957d17e75922b5d727 100644 (file)
@@ -1781,7 +1781,13 @@ rgb()/rgba()."
            res)))))))
 
 (defvar css--treesit-thing-settings
-  `((css (list
+  `((css (sexp
+          (not (or (and named
+                        ,(rx bos (or "stylesheet" "comment") eos))
+                   (and anonymous
+                        ,(rx (or "{" "}" "[" "]"
+                                 "(" ")" ","))))))
+         (list
           ,(rx bos (or "keyframe_block_list"
                        "block"
                        "pseudo_class_arguments"
@@ -1804,7 +1810,7 @@ rgb()/rgba()."
                        "declaration")
                eos))
          (text
-          ,(rx bos "comment" eos))))
+          ,(rx bos (or "comment" "string_value") eos))))
   "Settings for `treesit-thing-settings'.")
 
 (defvar css--treesit-font-lock-feature-list
index 30d1f080b96dd4ad2c1689661ea3ad2bea4e15cb..ff79945b2919c5fa1a755681f2e0d9c7d42875e5 100644 (file)
 
 (defvar html-ts-mode--treesit-things-settings
   `((html
-     (sexp ,(regexp-opt '("element"
-                          "text"
-                          "attribute"
-                          "value")))
-     (list ,(rx (or
-                 ;; Also match script_element and style_element
-                 "element"
-                 ;; HTML comments have the element syntax
-                 "comment")))
+     (sexp (not (or (and named
+                         ,(rx bos (or "document" "tag_name") eos))
+                    (and anonymous
+                         ,(rx (or "<!" "<" ">" "</"))))))
+     (list ,(rx (or "doctype"
+                    ;; Also match script_element and style_element
+                    "element"
+                    ;; HTML comments have the element syntax
+                    "comment")))
      (sentence ,(rx (and bos (or "tag_name" "attribute") eos)))
      (text ,(regexp-opt '("comment" "text")))))
   "Settings for `treesit-thing-settings'.")
index 5d2e26c7368f9526679f0bef433eb8be3c99a154..bd6221322c29e3a34cde08648c2ad0fc9c5ef577 100644 (file)
@@ -2996,8 +2996,7 @@ across atoms (such as symbols or words) inside the list."
   (let ((arg (or arg 1))
         (pred (or treesit-sexp-type-regexp 'sexp))
         (node-at-point
-         (when (null treesit-sexp-type-regexp)
-           (treesit-node-at (point) (treesit-language-at (point))))))
+         (treesit-node-at (point) (treesit-language-at (point)))))
     (or (when (and node-at-point
                    ;; Make sure point is strictly inside node.
                    (< (treesit-node-start node-at-point)
@@ -3099,7 +3098,7 @@ redefined by the variable `down-list-function'.
 
 ARG is described in the docstring of `down-list'."
   (interactive "^p")
-  (let* ((pred 'list)
+  (let* ((pred (or treesit-sexp-type-regexp 'list))
          (arg (or arg 1))
          (cnt arg)
          (inc (if (> arg 0) 1 -1)))
@@ -3115,7 +3114,8 @@ ARG is described in the docstring of `down-list'."
                         (treesit-thing-prev (point) pred)))
              (child (when sibling
                       (treesit-node-child sibling (if (> arg 0) 0 -1)))))
-        (or (when (and default-pos
+        (or (when (and (null treesit-sexp-type-regexp)
+                       default-pos
                        (or (null child)
                            (if (> arg 0)
                                (<= default-pos (treesit-node-start child))
@@ -3139,7 +3139,7 @@ redefined by the variable `up-list-function'.
 
 ARG is described in the docstring of `up-list'."
   (interactive "^p")
-  (let* ((pred 'list)
+  (let* ((pred (or treesit-sexp-type-regexp 'list))
          (arg (or arg 1))
          (cnt arg)
          (inc (if (> arg 0) 1 -1)))
@@ -3166,7 +3166,8 @@ ARG is described in the docstring of `up-list'."
                             (treesit-node-at (point) (car parsers)) pred)
                     parsers (cdr parsers)))))
 
-        (or (when (and default-pos
+        (or (when (and (null treesit-sexp-type-regexp)
+                       default-pos
                        (or (null parent)
                            (if (> arg 0)
                                (<= default-pos (treesit-node-end parent))
@@ -3179,6 +3180,37 @@ ARG is described in the docstring of `up-list'."
             (user-error "At top level")))
       (setq cnt (- cnt inc)))))
 
+(defun treesit-toggle-sexp-mode ()
+  "Toggle the mode of navigation for sexp and list commands.
+This mode toggle affects such navigation commands as
+`treesit-forward-sexp', `treesit-forward-list', `treesit-down-list',
+`treesit-up-list'.
+
+The list mode uses the `list' thing defined in `treesit-thing-settings'.
+In this mode commands use syntax definition to navigate symbols and
+treesit definition to navigate lists.
+
+The sexp mode uses the `sexp' thing defined in `treesit-thing-settings'.
+In this mode commands use the treesit definition only
+without distinction between symbols and lists."
+  (interactive)
+  (if (not (treesit-thing-defined-p 'list (treesit-language-at (point))))
+      (message "No `list' thing is defined in `treesit-thing-settings'")
+    (setq-local treesit-sexp-type-regexp
+                (unless treesit-sexp-type-regexp
+                  (if (treesit-thing-defined-p
+                       'sexp (treesit-language-at (point)))
+                      'sexp
+                    #'treesit-node-named))
+                forward-sexp-function
+                (if treesit-sexp-type-regexp
+                    #'treesit-forward-sexp
+                  #'treesit-forward-sexp-list))
+    (message "Toggle to mode where sexp commands navigate %s"
+             (or (and treesit-sexp-type-regexp
+                      "treesit nodes")
+                 "syntax symbols and treesit lists"))))
+
 (defun treesit-transpose-sexps (&optional arg)
   "Tree-sitter `transpose-sexps' function.
 ARG is the same as in `transpose-sexps'.