From 62d6f162ba7646783675dc87199ca31691164bf4 Mon Sep 17 00:00:00 2001 From: Theodor Thornhill Date: Sat, 7 Jan 2023 12:44:14 +0100 Subject: [PATCH] Add forward-sentence with tree sitter support (bug#60623) * etc/NEWS: Mention the new changes. * lisp/progmodes/c-ts-mode.el (c-ts-base-mode): Set the variable. * lisp/progmodes/java-ts-mode.el (java-ts-mode): Set the variable. * lisp/textmodes/paragraphs.el (forward-sentence-default-function): Move old implementation to its own function. (forward-sentence-function): New defvar defaulting to old behavior. (forward-sentence): Use the variable in this function unconditionally. * lisp/treesit.el (treesit-sentence-type-regexp): New defvar. (treesit-forward-sentence): New defun. (treesit-major-mode-setup): Conditionally set forward-sentence-function. --- etc/NEWS | 13 +++++++++++++ lisp/progmodes/c-ts-mode.el | 8 ++++++++ lisp/progmodes/java-ts-mode.el | 6 ++++++ lisp/textmodes/paragraphs.el | 16 +++++++++++++--- lisp/treesit.el | 28 ++++++++++++++++++++++++++++ 5 files changed, 68 insertions(+), 3 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 690e9c3faa9..98f5d71cc90 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -57,6 +57,19 @@ treesit.el now unconditionally sets 'transpose-sexps-function' for all Tree-sitter modes. This functionality utilizes the new 'transpose-sexps-function'. +** New defvar-local forward-sentence-function. +The previous implementation of 'forward-sentence' is moved into this +variable, which can be set to customize the sentence movement +behavior. + +** New defvar-local 'treesit-sentence-type-regexp. +Similarly to 'treesit-defun-type-regexp', this variable is used to +navigate sentences in Tree-sitter enabled modes. + +** New function 'treesit-forward-sentence'. +treesit.el now conditionally sets 'forward-sentence-function' for all +Tree-sitter modes that sets 'treesit-sentence-type-regexp'. + * Changes in Specialized Modes and Packages in Emacs 30.1 --- diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index a22f1f3c44f..dec866f762f 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -736,6 +736,14 @@ c-ts-base-mode :syntax-table c-ts-mode--syntax-table ;; Navigation. + (setq-local treesit-sentence-type-regexp + (regexp-opt '("statement" + "expression" + "definition" + "specifier" + "declaration" + "comment" + "preproc"))) (setq-local treesit-defun-type-regexp (cons (regexp-opt '("function_definition" "type_definition" diff --git a/lisp/progmodes/java-ts-mode.el b/lisp/progmodes/java-ts-mode.el index 87a4e2b90f8..0e3381e219a 100644 --- a/lisp/progmodes/java-ts-mode.el +++ b/lisp/progmodes/java-ts-mode.el @@ -296,6 +296,12 @@ java-ts-mode (append "{}():;," electric-indent-chars)) ;; Navigation. + (setq-local treesit-sentence-type-regexp + (regexp-opt '("statement" + "expression" + "parameters" + "list" + "comment"))) (setq-local treesit-defun-type-regexp (regexp-opt '("method_declaration" "class_declaration" diff --git a/lisp/textmodes/paragraphs.el b/lisp/textmodes/paragraphs.el index 73abb155aaa..4580be3450d 100644 --- a/lisp/textmodes/paragraphs.el +++ b/lisp/textmodes/paragraphs.el @@ -441,14 +441,12 @@ end-of-paragraph-text (if (< (point) (point-max)) (end-of-paragraph-text)))))) -(defun forward-sentence (&optional arg) +(defun forward-sentence-default-function (&optional arg) "Move forward to next end of sentence. With argument, repeat. When ARG is negative, move backward repeatedly to start of sentence. The variable `sentence-end' is a regular expression that matches ends of sentences. Also, every paragraph boundary terminates sentences as well." - (interactive "^p") - (or arg (setq arg 1)) (let ((opoint (point)) (sentence-end (sentence-end))) (while (< arg 0) @@ -480,6 +478,18 @@ forward-sentence (let ((npoint (constrain-to-field nil opoint t))) (not (= npoint opoint))))) +(defvar forward-sentence-function #'forward-sentence-default-function + "Function to be used to calculate sentence movements. +See `forward-sentence-default-function' for behavior description.") + +(defun forward-sentence (&optional arg) + "Move forward to next end of sentence. With argument, repeat. +When ARG is negative, move backward repeatedly to start of sentence. +Delegates its work to `forward-sentence-function'." + (interactive "^p") + (or arg (setq arg 1)) + (funcall forward-sentence-function arg)) + (defun count-sentences (start end) "Count sentences in current buffer from START to END." (let ((sentences 0) diff --git a/lisp/treesit.el b/lisp/treesit.el index a7f453a8899..0681e758b37 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -1783,6 +1783,32 @@ treesit-end-of-defun (when treesit-defun-skipper (funcall treesit-defun-skipper)))) +(defvar-local treesit-sentence-type-regexp "" + "A regexp that matches the node type of sentence nodes. + +A sentence node is a node that is bigger than a sexp, and +delimits larger statements in the source code. It is, however, +smaller in scope than defuns. This is used by +`treesit-forward-sentence' and friends.") + +(defun treesit-forward-sentence (&optional arg) + "Tree-sitter `forward-sentence-function' function. + +ARG is the same as in `forward-sentence-function'. + +If inside comment or other nodes described in +`treesit-sentence-type-regexp', use +`forward-sentence-default-function', else move across nodes as +described by `treesit-sentence-type-regexp'." + + (if (string-match-p + treesit-text-type-regexp + (treesit-node-type (treesit-node-at (point)))) + (funcall #'forward-sentence-default-function arg) + (funcall + (if (> arg 0) #'treesit-end-of-thing #'treesit-beginning-of-thing) + treesit-sentence-type-regexp (abs arg)))) + (defvar-local treesit-text-type-regexp "\\`comment\\'" "A regexp that matches the node type of textual nodes. @@ -2256,6 +2282,8 @@ treesit-major-mode-setup #'treesit-add-log-current-defun)) (setq-local transpose-sexps-function #'treesit-transpose-sexps) + (when treesit-sentence-type-regexp + (setq-local forward-sentence-function #'treesit-forward-sentence)) ;; Imenu. (when treesit-simple-imenu-settings -- 2.34.1