Add new variable 'forward-list-function' for 'treesit-forward-list'

* lisp/emacs-lisp/lisp.el (forward-list-default-function): New function.
(forward-list-function): New variable (bug#73404).
(forward-list): Move meat to 'forward-list-default-function',
and call 'forward-list-function' when non-nil.

* lisp/treesit.el (treesit-forward-list): Rewrite to not rely on
'treesit-forward-sexp'.
(treesit-major-mode-setup): Set 'forward-list-function' to
'treesit-forward-list'.
This commit is contained in:
Juri Linkov 2024-12-29 19:42:40 +02:00
parent c85d2e3519
commit 3db984c72b
3 changed files with 48 additions and 22 deletions

View file

@ -1002,6 +1002,11 @@ The new function 'treesit-forward-sexp-list' uses 'sexp-list'
to move across lists. But to move across atoms inside the list
it uses `forward-sexp-default-function'.
*** New function 'treesit-forward-list'.
Tree-sitter conditionally sets 'forward-list-function' for major modes
that have defined 'sexp-list' in 'treesit-thing-settings' to enable
the 'forward-list' motion command.
+++
*** New function 'treesit-language-display-name'.
This new function returns the display name of a language given the

View file

@ -143,6 +143,14 @@ This command assumes point is not in a string or comment."
(point))
nil t))))
(defun forward-list-default-function (&optional arg)
"Default function for `forward-list-function'."
(goto-char (or (scan-lists (point) arg 0) (buffer-end arg))))
(defvar forward-list-function nil
"If non-nil, `forward-list' delegates to this function.
Should take the same arguments and behave similarly to `forward-list'.")
(defun forward-list (&optional arg interactive)
"Move forward across one balanced group of parentheses.
This command will also work on other parentheses-like expressions
@ -150,6 +158,7 @@ defined by the current language mode.
With ARG, do it that many times.
Negative arg -N means move backward across N groups of parentheses.
This command assumes point is not in a string or comment.
Calls `forward-list-function' to do the work, if that is non-nil.
If INTERACTIVE is non-nil, as it is interactively,
report errors as appropriate for this kind of usage."
(interactive "^p\nd")
@ -160,7 +169,9 @@ report errors as appropriate for this kind of usage."
"No next group"
"No previous group"))))
(or arg (setq arg 1))
(goto-char (or (scan-lists (point) arg 0) (buffer-end arg)))))
(if forward-list-function
(funcall forward-list-function arg)
(forward-list-default-function arg))))
(defun backward-list (&optional arg interactive)
"Move backward across one balanced group of parentheses.
@ -169,6 +180,7 @@ defined by the current language mode.
With ARG, do it that many times.
Negative arg -N means move forward across N groups of parentheses.
This command assumes point is not in a string or comment.
Uses `forward-list' to do the work.
If INTERACTIVE is non-nil, as it is interactively,
report errors as appropriate for this kind of usage."
(interactive "^p\nd")

View file

@ -2420,29 +2420,10 @@ delimits medium sized statements in the source code. It is,
however, smaller in scope than sentences. This is used by
`treesit-forward-sexp' and friends.")
(defun treesit-forward-list (&optional arg)
"Move forward across a list.
What constitutes a list is determined by `sexp-list' in
`treesit-thing-settings' that usually defines
parentheses-like expressions.
Unlike `forward-sexp', this command moves only across a list,
but not across atoms (such as symbols or words) inside the list.
This command is the tree-sitter variant of `forward-list'. But since
`forward-list' has no \"forward-list-function\" like there is
`forward-sexp-function' for `forward-sexp', this command
can be used on its own.
ARG is described in the docstring of `forward-list'."
(interactive "^p")
(let ((treesit-sexp-type-regexp 'sexp-list))
(treesit-forward-sexp arg)))
(defun treesit-forward-sexp (&optional arg)
"Tree-sitter implementation for `forward-sexp-function'.
ARG is described in the docstring of `forward-sexp-function'.
ARG is described in the docstring of `forward-sexp'.
If point is inside a text environment where tree-sitter is not
supported, go forward a sexp using `forward-sexp-default-function'.
@ -2541,6 +2522,33 @@ ARG is described in the docstring of `forward-sexp-function'."
(goto-char default-pos))
(treesit-forward-list arg))))
(defun treesit-forward-list (&optional arg)
"Move forward across a list.
What constitutes a list is determined by `sexp-list' in
`treesit-thing-settings' that usually defines
parentheses-like expressions.
Unlike `forward-sexp', this command moves only across a list,
but not across atoms (such as symbols or words) inside the list.
This command is the tree-sitter variant of `forward-list'
redefined by the variable `forward-list-function'.
ARG is described in the docstring of `forward-list'."
(interactive "^p")
(let ((arg (or arg 1))
(pred 'sexp-list))
(or (if (> arg 0)
(treesit-end-of-thing pred (abs arg) 'restricted)
(treesit-beginning-of-thing pred (abs arg) 'restricted))
(when-let* ((parent (treesit-thing-at (point) pred t))
(boundary (if (> arg 0)
(treesit-node-child parent -1)
(treesit-node-child parent 0))))
(signal 'scan-error (list "No more group to move across"
(treesit-node-start boundary)
(treesit-node-end boundary)))))))
(defun treesit-transpose-sexps (&optional arg)
"Tree-sitter `transpose-sexps' function.
ARG is the same as in `transpose-sexps'.
@ -3465,7 +3473,8 @@ before calling this function."
(setq-local transpose-sexps-function #'treesit-transpose-sexps))
(when (treesit-thing-defined-p 'sexp-list nil)
(setq-local forward-sexp-function #'treesit-forward-sexp-list))
(setq-local forward-sexp-function #'treesit-forward-sexp-list)
(setq-local forward-list-function #'treesit-forward-list))
(when (treesit-thing-defined-p 'sentence nil)
(setq-local forward-sentence-function #'treesit-forward-sentence))