From: Theodor Thornhill via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
To: 60623@debbugs.gnu.org
Cc: casouri@gmail.com, eliz@gnu.org, monnier@iro.umontreal.ca
Subject: bug#60623: 30.0.50; Add forward-sentence with tree sitter support
Date: Sat, 07 Jan 2023 12:54:13 +0100 [thread overview]
Message-ID: <87o7ratva2.fsf@thornhill.no> (raw)
[-- Attachment #1: Type: text/plain, Size: 448 bytes --]
Hi all!
This patch tweaks the forward-sentence function to be usable with
tree-sitter.
It follows the same style as the recent change in transpose-sexps, so I
hope it isn't too controversial.
What exact node types do you consider useful for sentence movement?
I added an example value in java-ts-mode and c-ts-mode, but that is
merely a suggestion. Let's decide on some heuristic to decide the
proper nodes to use.
What do you think?
Theo
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-forward-sentence-with-tree-sitter-support.patch --]
[-- Type: text/x-patch, Size: 8243 bytes --]
From 32eb3c3401f2232c349843e21269ff88e982945e Mon Sep 17 00:00:00 2001
From: Theodor Thornhill <theo@thornhill.no>
Date: Sat, 7 Jan 2023 12:44:14 +0100
Subject: [PATCH] Add forward-sentence with tree sitter support
* 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-function): Move old
implementation to a new defvar.
(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 | 12 ++++++
lisp/progmodes/c-ts-mode.el | 8 ++++
lisp/progmodes/java-ts-mode.el | 6 +++
lisp/textmodes/paragraphs.el | 71 +++++++++++++++++++---------------
lisp/treesit.el | 18 +++++++++
5 files changed, 83 insertions(+), 32 deletions(-)
diff --git a/etc/NEWS b/etc/NEWS
index a2924201267..5b4533b0522 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -57,6 +57,18 @@ 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 sentece 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'.
+
\f
* 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 e76966e7660..3794286162e 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -735,6 +735,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..5bbb77c1cb6 100644
--- a/lisp/textmodes/paragraphs.el
+++ b/lisp/textmodes/paragraphs.el
@@ -441,44 +441,51 @@ end-of-paragraph-text
(if (< (point) (point-max))
(end-of-paragraph-text))))))
-(defun forward-sentence (&optional arg)
+(defvar forward-sentence-function
+ (lambda (&optional arg)
+ (let ((opoint (point))
+ (sentence-end (sentence-end)))
+ (while (< arg 0)
+ (let ((pos (point))
+ par-beg par-text-beg)
+ (save-excursion
+ (start-of-paragraph-text)
+ ;; Start of real text in the paragraph.
+ ;; We move back to here if we don't see a sentence-end.
+ (setq par-text-beg (point))
+ ;; Start of the first line of the paragraph.
+ ;; We use this as the search limit
+ ;; to allow sentence-end to match if it is anchored at
+ ;; BOL and the paragraph starts indented.
+ (beginning-of-line)
+ (setq par-beg (point)))
+ (if (and (re-search-backward sentence-end par-beg t)
+ (or (< (match-end 0) pos)
+ (re-search-backward sentence-end par-beg t)))
+ (goto-char (match-end 0))
+ (goto-char par-text-beg)))
+ (setq arg (1+ arg)))
+ (while (> arg 0)
+ (let ((par-end (save-excursion (end-of-paragraph-text) (point))))
+ (if (re-search-forward sentence-end par-end t)
+ (skip-chars-backward " \t\n")
+ (goto-char par-end)))
+ (setq arg (1- arg)))
+ (let ((npoint (constrain-to-field nil opoint t)))
+ (not (= npoint opoint)))))
"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."
+sentences. Also, every paragraph boundary terminates sentences as well.")
+
+(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))
- (let ((opoint (point))
- (sentence-end (sentence-end)))
- (while (< arg 0)
- (let ((pos (point))
- par-beg par-text-beg)
- (save-excursion
- (start-of-paragraph-text)
- ;; Start of real text in the paragraph.
- ;; We move back to here if we don't see a sentence-end.
- (setq par-text-beg (point))
- ;; Start of the first line of the paragraph.
- ;; We use this as the search limit
- ;; to allow sentence-end to match if it is anchored at
- ;; BOL and the paragraph starts indented.
- (beginning-of-line)
- (setq par-beg (point)))
- (if (and (re-search-backward sentence-end par-beg t)
- (or (< (match-end 0) pos)
- (re-search-backward sentence-end par-beg t)))
- (goto-char (match-end 0))
- (goto-char par-text-beg)))
- (setq arg (1+ arg)))
- (while (> arg 0)
- (let ((par-end (save-excursion (end-of-paragraph-text) (point))))
- (if (re-search-forward sentence-end par-end t)
- (skip-chars-backward " \t\n")
- (goto-char par-end)))
- (setq arg (1- arg)))
- (let ((npoint (constrain-to-field nil opoint t)))
- (not (= npoint opoint)))))
+ (funcall forward-sentence-function arg))
(defun count-sentences (start end)
"Count sentences in current buffer from START to END."
diff --git a/lisp/treesit.el b/lisp/treesit.el
index a7f453a8899..ec4d711bba8 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -1783,6 +1783,22 @@ 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'. Behavior of this
+function depends on `treesit-sentence-type-regexp'."
+ (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 +2272,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
next reply other threads:[~2023-01-07 11:54 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-01-07 11:54 Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors [this message]
2023-01-07 15:41 ` bug#60623: 30.0.50; Add forward-sentence with tree sitter support Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-01-08 13:29 ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-01-08 14:53 ` Eli Zaretskii
2023-01-08 19:35 ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-01-08 19:57 ` Eli Zaretskii
2023-01-08 20:07 ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-01-09 12:37 ` Eli Zaretskii
2023-01-09 13:28 ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-01-10 8:37 ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-01-10 15:07 ` Eli Zaretskii
2023-01-10 19:33 ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-01-10 20:03 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-01-10 20:22 ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-01-10 20:28 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-01-10 21:00 ` Drew Adams
2023-01-11 14:08 ` Eli Zaretskii
2023-01-11 14:41 ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-01-08 17:33 ` Juri Linkov
2023-01-08 8:36 ` Juri Linkov
2023-01-08 9:20 ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-01-08 16:41 ` Drew Adams
2023-01-08 17:04 ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-01-08 17:30 ` Juri Linkov
2023-01-08 19:19 ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-01-09 7:49 ` Juri Linkov
2023-01-09 8:01 ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-01-08 17:42 ` Drew Adams
2023-01-09 6:20 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-01-09 15:57 ` Drew Adams
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87o7ratva2.fsf@thornhill.no \
--to=bug-gnu-emacs@gnu.org \
--cc=60623@debbugs.gnu.org \
--cc=casouri@gmail.com \
--cc=eliz@gnu.org \
--cc=monnier@iro.umontreal.ca \
--cc=theo@thornhill.no \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).