From 64e8c4452ce852db0819f53653e2f1735385dd4a Mon Sep 17 00:00:00 2001 From: Juri Linkov Date: Sun, 14 Apr 2024 19:18:31 +0300 Subject: [PATCH] Add 'forward-sexp-default-function' to be used by 'treesit-forward-sexp' * lisp/emacs-lisp/lisp.el (forward-sexp-default-function): New function with body from 'forward-sexp' (bug#68993). (forward-sexp-function): Change the default value from nil to 'forward-sexp-default-function'. (forward-sexp): Use either 'forward-sexp-function' or 'forward-sexp-default-function'. * lisp/treesit.el (treesit-forward-sexp): In nodes of type 'text' fall back to 'forward-sexp-default-function'. Improve docstring. * doc/lispref/positions.texi (List Motion): Fix pxref. (cherry picked from commit 568c1741352a4932508fbbd474b9fd9ebe90ddfb) --- doc/lispref/positions.texi | 4 ++-- etc/NEWS | 4 ++++ lisp/emacs-lisp/lisp.el | 14 +++++++++----- lisp/treesit.el | 20 +++++++++++++++----- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/doc/lispref/positions.texi b/doc/lispref/positions.texi index 5e0143c7131..9193c1063d1 100644 --- a/doc/lispref/positions.texi +++ b/doc/lispref/positions.texi @@ -892,8 +892,8 @@ parser information to move across syntax constructs. Since what exactly is considered a sexp varies between languages, a major mode should set @code{treesit-thing-settings} to determine that. Then the mode can get navigation-by-sexp functionality for free, by using -@code{forward-sexp} and @code{backward-sexp}(@pxref{Moving by -Sentences,,, emacs, The extensible self-documenting text editor}). +@code{forward-sexp} and @code{backward-sexp}(@pxref{Expressions, +,, emacs, The extensible self-documenting text editor}). @node Skipping Characters @subsection Skipping Characters diff --git a/etc/NEWS b/etc/NEWS index 5ff82c99a52..e2740996c8d 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -2246,6 +2246,10 @@ All tree-sitter enabled modes that define 'sentence' in ** Functions and variables to move by program sexps +*** New function 'forward-sexp-default-function'. +The previous implementation of 'forward-sexp' is moved into its +own function, to be bound by 'forward-sexp-function'. + *** New function 'treesit-forward-sexp'. Tree-sitter conditionally sets 'forward-sexp-function' for major modes that have defined 'sexp' in 'treesit-thing-settings' to enable diff --git a/lisp/emacs-lisp/lisp.el b/lisp/emacs-lisp/lisp.el index c57b1357f63..bd0b38db7ea 100644 --- a/lisp/emacs-lisp/lisp.el +++ b/lisp/emacs-lisp/lisp.el @@ -45,7 +45,12 @@ This affects `insert-parentheses' and `insert-pair'." :type 'boolean :group 'lisp) -(defvar forward-sexp-function nil +(defun forward-sexp-default-function (&optional arg) + "Default function for `forward-sexp-function'." + (goto-char (or (scan-sexps (point) arg) (buffer-end arg))) + (if (< arg 0) (backward-prefix-chars))) + +(defvar forward-sexp-function #'forward-sexp-default-function ;; FIXME: ;; - for some uses, we may want a "sexp-only" version, which only ;; jumps over a well-formed sexp, rather than some dwimish thing @@ -74,10 +79,9 @@ report errors as appropriate for this kind of usage." "No next sexp" "No previous sexp")))) (or arg (setq arg 1)) - (if forward-sexp-function - (funcall forward-sexp-function arg) - (goto-char (or (scan-sexps (point) arg) (buffer-end arg))) - (if (< arg 0) (backward-prefix-chars))))) + (funcall (or forward-sexp-function + #'forward-sexp-default-function) + arg))) (defun backward-sexp (&optional arg interactive) "Move backward across one balanced expression (sexp). diff --git a/lisp/treesit.el b/lisp/treesit.el index 1443162f79c..2973aba771c 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -2138,14 +2138,24 @@ however, smaller in scope than sentences. This is used by (defun treesit-forward-sexp (&optional arg) "Tree-sitter implementation for `forward-sexp-function'. -ARG is described in the docstring of `forward-sexp-function'. If -there are no further sexps to move across, signal `scan-error' -like `forward-sexp' does. If point is already at top-level, -return nil without moving point." +ARG is described in the docstring of `forward-sexp-function'. + +If point is inside a text environment where tree-sitter is not +supported, go forward a sexp using `forward-sexp-default-function'. +If point is inside code, use tree-sitter functions with the +following behavior. If there are no further sexps to move across, +signal `scan-error' like `forward-sexp' does. If point is already +at top-level, return nil without moving point. + +What constitutes as text and source code sexp is determined +by `text' and `sexp' in `treesit-thing-settings'." (interactive "^p") (let ((arg (or arg 1)) (pred (or treesit-sexp-type-regexp 'sexp))) - (or (if (> arg 0) + (or (when (treesit-node-match-p (treesit-node-at (point)) 'text t) + (funcall #'forward-sexp-default-function arg) + t) + (if (> arg 0) (treesit-end-of-thing pred (abs arg) 'restricted) (treesit-beginning-of-thing pred (abs arg) 'restricted)) ;; If we couldn't move, we should signal an error and report -- 2.39.5