New command 'treesit-toggle-sexp-mode' (bug#76676).
* 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.
This commit is contained in:
parent
fa247a24a5
commit
99a2cb05a4
10 changed files with 161 additions and 116 deletions
11
etc/NEWS
11
etc/NEWS
|
@ -535,6 +535,17 @@ This variable has no effect when Transient Mark mode is off.
|
|||
|
||||
* Changes in Specialized Modes and Packages in Emacs 31.1
|
||||
|
||||
** Tree-sitter
|
||||
|
||||
*** New command 'treesit-toggle-sexp-mode'.
|
||||
It toggles the mode of navigation for such sexp and list commands as
|
||||
'treesit-forward-sexp', 'treesit-forward-list', 'treesit-down-list',
|
||||
'treesit-up-list'.
|
||||
In sexp mode these commands navigate purely by treesit nodes
|
||||
defined by the thing ‘sexp’.
|
||||
In list mode they navigate using syntax tables for symbols
|
||||
and using the treesit thing ‘list’ for lists.
|
||||
|
||||
---
|
||||
** Text mode
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -111,13 +111,6 @@
|
|||
"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"))
|
||||
|
||||
|
@ -574,21 +567,10 @@
|
|||
(: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))
|
||||
|
||||
|
|
|
@ -56,12 +56,6 @@
|
|||
: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
|
||||
|
|
|
@ -436,19 +436,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"
|
||||
|
|
|
@ -1455,7 +1455,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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -90,15 +90,15 @@
|
|||
|
||||
(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'.")
|
||||
|
|
|
@ -3004,8 +3004,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)
|
||||
|
@ -3107,7 +3106,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)))
|
||||
|
@ -3123,7 +3122,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))
|
||||
|
@ -3147,7 +3147,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)))
|
||||
|
@ -3174,7 +3174,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))
|
||||
|
@ -3187,6 +3188,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'.
|
||||
|
|
Loading…
Add table
Reference in a new issue