* doc/lispref/parsing.texi (User-defined Things): Mention new
functions 'treesit-forward-list', 'treesit-down-list',
'treesit-up-list', 'treesit-show-paren-data' that use the thing
'list' with the symbol property 'treesit-thing-symbol' (bug#73404).
* lisp/treesit.el: Put the property 'treesit-thing-symbol'
on the symbol 'list'.
(treesit--forward-list-with-default, treesit-down-list)
(treesit-up-list, treesit-navigate-thing)
(treesit-show-paren-data--categorize, treesit-major-mode-setup):
Replace 'sexp-list' with 'list'.
* lisp/progmodes/c-ts-mode.el (c-ts-mode--thing-settings):
* lisp/progmodes/js.el (js-ts-mode):
* lisp/progmodes/ruby-ts-mode.el (ruby-ts-mode):
* lisp/progmodes/typescript-ts-mode.el (typescript-ts-base-mode)
(tsx-ts-mode):
* lisp/textmodes/html-ts-mode.el (html-ts-mode):
Replace 'sexp-list' with 'list'.
* src/treesit.c (treesit_traverse_validate_predicate)
(treesit_traverse_match_predicate): Check if the 'pred'
symbol has the property 'Qtreesit_thing_symbol'.
(syms_of_treesit): New symbol 'Qtreesit_thing_symbol'.
(cherry picked from commit
42a5ac3b513ff03c64c9609fc7e79c2b7932b2a4)
Emacs builtin functions already make use some thing definitions.
Command @code{treesit-forward-sexp} uses the @code{sexp} definition if
-major mode defines it; @code{treesit-forward-sentence} uses the
-@code{sentence} definition. Defun movement functions like
-@code{treesit-end-of-defun} uses the @code{defun} definition
-(@code{defun} definition is overridden by
+major mode defines it; @code{treesit-forward-list},
+@code{treesit-down-list}, @code{treesit-up-list},
+@code{treesit-show-paren-data} use the @code{list} definition (its
+symbol @code{list} has the symbol property @code{treesit-thing-symbol}
+to avoid ambiguity with the function that has the same name);
+@code{treesit-forward-sentence} uses the @code{sentence} definition.
+Defun movement functions like @code{treesit-end-of-defun} uses the
+@code{defun} definition (@code{defun} definition is overridden by
@var{treesit-defun-type-regexp} for backward compatibility). Major
modes can also define @code{comment}, @code{string}, @code{text}
(generally comments and strings).
'treesit-font-lock-setting-feature', 'treesit-font-lock-setting-enable',
and 'treesit-font-lock-setting-override'.
-*** New treesit thing 'sexp-list'.
+*** New treesit thing 'list'.
Unlike the existing thing 'sexp' that defines both lists and atoms,
-'sexp-list' defines only lists to be navigated by 'forward-sexp'.
-The new function 'treesit-forward-sexp-list' uses 'sexp-list'
+'list' defines only lists to be navigated by 'forward-sexp'.
+The new function 'treesit-forward-sexp-list' uses 'list'
to move across lists. But to move across atoms inside the list
it uses 'forward-sexp-default-function'.
-*** New tree-sitter based functions for moving by sexp-lists.
-If a major mode defines 'sexp-list' in 'treesit-thing-settings',
+*** New tree-sitter based functions for moving by lists.
+If a major mode defines 'list' in 'treesit-thing-settings',
tree-sitter setup for these modes sets 'forward-list-function' to
'treesit-forward-list', 'up-list-function' to 'treesit-up-list', and
'down-list-function' to 'treesit-down-list'. This enables the
`(;; 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-list
+ (list
,(regexp-opt '("preproc_params"
"preproc_parenthesized_expression"
"preproc_argument_list"
"Nodes that designate sexps in JavaScript.
See `treesit-thing-settings' for more information.")
-(defvar js--treesit-sexp-list-nodes
+(defvar js--treesit-list-nodes
'("export_clause"
"named_imports"
"statement_block"
(setq-local treesit-thing-settings
`((javascript
(sexp ,(js--regexp-opt-symbol js--treesit-sexp-nodes))
- (sexp-list ,(js--regexp-opt-symbol js--treesit-sexp-list-nodes))
+ (list ,(js--regexp-opt-symbol js--treesit-list-nodes))
(sentence ,(js--regexp-opt-symbol js--treesit-sentence-nodes))
(text ,(js--regexp-opt-symbol '("comment"
"string_fragment"))))))
(equal (treesit-node-type (treesit-node-child node 0))
"(")))
-(defun ruby-ts--sexp-list-p (node)
+(defun ruby-ts--list-p (node)
;; Distinguish between the named `unless' node and the
;; node with the same value of type.
(when (treesit-node-check node 'named)
)
eol)
#'ruby-ts--sexp-p))
- (sexp-list
+ (list
,(cons (rx
bol
(or
"array"
"hash")
eol)
- #'ruby-ts--sexp-list-p))
+ #'ruby-ts--list-p))
(text ,(lambda (node)
(or (member (treesit-node-type node)
'("comment" "string_content" "heredoc_content"))
"Nodes that designate sexps in TypeScript.
See `treesit-thing-settings' for more information.")
-(defvar typescript-ts-mode--sexp-list-nodes
+(defvar typescript-ts-mode--list-nodes
'("export_clause"
"named_imports"
"statement_block"
(setq-local treesit-thing-settings
`((typescript
(sexp ,(regexp-opt typescript-ts-mode--sexp-nodes 'symbols))
- (sexp-list ,(regexp-opt typescript-ts-mode--sexp-list-nodes
+ (list ,(regexp-opt typescript-ts-mode--list-nodes
'symbols))
(sentence ,(regexp-opt
typescript-ts-mode--sentence-nodes 'symbols))
(sexp ,(regexp-opt
(append typescript-ts-mode--sexp-nodes
'("jsx"))))
- (sexp-list ,(concat "^"
+ (list ,(concat "^"
(regexp-opt
- (append typescript-ts-mode--sexp-list-nodes
+ (append typescript-ts-mode--list-nodes
'(
"jsx_element"
"jsx_self_closing_element"
"text"
"attribute"
"value")))
- (sexp-list ,(regexp-opt '("element")) 'symbols)
+ (list ,(regexp-opt '("element")) 'symbols)
(sentence "tag")
(text ,(regexp-opt '("comment" "text"))))))
however, smaller in scope than sentences. This is used by
`treesit-forward-sexp' and friends.")
+;; Avoid interpreting the symbol `list' as a function.
+(put 'list 'treesit-thing-symbol t)
+
(defun treesit--scan-error (pred arg)
(when-let* ((parent (treesit-thing-at (point) pred t))
(boundary (treesit-node-child parent (if (> arg 0) -1 0))))
by `text' and `sexp' in `treesit-thing-settings'.
There is an alternative implementation in `treesit-forward-sexp-list'
-that uses `sexp-list' in `treesit-thing-settings' to move only
+that uses `list' in `treesit-thing-settings' to move only
across lists, whereas uses `forward-sexp-default-function' to move
across atoms (such as symbols or words) inside the list."
(interactive "^p")
the boundaries of the list.
ARG is described in the docstring of `forward-list'."
- (let* ((pred (or treesit-sexp-type-regexp 'sexp-list))
+ (let* ((pred (or treesit-sexp-type-regexp 'list))
(arg (or arg 1))
(cnt arg)
(inc (if (> arg 0) 1 -1)))
Whereas `treesit-forward-sexp' moves across both lists and atoms
using `sexp' in `treesit-thing-settings', this function uses
-`sexp-list' in `treesit-thing-settings' to move only across lists.
+`list' in `treesit-thing-settings' to move only across lists.
But to move across atoms (such as symbols or words) inside the list
it uses `forward-sexp-default-function' as long as it doesn't go
outside of the boundaries of the current list.
(defun treesit-forward-list (&optional arg)
"Move forward across a list.
-What constitutes a list is determined by `sexp-list' in
+What constitutes a list is determined by `list' in
`treesit-thing-settings' that usually defines
parentheses-like expressions.
(defun treesit-down-list (&optional arg)
"Move forward down one level of parentheses.
What constitutes a level of parentheses is determined by
-`sexp-list' in `treesit-thing-settings' that usually defines
+`list' in `treesit-thing-settings' that usually defines
parentheses-like expressions.
This command is the tree-sitter variant of `down-list'
ARG is described in the docstring of `down-list'."
(interactive "^p")
- (let* ((pred 'sexp-list)
+ (let* ((pred 'list)
(arg (or arg 1))
(cnt arg)
(inc (if (> arg 0) 1 -1)))
(defun treesit-up-list (&optional arg escape-strings no-syntax-crossing)
"Move forward out of one level of parentheses.
What constitutes a level of parentheses is determined by
-`sexp-list' in `treesit-thing-settings' that usually defines
+`list' in `treesit-thing-settings' that usually defines
parentheses-like expressions.
This command is the tree-sitter variant of `up-list'
ARG is described in the docstring of `up-list'."
(interactive "^p")
- (let* ((pred 'sexp-list)
+ (let* ((pred 'list)
(arg (or arg 1))
(cnt arg)
(inc (if (> arg 0) 1 -1)))
(setq pos (funcall
advance
(cond ((and (null next) (null prev)
- (not (eq thing 'sexp-list)))
+ (not (eq thing 'list)))
parent)
((> arg 0) next)
(t prev))))
;;; Show paren mode
(defun treesit-show-paren-data--categorize (pos &optional end-p)
- (let* ((pred 'sexp-list)
+ (let* ((pred 'list)
(parent (when (treesit-thing-defined-p
- 'sexp-list (treesit-language-at pos))
+ pred (treesit-language-at pos))
(treesit-parent-until
(treesit-node-at (if end-p (1- pos) pos)) pred)))
(first (when parent (treesit-node-child parent 0)))
(setq-local forward-sexp-function #'treesit-forward-sexp)
(setq-local transpose-sexps-function #'treesit-transpose-sexps))
- (when (treesit-thing-defined-p 'sexp-list nil)
+ (when (treesit-thing-defined-p 'list nil)
(setq-local forward-sexp-function #'treesit-forward-sexp-list)
(setq-local forward-list-function #'treesit-forward-list)
(setq-local down-list-function #'treesit-down-list)
}
if (STRINGP (pred))
return true;
- else if (FUNCTIONP (pred))
+ else if (FUNCTIONP (pred)
+ && !(SYMBOLP (pred) && !NILP (Fget (pred, Qtreesit_thing_symbol))))
return true;
else if (SYMBOLP (pred))
{
const char *type = ts_node_type (node);
return fast_c_string_match (pred, type, strlen (type)) >= 0;
}
- else if (FUNCTIONP (pred))
+ else if (FUNCTIONP (pred)
+ && !(SYMBOLP (pred) && !NILP (Fget (pred, Qtreesit_thing_symbol))))
{
Lisp_Object lisp_node = make_treesit_node (parser, node);
return !NILP (CALLN (Ffuncall, pred, lisp_node));
DEFSYM (Qtreesit_invalid_predicate, "treesit-invalid-predicate");
DEFSYM (Qtreesit_predicate_not_found, "treesit-predicate-not-found");
+ DEFSYM (Qtreesit_thing_symbol, "treesit-thing-symbol");
+
DEFSYM (Qor, "or");
#ifdef WINDOWSNT