From: Theodor Thornhill Date: Tue, 17 Jan 2023 20:18:29 +0000 (+0100) Subject: Add treesit-forward-sexp (bug#60894) X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=207901457c018d94b1ce9e13a897d8241b1f3af2;p=emacs.git Add treesit-forward-sexp (bug#60894) * lisp/progmodes/java-ts-mode.el (java-ts-mode): Use treesit-sexp-type-regexp. * lisp/treesit.el (treesit-sexp-type-regexp): New defvar. (treesit-forward-sexp): New command. (treesit-major-mode-setup): Conditionally set forward-sexp-function. * lisp/progmodes/ruby-ts-mode.el: Add some types to ruby-ts-mode. * doc/lispref/positions.texi (List Motion): Mention the change in the manual. * etc/NEWS: Mention the change. --- diff --git a/doc/lispref/positions.texi b/doc/lispref/positions.texi index 8d95ecee7ab..838877b6282 100644 --- a/doc/lispref/positions.texi +++ b/doc/lispref/positions.texi @@ -875,6 +875,23 @@ by using @code{forward-sentence} and @code{backward-sentence}(@pxref{Moving by Sentences,,, emacs, The extensible self-documenting text editor}). +@defvar treesit-sexp-type-regexp +The value of this variable is a regexp matching the node type of sexp +nodes. (For ``node'' and ``node type'', @pxref{Parsing Program +Source}.) +@end defvar + +@findex treesit-forward-sexp +@findex forward-sexp@r{, and tree-sitter} +@findex backward-sexp@r{, and tree-sitter} +If Emacs is compiled with tree-sitter, it can use the tree-sitter +parser information to move across syntax constructs. Since what +exactly is considered a sexp varies between languages, a major mode +should set @code{treesit-sexp-type-regexp} 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}). + @node Skipping Characters @subsection Skipping Characters @cindex skipping characters diff --git a/etc/NEWS b/etc/NEWS index cde6783349f..fc8a3ac66a0 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -84,6 +84,15 @@ define "sentences" in Tree-sitter enabled modes. All tree-sitter modes that define 'treesit-sentence-type-regexp' now set 'forward-sentence-function' to call 'treesit-forward-sentence'. +*** New defvar-local 'treesit-sexp-type-regexp'. +Similarly to 'treesit-defun-type-regexp', this variable is used to +define "sexps" in Tree-sitter enabled modes. + +*** New function 'treesit-forward-sexp'. +treesit.el conditionally sets 'forward-sexp-function` for major modes +that have defined 'treesit-sexp-type-regexp' to enable sexp-related +motion commands. + * Changes in Specialized Modes and Packages in Emacs 30.1 --- diff --git a/lisp/progmodes/java-ts-mode.el b/lisp/progmodes/java-ts-mode.el index 83c437d307b..03093e09805 100644 --- a/lisp/progmodes/java-ts-mode.el +++ b/lisp/progmodes/java-ts-mode.el @@ -328,6 +328,21 @@ Return nil if there is no name or if NODE is not a defun node." "package_declaration" "import_declaration"))) + (setq-local treesit-sexp-type-regexp + (regexp-opt '("annotation" + "parenthesized_expression" + "argument_list" + "identifier" + "modifiers" + "block" + "body" + "literal" + "access" + "reference" + "_type" + "true" + "false"))) + ;; Font-lock. (setq-local treesit-font-lock-settings java-ts-mode--font-lock-settings) (setq-local treesit-font-lock-feature-list diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el index f075824591d..66b50a4b540 100644 --- a/lisp/progmodes/ruby-ts-mode.el +++ b/lisp/progmodes/ruby-ts-mode.el @@ -1008,6 +1008,20 @@ leading double colon is not added." ;; Navigation. (setq-local treesit-defun-type-regexp ruby-ts--method-regex) + (setq-local treesit-sexp-type-regexp + (regexp-opt '("class" + "module" + "method" + "argument_list" + "array" + "hash" + "parenthesized_statements" + "if" + "case" + "block" + "do_block" + "begin"))) + ;; AFAIK, Ruby can not nest methods (setq-local treesit-defun-prefer-top-level nil) diff --git a/lisp/treesit.el b/lisp/treesit.el index e8571d43db3..7aeff3b8b49 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -1636,6 +1636,21 @@ BACKWARD and ALL are the same as in `treesit-search-forward'." (goto-char current-pos))) node)) +(defvar-local treesit-sexp-type-regexp nil + "A regexp that matches the node type of sexp nodes. + +A sexp node is a node that is bigger than punctuation, and +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-sexp (&optional arg) + (interactive "^p") + (or arg (setq arg 1)) + (funcall + (if (> arg 0) #'treesit-end-of-thing #'treesit-beginning-of-thing) + treesit-sexp-type-regexp (abs arg))) + (defun treesit-transpose-sexps (&optional arg) "Tree-sitter `transpose-sexps' function. Arg is the same as in `transpose-sexps'. @@ -2301,6 +2316,8 @@ before calling this function." (setq-local add-log-current-defun-function #'treesit-add-log-current-defun)) + (when treesit-sexp-type-regexp + (setq-local forward-sexp-function #'treesit-forward-sexp)) (setq-local transpose-sexps-function #'treesit-transpose-sexps) (when treesit-sentence-type-regexp (setq-local forward-sentence-function #'treesit-forward-sentence))