From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Juri Linkov Newsgroups: gmane.emacs.bugs Subject: bug#68824: treesitter support for outline-minor-mode Date: Sun, 04 Feb 2024 19:15:20 +0200 Organization: LINKOV.NET Message-ID: <86r0hsxiaf.fsf@mail.linkov.net> References: <86le8667u7.fsf@mail.linkov.net> <865xza39vp.fsf@gnu.org> <86y1c6q7oh.fsf@mail.linkov.net> <868r44ryzb.fsf@mail.linkov.net> <3D859057-3DE9-470A-80A4-E0F734A0A622@gmail.com> 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="20004"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/30.0.50 (x86_64-pc-linux-gnu) Cc: 68824@debbugs.gnu.org To: Yuan Fu Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Sun Feb 04 18:19:15 2024 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 1rWg9B-00053R-OO for geb-bug-gnu-emacs@m.gmane-mx.org; Sun, 04 Feb 2024 18:19:13 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rWg8q-0000Bw-T0; Sun, 04 Feb 2024 12:18:52 -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 1rWg8q-0000Bm-93 for bug-gnu-emacs@gnu.org; Sun, 04 Feb 2024 12:18:52 -0500 Original-Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rWg8o-0003xA-ER for bug-gnu-emacs@gnu.org; Sun, 04 Feb 2024 12:18:51 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1rWg90-0000f5-EM for bug-gnu-emacs@gnu.org; Sun, 04 Feb 2024 12:19:02 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Juri Linkov Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 04 Feb 2024 17:19:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 68824 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch Original-Received: via spool by 68824-submit@debbugs.gnu.org id=B68824.17070670912480 (code B ref 68824); Sun, 04 Feb 2024 17:19:02 +0000 Original-Received: (at 68824) by debbugs.gnu.org; 4 Feb 2024 17:18:11 +0000 Original-Received: from localhost ([127.0.0.1]:49979 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rWg8B-0000dv-7n for submit@debbugs.gnu.org; Sun, 04 Feb 2024 12:18:11 -0500 Original-Received: from relay9-d.mail.gandi.net ([2001:4b98:dc4:8::229]:40373) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rWg87-0000dO-HH for 68824@debbugs.gnu.org; Sun, 04 Feb 2024 12:18:09 -0500 Original-Received: by mail.gandi.net (Postfix) with ESMTPSA id 685FEFF804; Sun, 4 Feb 2024 17:17:46 +0000 (UTC) In-Reply-To: <3D859057-3DE9-470A-80A4-E0F734A0A622@gmail.com> (Yuan Fu's message of "Thu, 1 Feb 2024 16:34:47 -0800") X-GND-Sasl: juri@linkov.net 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:279421 Archived-At: --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit > Instead of using treesit-search-forward, can you use > treesit-beginning-of-thing or treesit--navigate-thing to do what you want? > They handle the “child before parent” problem for you, and handles some > other edge cases. Thanks, I tried and it works. Probably treesit--navigate-thing is not internal anymore. Also the patch below uses treesit--thing-at that doesn't look internal either. So maybe two dashes could be removed from names. Also a remaining question: why treesit-parent-until simply calls ‘(funcall pred node)’ instead of supporting the standard format that includes a regexp by using treesit-node-match-p? This causes such an inconvenience that for treesit-outline-level that uses treesit-parent-until there is a need to wrap a regexp in a lambda such as for html-ts-mode below. --=-=-= Content-Type: text/x-diff Content-Disposition: inline; filename=treesit-outline-search.patch diff --git a/lisp/treesit.el b/lisp/treesit.el index fab2ddd88e6..921e61b2160 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -2854,6 +2854,53 @@ treesit-simple-imenu index)))) treesit-simple-imenu-settings))) +;;; Outline minor mode + +(defvar-local treesit-outline-predicate nil + "Predicate used to find outline headings in the syntax tree. +Intended to be set by a major mode. When nil, the predicate +is constructed from the value of `treesit-simple-imenu-settings' +when a major mode sets it.") + +(defun treesit-outline-search (&optional bound move backward looking-at) + "Search for the next outline heading in the syntax tree. +See the descriptions of arguments in `outline-search-function'." + (if looking-at + (when-let* ((node (or (treesit--thing-at (pos-eol) treesit-outline-predicate) + (treesit--thing-at (pos-bol) treesit-outline-predicate))) + (start (treesit-node-start node))) + (eq (pos-bol) (save-excursion (goto-char start) (pos-bol)))) + + (let* ((pos + ;; When function wants to find the current outline, point + ;; is at the beginning of the current line. When it wants + ;; to find the next outline, point is at the second column. + (if (eq (point) (pos-bol)) + (if (bobp) (point) (1- (point))) + (pos-eol))) + (found (treesit--navigate-thing pos (if backward -1 1) 'beg + treesit-outline-predicate))) + (if found + (if (or (not bound) (if backward (>= found bound) (<= found bound))) + (progn + (goto-char found) + (goto-char (pos-bol)) + (set-match-data (list (point) (pos-eol))) + t) + (when move (goto-char bound)) + nil) + (when move (goto-char (or bound (if backward (point-min) (point-max))))) + nil)))) + +(defun treesit-outline-level () + "Return the depth of the current outline heading." + (let* ((node (treesit-node-at (point))) + (level (if (treesit-node-match-p node treesit-outline-predicate t) + 1 0))) + (while (setq node (treesit-parent-until node treesit-outline-predicate)) + (setq level (1+ level))) + (if (zerop level) 1 level))) + ;;; Activating tree-sitter (defun treesit-ready-p (language &optional quiet) @@ -2984,6 +3031,23 @@ treesit-major-mode-setup (setq-local imenu-create-index-function #'treesit-simple-imenu)) + ;; Outline minor mode. + (when (and (or treesit-outline-predicate treesit-simple-imenu-settings) + (not (seq-some #'local-variable-p + '(outline-search-function + outline-regexp outline-level)))) + (unless treesit-outline-predicate + (setq treesit-outline-predicate + (lambda (node) + (seq-some + (lambda (setting) + (and (string-match-p (nth 1 setting) (treesit-node-type node)) + (or (null (nth 2 setting)) + (funcall (nth 2 setting) node)))) + treesit-simple-imenu-settings)))) + (setq-local outline-search-function #'treesit-outline-search + outline-level #'treesit-outline-level)) + ;; Remove existing local parsers. (dolist (ov (overlays-in (point-min) (point-max))) (when-let ((parser (overlay-get ov 'treesit-parser))) diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index e5835bdb62d..ac0682a2dc7 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -1259,6 +1259,15 @@ c-ts-base-mode eos) c-ts-mode--defun-for-class-in-imenu-p nil)))) + (setq-local treesit-outline-predicate + (lambda (node) + (and (treesit-node-match-p + node "\\`function_declarator\\'" t) + (when-let ((parent (treesit-node-parent node))) + (treesit-node-match-p + parent + "\\`function_definition\\'" t))))) + (setq-local treesit-font-lock-feature-list c-ts-mode--feature-list)) diff --git a/lisp/textmodes/html-ts-mode.el b/lisp/textmodes/html-ts-mode.el index 301f3e8791c..71fed15f2fc 100644 --- a/lisp/textmodes/html-ts-mode.el +++ b/lisp/textmodes/html-ts-mode.el @@ -121,6 +121,16 @@ html-ts-mode ;; Imenu. (setq-local treesit-simple-imenu-settings '(("Element" "\\`tag_name\\'" nil nil))) + + ;; Outline minor mode. + (setq-local treesit-outline-predicate + (lambda (node) (treesit-node-match-p + node "\\`element\\'" t))) + ;; Restore default value for `treesit-outline-search'. + (kill-local-variable 'outline-regexp) + (kill-local-variable 'outline-heading-end-regexp) + (kill-local-variable 'outline-level) + (treesit-major-mode-setup)) (if (treesit-ready-p 'html) --=-=-=--