GNU bug report logs - #76398
treesit-aggregated-outline-predicate

Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.

Package: emacs; Reported by: Juri Linkov <juri@HIDDEN>; dated Tue, 18 Feb 2025 17:36:01 UTC; Maintainer for emacs is bug-gnu-emacs@HIDDEN.

Message received at 76398 <at> debbugs.gnu.org:


Received: (at 76398) by debbugs.gnu.org; 19 Feb 2025 07:47:07 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Feb 19 02:47:07 2025
Received: from localhost ([127.0.0.1]:41309 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tkenS-00007B-W9
	for submit <at> debbugs.gnu.org; Wed, 19 Feb 2025 02:47:07 -0500
Received: from relay7-d.mail.gandi.net ([2001:4b98:dc4:8::227]:52679)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <juri@HIDDEN>) id 1tkenP-00005n-Tz
 for 76398 <at> debbugs.gnu.org; Wed, 19 Feb 2025 02:47:04 -0500
Received: by mail.gandi.net (Postfix) with ESMTPSA id 293EA441F0;
 Wed, 19 Feb 2025 07:46:53 +0000 (UTC)
From: Juri Linkov <juri@HIDDEN>
To: 76398 <at> debbugs.gnu.org
Subject: Re: bug#76398: treesit-aggregated-outline-predicate
In-Reply-To: <87tt8rrwnf.fsf@HIDDEN>
Organization: LINKOV.NET
References: <87tt8rrwnf.fsf@HIDDEN>
Date: Wed, 19 Feb 2025 09:46:23 +0200
Message-ID: <87frkas7g0.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/31.0.50 (x86_64-pc-linux-gnu)
MIME-Version: 1.0
Content-Type: text/plain
X-GND-State: clean
X-GND-Score: 0
X-GND-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdeifeeikecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfitefpfffkpdcuggftfghnshhusghstghrihgsvgenuceurghilhhouhhtmecufedtudenucenucfjughrpefhvfevufgjohhffffkfgggtgesthdtredttdertdenucfhrhhomheplfhurhhiucfnihhnkhhovhcuoehjuhhriheslhhinhhkohhvrdhnvghtqeenucggtffrrghtthgvrhhnpeffgeetfeevlefhleejfeeuheeiudeitdffhfdutdekfeffgffhveehteegueekheenucfkphepledurdduvdelrdelkedrheenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepihhnvghtpeeluddruddvledrleekrdehpdhhvghlohepmhgrihhlrdhgrghnughirdhnvghtpdhmrghilhhfrhhomhepjhhurhhisehlihhnkhhovhdrnhgvthdpnhgspghrtghpthhtohepfedprhgtphhtthhopehvrdhpuhhpihhllhhosehgmhgrihhlrdgtohhmpdhrtghpthhtoheptggrshhouhhrihesghhmrghilhdrtghomhdprhgtphhtthhopeejieefleekseguvggssghughhsrdhgnhhurdhorhhg
X-GND-Sasl: juri@HIDDEN
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 76398
Cc: casouri@HIDDEN, v.pupillo@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

> So this patch helps 'treesit-outline-search' to get out of the local parser
> to the primary parser to continue search for the next outline predicate.
>
> 'treesit-outline-level' should do the same, but currently I can't find
> a suitable function to break out of embedded confinement
> and get the host node that contains the guest ranges.
> I mean that e.g. (treesit-parser-root-node (treesit-node-parser node))
> can get the root node of the local parser, but how to get its parent node
> in the primary parser?  It's understandable that treesit-node-parent
> doesn't go out of its parser.  But maybe there is another function?
> If such function doesn't exist, this is fine, then could find that
> node manually by calculating from treesit-parser-included-ranges.

Maybe we need two new primitives:

  (treesit-next-parser-boundary POS)
  (treesit-prev-parser-boundary POS)

and

  (treesit-upper-parser-node POS)




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#76398; Package emacs. Full text available.

Message received at submit <at> debbugs.gnu.org:


Received: (at submit) by debbugs.gnu.org; 18 Feb 2025 17:35:13 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Feb 18 12:35:13 2025
Received: from localhost ([127.0.0.1]:60578 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tkRV2-0002Yk-FR
	for submit <at> debbugs.gnu.org; Tue, 18 Feb 2025 12:35:13 -0500
Received: from lists.gnu.org ([2001:470:142::17]:44942)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <juri@HIDDEN>) id 1tkRV0-0002T0-PA
 for submit <at> debbugs.gnu.org; Tue, 18 Feb 2025 12:35:11 -0500
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 <juri@HIDDEN>) id 1tkRUu-0001CB-QE
 for bug-gnu-emacs@HIDDEN; Tue, 18 Feb 2025 12:35:05 -0500
Received: from relay2-d.mail.gandi.net ([217.70.183.194])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <juri@HIDDEN>) id 1tkRUr-0001zy-QF
 for bug-gnu-emacs@HIDDEN; Tue, 18 Feb 2025 12:35:04 -0500
Received: by mail.gandi.net (Postfix) with ESMTPSA id C8BAB4418D
 for <bug-gnu-emacs@HIDDEN>; Tue, 18 Feb 2025 17:34:56 +0000 (UTC)
From: Juri Linkov <juri@HIDDEN>
To: bug-gnu-emacs@HIDDEN
Subject: treesit-aggregated-outline-predicate
Organization: LINKOV.NET
X-Debbugs-Cc: casouri@HIDDEN, v.pupillo@HIDDEN
Date: Tue, 18 Feb 2025 19:27:17 +0200
Message-ID: <87tt8rrwnf.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/31.0.50 (x86_64-pc-linux-gnu)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-GND-State: clean
X-GND-Score: 0
X-GND-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdeiudelvdcutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfitefpfffkpdcuggftfghnshhusghstghrihgsvgenuceurghilhhouhhtmecufedtudenucenucfjughrpefhvffuohffkfgfgggtsehmtderredtredtnecuhfhrohhmpefluhhrihcunfhinhhkohhvuceojhhurhhisehlihhnkhhovhdrnhgvtheqnecuggftrfgrthhtvghrnhepveetfeeiuefhtdeguedukefgjeejkedvvdevhfdvfedtieefkeevleeikefffedunecukfhppeeluddruddvledrleekrdehnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehinhgvthepledurdduvdelrdelkedrhedphhgvlhhopehmrghilhdrghgrnhguihdrnhgvthdpmhgrihhlfhhrohhmpehjuhhriheslhhinhhkohhvrdhnvghtpdhnsggprhgtphhtthhopedupdhrtghpthhtohepsghughdqghhnuhdqvghmrggtshesghhnuhdrohhrgh
X-GND-Sasl: juri@HIDDEN
Received-SPF: pass client-ip=217.70.183.194; envelope-from=juri@HIDDEN;
 helo=relay2-d.mail.gandi.net
X-Spam_score_int: -24
X-Spam_score: -2.5
X-Spam_bar: --
X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_LOW=-0.7,
 RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001,
 RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001,
 SPF_HELO_PASS=-0.001, SPF_PASS=-0.001,
 TRACKER_ID=0.1 autolearn=ham autolearn_force=no
X-Spam_action: no action
X-Spam-Score: 0.8 (/)
X-Debbugs-Envelope-To: submit
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -0.2 (/)

--=-=-=
Content-Type: text/plain

As discussed in bug#74610, in multi-language modes
treesit-outline-predicate ends abruptly after the first embedded range
since it can't find more matches in its range, it can't go out back
to the primary parser.

So this patch helps 'treesit-outline-search' to get out of the local parser
to the primary parser to continue search for the next outline predicate.

'treesit-outline-level' should do the same, but currently I can't find
a suitable function to break out of embedded confinement
and get the host node that contains the guest ranges.
I mean that e.g. (treesit-parser-root-node (treesit-node-parser node))
can get the root node of the local parser, but how to get its parent node
in the primary parser?  It's understandable that treesit-node-parent
doesn't go out of its parser.  But maybe there is another function?
If such function doesn't exist, this is fine, then could find that
node manually by calculating from treesit-parser-included-ranges.

--=-=-=
Content-Type: text/x-diff
Content-Disposition: inline;
 filename=treesit-aggregated-outline-predicate.patch

diff --git a/lisp/textmodes/mhtml-ts-mode.el b/lisp/textmodes/mhtml-ts-mode.el
index 83f8879f427..7a481599310 100644
--- a/lisp/textmodes/mhtml-ts-mode.el
+++ b/lisp/textmodes/mhtml-ts-mode.el
@@ -580,7 +580,10 @@ mhtml-ts-mode
     (setq-local treesit-aggregated-simple-imenu-settings
                 mhtml-ts-mode--treesit-aggregated-simple-imenu-settings)
 
-    ;; (setq-local treesit-outline-predicate nil)
+    (setq-local treesit-aggregated-outline-predicate
+                `((html . ,#'html-ts-mode--outline-predicate)
+                  (javascript . "\\`function_declaration\\'")
+                  (css . "\\`rule_set\\'")))
 
     (treesit-major-mode-setup)
 
diff --git a/lisp/treesit.el b/lisp/treesit.el
index 30efd4d4599..ab9bfc33d3d 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -3601,6 +3601,16 @@ treesit-outline-predicate
 is constructed from the value of `treesit-simple-imenu-settings'
 when a major mode sets it.")
 
+(defvar-local treesit-aggregated-outline-predicate nil
+  "Settings that configure `treesit-outline-search' for multi-language modes.
+
+The value should be an alist of (LANG . SETTINGS), where LANG is a
+language symbol, and SETTINGS has the same form as
+`treesit-outline-predicate'.
+
+When both this variable and `treesit-outline-predicate' are non-nil,
+this variable takes priority.")
+
 (defun treesit-outline-predicate--from-imenu (node)
   ;; Return an outline searching predicate created from Imenu.
   ;; Return the value suitable to set `treesit-outline-predicate'.
@@ -3618,7 +3628,10 @@ treesit-outline-predicate--from-imenu
 
 (defun treesit-outline--at-point ()
   "Return the outline heading node at the current line."
-  (let* ((pred treesit-outline-predicate)
+  (let* ((pred (if treesit-aggregated-outline-predicate
+                   (alist-get (treesit-language-at (point))
+                              treesit-aggregated-outline-predicate)
+                 treesit-outline-predicate))
          (bol (pos-bol))
          (eol (pos-eol))
          (current (treesit-thing-at (point) pred))
@@ -3649,9 +3662,35 @@ treesit-outline-search
               (if (eq (point) (pos-bol))
                   (if (bobp) (point) (1- (point)))
                 (pos-eol))))
+           (pred (if treesit-aggregated-outline-predicate
+                     (alist-get (treesit-language-at pos)
+                                treesit-aggregated-outline-predicate)
+                   treesit-outline-predicate))
            (found (or bob-pos
-                      (treesit-navigate-thing pos (if backward -1 1) 'beg
-                                              treesit-outline-predicate))))
+                      (treesit-navigate-thing pos (if backward -1 1) 'beg pred))))
+
+      ;; Handle multi-language modes
+      (when-let* ((ranges (mapcar #'treesit-parser-included-ranges
+                                  (treesit-parser-list)))
+                  (ranges (delq nil (delete '((1 . 1)) ranges))))
+        (if found
+            nil
+          ;; Possibly was inside the local range, and when can't find
+          ;; more matches inside the local range then need to go out
+          (when-let* ((bounds (seq-filter
+                               (lambda (p) (if backward (< p pos) (> p pos)))
+                               (flatten-list
+                                (mapcar (lambda (rr)
+                                          (mapcar (if backward #'car #'cdr) rr))
+                                        ranges))))
+                      (closest (when bounds (if backward (seq-max bounds) (seq-min bounds)))))
+            (setq found (treesit-navigate-thing
+                         closest (if backward -1 1) 'beg
+                         (if treesit-aggregated-outline-predicate
+                             (alist-get (treesit-language-at closest)
+                                        treesit-aggregated-outline-predicate)
+                           treesit-outline-predicate))))))
+
       (if found
           (if (or (not bound) (if backward (>= found bound) (<= found bound)))
               (progn
@@ -3667,10 +3706,25 @@ treesit-outline-search
 (defun treesit-outline-level ()
   "Return the depth of the current outline heading."
   (let* ((node (treesit-outline--at-point))
-         (level 1))
-    (while (setq node (treesit-parent-until node treesit-outline-predicate))
+         (level 1)
+         (parser (when treesit-aggregated-outline-predicate
+                   (treesit-node-parser node)))
+         (pred (if treesit-aggregated-outline-predicate
+                   (alist-get (treesit-language-at (point))
+                              treesit-aggregated-outline-predicate)
+                 treesit-outline-predicate)))
+    (while (setq node (treesit-parent-until node pred))
       (setq level (1+ level)))
-    (if (zerop level) 1 level)))
+    (when-let* ((_ parser)
+                (host-lang (treesit-parser-language treesit-primary-parser))
+                (_ (not (eq (treesit-language-at (point)) host-lang)))
+                (host-pred (alist-get host-lang treesit-aggregated-outline-predicate)))
+      ;; Now need to break out of embedded confinement
+      ;; and get the host node that contains the guest ranges
+      (setq node (treesit-parser-root-node parser))
+      (while (setq node (treesit-parent-until node host-pred))
+        (setq level (1+ level))))
+    level))
 
 ;;; Hideshow mode
 
@@ -3955,11 +4009,14 @@ treesit-major-mode-setup
                 #'treesit-simple-imenu))
 
   ;; Outline minor mode.
-  (when (and (or treesit-outline-predicate treesit-simple-imenu-settings)
+  (when (and (or treesit-outline-predicate
+                 treesit-aggregated-outline-predicate
+                 treesit-simple-imenu-settings)
              (not (seq-some #'local-variable-p
                             '(outline-search-function
                               outline-regexp outline-level))))
-    (unless treesit-outline-predicate
+    (unless (or treesit-outline-predicate
+                treesit-aggregated-outline-predicate)
       (setq treesit-outline-predicate
             #'treesit-outline-predicate--from-imenu))
     (setq-local outline-search-function #'treesit-outline-search

--=-=-=--




Acknowledgement sent to Juri Linkov <juri@HIDDEN>:
New bug report received and forwarded. Copy sent to casouri@HIDDEN, v.pupillo@HIDDEN, bug-gnu-emacs@HIDDEN. Full text available.
Report forwarded to casouri@HIDDEN, v.pupillo@HIDDEN, bug-gnu-emacs@HIDDEN:
bug#76398; Package emacs. Full text available.
Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.
Last modified: Wed, 19 Feb 2025 08:00:03 UTC

GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997 nCipher Corporation Ltd, 1994-97 Ian Jackson.