From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Theodor Thornhill via "Bug reports for GNU Emacs, the Swiss army knife of text editors" Newsgroups: gmane.emacs.bugs Subject: bug#60623: 30.0.50; Add forward-sentence with tree sitter support Date: Sat, 07 Jan 2023 12:54:13 +0100 Message-ID: <87o7ratva2.fsf@thornhill.no> Reply-To: Theodor Thornhill Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="2654"; mail-complaints-to="usenet@ciao.gmane.io" Cc: casouri@gmail.com, eliz@gnu.org, monnier@iro.umontreal.ca To: 60623@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Sat Jan 07 12:55:29 2023 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pE7nM-0000WI-Tv for geb-bug-gnu-emacs@m.gmane-mx.org; Sat, 07 Jan 2023 12:55:29 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pE7nD-0008JF-1r; Sat, 07 Jan 2023 06:55:19 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pE7mx-0008I6-Lw for bug-gnu-emacs@gnu.org; Sat, 07 Jan 2023 06:55:05 -0500 Original-Received: from debbugs.gnu.org ([209.51.188.43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1pE7mx-0008Lq-Bv; Sat, 07 Jan 2023 06:55:03 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1pE7mw-0005NK-HH; Sat, 07 Jan 2023 06:55:02 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Theodor Thornhill Original-Sender: "Debbugs-submit" Resent-CC: casouri@gmail.com, eliz@gnu.org, monnier@iro.umontreal.ca, bug-gnu-emacs@gnu.org Resent-Date: Sat, 07 Jan 2023 11:55:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 60623 X-GNU-PR-Package: emacs X-Debbugs-Original-To: bug-gnu-emacs@gnu.org X-Debbugs-Original-Xcc: casouri@gmail.com, eliz@gnu.org, monnier@iro.umontreal.ca Original-Received: via spool by submit@debbugs.gnu.org id=B.167309246720584 (code B ref -1); Sat, 07 Jan 2023 11:55:02 +0000 Original-Received: (at submit) by debbugs.gnu.org; 7 Jan 2023 11:54:27 +0000 Original-Received: from localhost ([127.0.0.1]:56596 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pE7mM-0005Lv-JJ for submit@debbugs.gnu.org; Sat, 07 Jan 2023 06:54:27 -0500 Original-Received: from lists.gnu.org ([209.51.188.17]:56944) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pE7mK-0005Ll-VW for submit@debbugs.gnu.org; Sat, 07 Jan 2023 06:54:25 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pE7mK-0008EI-CP for bug-gnu-emacs@gnu.org; Sat, 07 Jan 2023 06:54:24 -0500 Original-Received: from out-10.mta0.migadu.com ([91.218.175.10]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pE7mH-00085C-Kc for bug-gnu-emacs@gnu.org; Sat, 07 Jan 2023 06:54:24 -0500 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=thornhill.no; s=key1; t=1673092456; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type; bh=EO1YEgA68QXCXqiexzqKBDf2M/KHINsMIZtKn/AqIUM=; b=Z7OnSOwAzPCMPTaHFSVcrsh55n5Y5rhoSGJ+YC99mKuCm9uXPM8p3OSvk3H5KCVxabO7/k z+G8893oLWmfLgGmc90CdUIAd/dSTe1Kydv9e8UlIjqOxuQGDFlIrr0nU1WLb7IN/I80oN CxbGtkkkYszcFHgIhcxCi+fV+aXAGamVxBrpk92P/8KMPqrMHH1D+fXXEjjtogAQ7+RUlM 1rqaZWe1PjYnrBpqElk6hKggxCybmyjzF620X7CCCU8YI22b1+UBLAcoLAhWK5vlrRGu4J kBuXGoDhHODuxOl61U+jSW+7S0N8ewWPonhHaTYk4TOXHArlX2hFmdS4yoCRwg== X-Migadu-Flow: FLOW_OUT Received-SPF: pass client-ip=91.218.175.10; envelope-from=theo@thornhill.no; helo=out-10.mta0.migadu.com X-Spam_score_int: -16 X-Spam_score: -1.7 X-Spam_bar: - X-Spam_report: (-1.7 / 5.0 requ) BAYES_00=-1.9, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:252789 Archived-At: --=-=-= Content-Type: text/plain 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 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Add-forward-sentence-with-tree-sitter-support.patch >From 32eb3c3401f2232c349843e21269ff88e982945e 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 * 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'. + * 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 --=-=-=--