GNU bug report logs - #75609
Hideshow support for treesitter

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; Severity: wishlist; Reported by: Juri Linkov <juri@HIDDEN>; Keywords: patch; dated Thu, 16 Jan 2025 17:50:01 UTC; Maintainer for emacs is bug-gnu-emacs@HIDDEN.
Severity set to 'wishlist' from 'normal' Request was from Stefan Kangas <stefankangas@HIDDEN> to control <at> debbugs.gnu.org. Full text available.

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


Received: (at 75609) by debbugs.gnu.org; 18 Jan 2025 17:44:28 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Jan 18 12:44:28 2025
Received: from localhost ([127.0.0.1]:43638 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tZCs0-0003iA-Cp
	for submit <at> debbugs.gnu.org; Sat, 18 Jan 2025 12:44:28 -0500
Received: from relay9-d.mail.gandi.net ([2001:4b98:dc4:8::229]:55777)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <juri@HIDDEN>) id 1tZCrw-0003hs-4h
 for 75609 <at> debbugs.gnu.org; Sat, 18 Jan 2025 12:44:25 -0500
Received: by mail.gandi.net (Postfix) with ESMTPSA id 09ECDFF803;
 Sat, 18 Jan 2025 17:44:15 +0000 (UTC)
From: Juri Linkov <juri@HIDDEN>
To: Yuan Fu <casouri@HIDDEN>
Subject: Re: bug#75609: Hideshow support for treesitter
In-Reply-To: <2999991B-3A95-4CC7-92BE-9A6B8F18BADE@HIDDEN> (Yuan Fu's
 message of "Fri, 17 Jan 2025 23:40:16 -0800")
Organization: LINKOV.NET
References: <87tt9yu00k.fsf@HIDDEN>
 <2999991B-3A95-4CC7-92BE-9A6B8F18BADE@HIDDEN>
Date: Sat, 18 Jan 2025 19:43:19 +0200
Message-ID: <87ikqc3tmw.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; charset=utf-8
Content-Transfer-Encoding: 8bit
X-GND-Sasl: juri@HIDDEN
X-Spam-Score: -0.7 (/)
X-Debbugs-Envelope-To: 75609
Cc: 75609 <at> debbugs.gnu.org
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.7 (-)

>> +(defun treesit-hs-inside-comment-p ()
>> +  (let ((thing (or (treesit-thing-at (point) "comment")
>> +                   (unless (bobp)
>> +                     (treesit-thing-at (1- (point)) "comment")))))
>> +    (when thing
>> +      (list (treesit-node-start thing) (treesit-node-end thing)))))
>> +
>
> FYI some grammar calls comments line_comment and block_comment.
> Maybe use the comment thing first, and then match “comment” with the node type?

We need to introduce the new thing named "comment".
It's necessary to add treesit support for 'forward-comment'
that is used in many packages including 'hideshow'.

This means adding the variable 'forward-comment-function'
with the default value 'forward-comment-default-function'.
Then will override it with 'treesit-forward-comment' that
uses the comment thing.

>> @@ -644,6 +648,9 @@ hs-inside-comment-p
>> beginning.  If we are inside of a comment but this condition is not met,
>> we return a list having a nil as its car and the end of comment position
>> as cdr."
>> +  (cond ((functionp hs-inside-comment-p-func)
>> +         (funcall hs-inside-comment-p-func))
>> +  (t
>
> Did you do this indentation on purpose to make a easier-to-read diff?

Indeed, this was to make it easier-to-read.  And in the next patch
I will just rename the default function to 'hs-inside-comment-p--default'.




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

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


Received: (at 75609) by debbugs.gnu.org; 18 Jan 2025 07:40:41 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Jan 18 02:40:41 2025
Received: from localhost ([127.0.0.1]:39794 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tZ3Rh-0004is-4r
	for submit <at> debbugs.gnu.org; Sat, 18 Jan 2025 02:40:41 -0500
Received: from mail-pl1-x62c.google.com ([2607:f8b0:4864:20::62c]:50683)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.84_2) (envelope-from <casouri@HIDDEN>) id 1tZ3Rd-0004iY-PU
 for 75609 <at> debbugs.gnu.org; Sat, 18 Jan 2025 02:40:38 -0500
Received: by mail-pl1-x62c.google.com with SMTP id
 d9443c01a7336-2161eb95317so55568085ad.1
 for <75609 <at> debbugs.gnu.org>; Fri, 17 Jan 2025 23:40:37 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1737186031; x=1737790831; darn=debbugs.gnu.org;
 h=to:references:message-id:content-transfer-encoding:cc:date
 :in-reply-to:from:subject:mime-version:from:to:cc:subject:date
 :message-id:reply-to;
 bh=f/KkueBlApzwAeL4WC0oBoGL7jUU4EI5OyA6BZnAlCo=;
 b=VhJtjrb0Mgj2EdGwKtLW4a2fOAo9aFqMO/CoSQakYMa7tqfAohZE0L6vpLaC4fqZyR
 dR9j3dTLABmbQLid/kXtm1ztb5KKjNwPjNDUbBvJ7X/wvfoxrrm55+oAfDUYzb+sarHB
 5vnK6WBFxDrx0CZT+Q8U5XTsQQ/WvblfpO/rHCf5VwfwvbZkbm2dpBGv+xbcFnHc4bak
 Qo3V5e9esj5KIfEY/IGjlJ7clkZkVPBQwsWYjVv+bcfgOux/VUjE0+AWVosMvHci52J2
 Vnc1o/Kbs773qub9jhzacUchTidzW0dqK+D9vQMKSf5oluL1uLHPl7iVKXrzEqFAMmOi
 UhVQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1737186031; x=1737790831;
 h=to:references:message-id:content-transfer-encoding:cc:date
 :in-reply-to:from:subject:mime-version:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=f/KkueBlApzwAeL4WC0oBoGL7jUU4EI5OyA6BZnAlCo=;
 b=wHPzsK8wOZsjKfwIPtM08tEEWMoifSLKATO7wk1keBLSZ8IoY8VsClPLZI6Y7WORGS
 VeHS750rlNU9DxIO/islTvhs5sXncvdGcHdTpNm7I2SeSRsPNv4x9ZSoxogmq930MTau
 qna9RqitlWaQch04hQNQZFk3FT2/mkY5/QpHDp4LCZ72E75oAFsKsPOGGMdQnAJK43DF
 y9nrlcGESzGoEgVXt3C5qLqZeiTyckTkPmIh/NFqbPfBolwZvAdOPcg/RA7EfvVaHDsQ
 PiOy64C3kbJGGK1WPUjib7mF/Y9I8zt5WERAUXLQl51TifkdK/0AdzGSXLRZ9mE0cQ1P
 MAcw==
X-Gm-Message-State: AOJu0YzLvZFM6eH4apV804UDk/nYi4u6cYLjiJmsCB6/ePvXdOOAwOfH
 wh5AsyU+PiSNPvvhH0ZQ6utdfWOcoJLXhoUJifNw5pYH376rgOgk
X-Gm-Gg: ASbGncvMT26nrMJO8rIYh361oJmTc7sLmoP7oYimk510Qsn4V3w+ZaFqtaBmfXh3fka
 kLDtzN+5ieYhLPrM3cHgT0F65yZ7KCZZXy4TBOop+QOqC4qHt/Oy71cvRYZVt4qsbWLj4YDARbY
 wWLdwJhfsM3+prxbm9mIANi/rQuhF60/A07flUE2ubKtbfyYiF8zwdd3H+Ew+Fzulir66UIZEPQ
 XYgRWqKOvFBHrnCi6VGhcGeYx8qOvcaMaNmWCVuPNEfe8JfTilykFL5C3R/YNE6dQxy6zbrwRc=
X-Google-Smtp-Source: AGHT+IEUbmVaXBNhzCR2RwOZMejOnUTSkIPodrD4kLnSi0O/zMlEk2KeHGxQC2vxuok6tMTintMiCQ==
X-Received: by 2002:a17:902:f60f:b0:215:8270:77e2 with SMTP id
 d9443c01a7336-21c34cb5bf8mr98269265ad.0.1737186031193; 
 Fri, 17 Jan 2025 23:40:31 -0800 (PST)
Received: from smtpclient.apple ([2406:da14:40a:c900:b51c:c5cf:684f:70e8])
 by smtp.gmail.com with ESMTPSA id
 d9443c01a7336-21c2ce9ff84sm26869015ad.29.2025.01.17.23.40.29
 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
 Fri, 17 Jan 2025 23:40:30 -0800 (PST)
Content-Type: text/plain;
	charset=utf-8
Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3776.700.51\))
Subject: Re: bug#75609: Hideshow support for treesitter
From: Yuan Fu <casouri@HIDDEN>
In-Reply-To: <87tt9yu00k.fsf@HIDDEN>
Date: Fri, 17 Jan 2025 23:40:16 -0800
Content-Transfer-Encoding: quoted-printable
Message-Id: <2999991B-3A95-4CC7-92BE-9A6B8F18BADE@HIDDEN>
References: <87tt9yu00k.fsf@HIDDEN>
To: Juri Linkov <juri@HIDDEN>
X-Mailer: Apple Mail (2.3776.700.51)
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 75609
Cc: 75609 <at> debbugs.gnu.org
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 (-)



> On Jan 16, 2025, at 9:45=E2=80=AFAM, Juri Linkov <juri@HIDDEN> =
wrote:
>=20
> Tags: patch
>=20
> Now that we have the new list thing in tree-sitter, it became possible
> to implement the hideshow support to hide the list things, i.e.
> exactly what hs-minor-mode did in non-ts modes:

Awesome! Thanks :-) Some comments below:

>=20
> diff --git a/lisp/treesit.el b/lisp/treesit.el
> index ac34edaf84d..0e48fb91b44 100644
> --- a/lisp/treesit.el
> +++ b/lisp/treesit.el
> @@ -3420,6 +3420,65 @@ treesit-outline-level
>       (setq level (1+ level)))
>     (if (zerop level) 1 level)))
>=20
> +;;; Hideshow mode
> +
> +(defun treesit-hs-block-end ()
> +  (let* ((pred 'list)
> +         (thing (treesit-thing-at
> +                 (if (bobp) (point) (1- (point))) pred))
> +         (end (when thing (treesit-node-end thing)))
> +         (last (when thing (treesit-node-child thing -1)))
> +         (beg (if last (treesit-node-start last)
> +                (if (bobp) (point) (1- (point))))))
> +    (when (and thing (eq (point) end))
> +      (set-match-data (list beg end))
> +      t)))
> +
> +(defun treesit-hs-find-block-beginning ()
> +  (let* ((pred 'list)
> +         (thing (treesit-thing-at (point) pred))
> +         (thing (or thing (treesit-parent-until (treesit-node-at =
(point)) pred)))
> +         (beg (when thing (treesit-node-start thing)))
> +         (end (when thing (treesit-node-end thing))))
> +    (when thing
> +      (goto-char beg)
> +      (set-match-data (list beg end))
> +      t)))
> +
> +(defun treesit-hs-find-next-block (_regexp _maxp comments)
> +  (let* ((pred (if comments '(or list "comment") 'list))
> +         ;; `treesit-navigate-thing' can't find a thing at bobp,
> +         ;; so use `treesit-thing-at' to match at bobp.
> +         (current (treesit-thing-at (point) pred))
> +         (beg (or (and current (eq (point) (treesit-node-start =
current)) (point))
> +                  (treesit-navigate-thing (point) 1 'beg pred)))
> +         (thing (when beg (treesit-thing-at beg pred)))
> +         (end (when thing (treesit-node-end thing))))
> +    (when thing
> +      (goto-char end)
> +      (set-match-data
> +       (if (and comments (equal (treesit-node-type thing) "comment"))
> +           (list beg end nil nil beg end)
> +         (list beg end beg end)))
> +      t)))
> +
> +(defun treesit-hs-looking-at-block-start-p ()
> +  (let* ((pred 'list)
> +         (thing (treesit-thing-at (point) pred))
> +         (beg (when thing (treesit-node-start thing)))
> +         (first (when thing (treesit-node-child thing 0)))
> +         (end (if first (treesit-node-end first) (1+ (point)))))
> +    (when (and thing (eq (point) beg))
> +      (set-match-data (list beg end))
> +      t)))
> +
> +(defun treesit-hs-inside-comment-p ()
> +  (let ((thing (or (treesit-thing-at (point) "comment")
> +                   (unless (bobp)
> +                     (treesit-thing-at (1- (point)) "comment")))))
> +    (when thing
> +      (list (treesit-node-start thing) (treesit-node-end thing)))))
> +

FYI some grammar calls comments line_comment and block_comment. Maybe =
use the comment thing first, and then match =E2=80=9Ccomment=E2=80=9D =
with the node type?

> ;;; Show paren mode
>=20
> (defun treesit-show-paren-data--categorize (pos &optional end-p)
> @@ -3603,7 +3662,17 @@ treesit-major-mode-setup
>     (setq-local forward-list-function #'treesit-forward-list)
>     (setq-local down-list-function #'treesit-down-list)
>     (setq-local up-list-function #'treesit-up-list)
> -    (setq-local show-paren-data-function 'treesit-show-paren-data))
> +    (setq-local show-paren-data-function #'treesit-show-paren-data)
> +    (setq hs-block-start-regexp nil
> +          hs-block-start-mdata-select 0
> +          hs-block-end-regexp #'treesit-hs-block-end
> +          hs-c-start-regexp nil
> +          hs-forward-sexp-func #'forward-list
> +          hs-adjust-block-beginning nil
> +          hs-find-block-beginning-func =
#'treesit-hs-find-block-beginning
> +          hs-find-next-block-func #'treesit-hs-find-next-block
> +          hs-looking-at-block-start-p-func =
#'treesit-hs-looking-at-block-start-p
> +          hs-inside-comment-p-func #'treesit-hs-inside-comment-p))
>=20
>   (when (treesit-thing-defined-p 'sentence nil)
>     (setq-local forward-sentence-function #'treesit-forward-sentence))
> diff --git a/lisp/progmodes/hideshow.el b/lisp/progmodes/hideshow.el
> index 823eb0527c6..ea7bc738a4d 100644
> --- a/lisp/progmodes/hideshow.el
> +++ b/lisp/progmodes/hideshow.el
> @@ -259,14 +259,11 @@ hs-special-modes-alist
>   ;; to the mode hierarchy.
>   (mapcar #'purecopy
>   '((c-mode "{" "}" "/[*/]" nil nil)
> -    (c-ts-mode "{" "}" "/[*/]" nil nil)
>     (c++-mode "{" "}" "/[*/]" nil nil)
> -    (c++-ts-mode "{" "}" "/[*/]" nil nil)
>     (bibtex-mode ("@\\S(*\\(\\s(\\)" 1))
>     (java-mode "{" "}" "/[*/]" nil nil)
>     (java-ts-mode "{" "}" "/[*/]" nil nil)
>     (js-mode "{" "}" "/[*/]" nil)
> -    (js-ts-mode "{" "}" "/[*/]" nil)
>     (lua-ts-mode "{\\|\\[\\[" "}\\|\\]\\]" "--" nil)
>     (mhtml-mode "{\\|<[^/>]*?" "}\\|</[^/>]*[^/]>" "<!--" =
mhtml-forward nil)
>     ;; Add more support here.
> @@ -481,6 +478,9 @@ hs-looking-at-block-start-p-func
> Python, where `looking-at' and `syntax-ppss' check is not enough
> to check if the point is at the block start.")
>=20
> +(defvar-local hs-inside-comment-p-func nil
> +  "Function used to check if point is inside a comment.")
> +
> (defvar hs-headline nil
>   "Text of the line where a hidden block begins, set during isearch.
> You can display this in the mode line by adding the symbol =
`hs-headline'
> @@ -625,9 +625,13 @@ hs-hide-block-at-point
>  (setq p (line-end-position)))
> ;; `q' is the point at the end of the block
> (hs-forward-sexp mdata 1)
> - (setq q (if (looking-back hs-block-end-regexp nil)
> -    (match-beginning 0)
> -  (point)))
> + (setq q (cond ((and (stringp hs-block-end-regexp)
> +                            (looking-back hs-block-end-regexp nil))
> +       (match-beginning 0))
> +                      ((functionp hs-block-end-regexp)
> +                       (funcall hs-block-end-regexp)
> +                       (match-beginning 0))
> +      (t (point))))
>         (when (and (< p q) (> (count-lines p q) 1))
>           (cond ((and hs-allow-nesting (setq ov (hs-overlay-at p)))
>                  (delete-overlay ov))
> @@ -644,6 +648,9 @@ hs-inside-comment-p
> beginning.  If we are inside of a comment but this condition is not =
met,
> we return a list having a nil as its car and the end of comment =
position
> as cdr."
> +  (cond ((functionp hs-inside-comment-p-func)
> +         (funcall hs-inside-comment-p-func))
> +  (t

Did you do this indentation on purpose to make a easier-to-read diff?

>   (save-excursion
>     ;; the idea is to look backwards for a comment start regexp, do a
>     ;; forward comment, and see if we are inside, then extend
> @@ -692,7 +699,7 @@ hs-inside-comment-p
>           (skip-chars-backward " \t\n\f")
>           (end-of-line)
>           (when (>=3D (point) q)
> -            (list (and hideable p) (point))))))))
> +            (list (and hideable p) (point))))))))))
>=20
> (defun hs-grok-mode-type ()
>   "Set up hideshow variables for new buffers.
> @@ -704,7 +711,7 @@ hs-grok-mode-type
>            (bound-and-true-p comment-end))
>       (let* ((lookup (assoc major-mode hs-special-modes-alist))
>              (start-elem (or (nth 1 lookup) "\\s(")))
> -        (if (listp start-elem)
> +        (if (consp start-elem)
>             ;; handle (START-REGEXP MDATA-SELECT)
>             (setq hs-block-start-regexp (car start-elem)
>                   hs-block-start-mdata-select (cadr start-elem))
> @@ -850,14 +857,16 @@ hs-hide-all
>      (syntax-propertize (point-max))
>      (let ((spew (make-progress-reporter "Hiding all blocks..."
>                                          (point-min) (point-max)))
> -           (re (concat "\\("
> -                       hs-block-start-regexp
> -                       "\\)"
> -                       (if hs-hide-comments-when-hiding-all
> -                           (concat "\\|\\("
> -                                   hs-c-start-regexp
> -                                   "\\)")
> -                         ""))))
> +           (re (when (stringp hs-block-start-regexp)
> +                 (concat "\\("
> +                         hs-block-start-regexp
> +                         "\\)"
> +                         (if (and hs-hide-comments-when-hiding-all
> +                                  (stringp hs-c-start-regexp))
> +                             (concat "\\|\\("
> +                                     hs-c-start-regexp
> +                                     "\\)")
> +                           "")))))
>        (while (funcall hs-find-next-block-func re (point-max)
>                        hs-hide-comments-when-hiding-all)
>          (if (match-beginning 1)
> @@ -869,7 +878,9 @@ hs-hide-all
> (hs-hide-block-at-point t))
> ;; Go to end of matched data to prevent from getting stuck
> ;; with an endless loop.
> -                 (when (looking-at hs-block-start-regexp)
> +                 (when (if (stringp hs-block-start-regexp)
> +                           (looking-at hs-block-start-regexp)
> +                         (eq (point) (match-beginning 0)))
>   (goto-char (match-end 0)))))
>            ;; found a comment, probably
>            (let ((c-reg (hs-inside-comment-p)))
> @@ -1008,7 +1019,8 @@ hs-minor-mode
>   (setq hs-headline nil)
>   (if hs-minor-mode
>       (progn
> -        (hs-grok-mode-type)
> +        (unless (buffer-local-value 'hs-inside-comment-p-func =
(current-buffer))
> +          (hs-grok-mode-type))
>         ;; Turn off this mode if we change major modes.
>         (add-hook 'change-major-mode-hook
>                   #'turn-off-hideshow





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

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


Received: (at submit) by debbugs.gnu.org; 16 Jan 2025 17:49:19 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Jan 16 12:49:19 2025
Received: from localhost ([127.0.0.1]:34556 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1tYTza-00010O-LQ
	for submit <at> debbugs.gnu.org; Thu, 16 Jan 2025 12:49:19 -0500
Received: from lists.gnu.org ([2001:470:142::17]:50564)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <juri@HIDDEN>) id 1tYTzX-000105-TT
 for submit <at> debbugs.gnu.org; Thu, 16 Jan 2025 12:49:16 -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 1tYTzP-0005Pc-ID
 for bug-gnu-emacs@HIDDEN; Thu, 16 Jan 2025 12:49:07 -0500
Received: from relay3-d.mail.gandi.net ([217.70.183.195])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <juri@HIDDEN>) id 1tYTzM-0004jL-1b
 for bug-gnu-emacs@HIDDEN; Thu, 16 Jan 2025 12:49:06 -0500
Received: by mail.gandi.net (Postfix) with ESMTPSA id 1A2A86000A
 for <bug-gnu-emacs@HIDDEN>; Thu, 16 Jan 2025 17:48:58 +0000 (UTC)
From: Juri Linkov <juri@HIDDEN>
To: bug-gnu-emacs@HIDDEN
Subject: Hideshow support for treesitter
Organization: LINKOV.NET
X-Debbugs-Cc: Yuan Fu <casouri@HIDDEN>
Date: Thu, 16 Jan 2025 19:45:11 +0200
Message-ID: <87tt9yu00k.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-Sasl: juri@HIDDEN
Received-SPF: pass client-ip=217.70.183.195; envelope-from=juri@HIDDEN;
 helo=relay3-d.mail.gandi.net
X-Spam_score_int: -25
X-Spam_score: -2.6
X-Spam_bar: --
X-Spam_report: (-2.6 / 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_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001,
 SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no
X-Spam_action: no action
X-Spam-Score: 0.7 (/)
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.3 (/)

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

Tags: patch

Now that we have the new list thing in tree-sitter, it became possible
to implement the hideshow support to hide the list things, i.e.
exactly what hs-minor-mode did in non-ts modes:


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

diff --git a/lisp/treesit.el b/lisp/treesit.el
index ac34edaf84d..0e48fb91b44 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -3420,6 +3420,65 @@ treesit-outline-level
       (setq level (1+ level)))
     (if (zerop level) 1 level)))
 
+;;; Hideshow mode
+
+(defun treesit-hs-block-end ()
+  (let* ((pred 'list)
+         (thing (treesit-thing-at
+                 (if (bobp) (point) (1- (point))) pred))
+         (end (when thing (treesit-node-end thing)))
+         (last (when thing (treesit-node-child thing -1)))
+         (beg (if last (treesit-node-start last)
+                (if (bobp) (point) (1- (point))))))
+    (when (and thing (eq (point) end))
+      (set-match-data (list beg end))
+      t)))
+
+(defun treesit-hs-find-block-beginning ()
+  (let* ((pred 'list)
+         (thing (treesit-thing-at (point) pred))
+         (thing (or thing (treesit-parent-until (treesit-node-at (point)) pred)))
+         (beg (when thing (treesit-node-start thing)))
+         (end (when thing (treesit-node-end thing))))
+    (when thing
+      (goto-char beg)
+      (set-match-data (list beg end))
+      t)))
+
+(defun treesit-hs-find-next-block (_regexp _maxp comments)
+  (let* ((pred (if comments '(or list "comment") 'list))
+         ;; `treesit-navigate-thing' can't find a thing at bobp,
+         ;; so use `treesit-thing-at' to match at bobp.
+         (current (treesit-thing-at (point) pred))
+         (beg (or (and current (eq (point) (treesit-node-start current)) (point))
+                  (treesit-navigate-thing (point) 1 'beg pred)))
+         (thing (when beg (treesit-thing-at beg pred)))
+         (end (when thing (treesit-node-end thing))))
+    (when thing
+      (goto-char end)
+      (set-match-data
+       (if (and comments (equal (treesit-node-type thing) "comment"))
+           (list beg end nil nil beg end)
+         (list beg end beg end)))
+      t)))
+
+(defun treesit-hs-looking-at-block-start-p ()
+  (let* ((pred 'list)
+         (thing (treesit-thing-at (point) pred))
+         (beg (when thing (treesit-node-start thing)))
+         (first (when thing (treesit-node-child thing 0)))
+         (end (if first (treesit-node-end first) (1+ (point)))))
+    (when (and thing (eq (point) beg))
+      (set-match-data (list beg end))
+      t)))
+
+(defun treesit-hs-inside-comment-p ()
+  (let ((thing (or (treesit-thing-at (point) "comment")
+                   (unless (bobp)
+                     (treesit-thing-at (1- (point)) "comment")))))
+    (when thing
+      (list (treesit-node-start thing) (treesit-node-end thing)))))
+
 ;;; Show paren mode
 
 (defun treesit-show-paren-data--categorize (pos &optional end-p)
@@ -3603,7 +3662,17 @@ treesit-major-mode-setup
     (setq-local forward-list-function #'treesit-forward-list)
     (setq-local down-list-function #'treesit-down-list)
     (setq-local up-list-function #'treesit-up-list)
-    (setq-local show-paren-data-function 'treesit-show-paren-data))
+    (setq-local show-paren-data-function #'treesit-show-paren-data)
+    (setq hs-block-start-regexp nil
+          hs-block-start-mdata-select 0
+          hs-block-end-regexp #'treesit-hs-block-end
+          hs-c-start-regexp nil
+          hs-forward-sexp-func #'forward-list
+          hs-adjust-block-beginning nil
+          hs-find-block-beginning-func #'treesit-hs-find-block-beginning
+          hs-find-next-block-func #'treesit-hs-find-next-block
+          hs-looking-at-block-start-p-func #'treesit-hs-looking-at-block-start-p
+          hs-inside-comment-p-func #'treesit-hs-inside-comment-p))
 
   (when (treesit-thing-defined-p 'sentence nil)
     (setq-local forward-sentence-function #'treesit-forward-sentence))
diff --git a/lisp/progmodes/hideshow.el b/lisp/progmodes/hideshow.el
index 823eb0527c6..ea7bc738a4d 100644
--- a/lisp/progmodes/hideshow.el
+++ b/lisp/progmodes/hideshow.el
@@ -259,14 +259,11 @@ hs-special-modes-alist
   ;; to the mode hierarchy.
   (mapcar #'purecopy
   '((c-mode "{" "}" "/[*/]" nil nil)
-    (c-ts-mode "{" "}" "/[*/]" nil nil)
     (c++-mode "{" "}" "/[*/]" nil nil)
-    (c++-ts-mode "{" "}" "/[*/]" nil nil)
     (bibtex-mode ("@\\S(*\\(\\s(\\)" 1))
     (java-mode "{" "}" "/[*/]" nil nil)
     (java-ts-mode "{" "}" "/[*/]" nil nil)
     (js-mode "{" "}" "/[*/]" nil)
-    (js-ts-mode "{" "}" "/[*/]" nil)
     (lua-ts-mode "{\\|\\[\\[" "}\\|\\]\\]" "--" nil)
     (mhtml-mode "{\\|<[^/>]*?" "}\\|</[^/>]*[^/]>" "<!--" mhtml-forward nil)
     ;; Add more support here.
@@ -481,6 +478,9 @@ hs-looking-at-block-start-p-func
 Python, where `looking-at' and `syntax-ppss' check is not enough
 to check if the point is at the block start.")
 
+(defvar-local hs-inside-comment-p-func nil
+  "Function used to check if point is inside a comment.")
+
 (defvar hs-headline nil
   "Text of the line where a hidden block begins, set during isearch.
 You can display this in the mode line by adding the symbol `hs-headline'
@@ -625,9 +625,13 @@ hs-hide-block-at-point
 	  (setq p (line-end-position)))
 	;; `q' is the point at the end of the block
 	(hs-forward-sexp mdata 1)
-	(setq q (if (looking-back hs-block-end-regexp nil)
-		    (match-beginning 0)
-		  (point)))
+	(setq q (cond ((and (stringp hs-block-end-regexp)
+                            (looking-back hs-block-end-regexp nil))
+		       (match-beginning 0))
+                      ((functionp hs-block-end-regexp)
+                       (funcall hs-block-end-regexp)
+                       (match-beginning 0))
+		      (t (point))))
         (when (and (< p q) (> (count-lines p q) 1))
           (cond ((and hs-allow-nesting (setq ov (hs-overlay-at p)))
                  (delete-overlay ov))
@@ -644,6 +648,9 @@ hs-inside-comment-p
 beginning.  If we are inside of a comment but this condition is not met,
 we return a list having a nil as its car and the end of comment position
 as cdr."
+  (cond ((functionp hs-inside-comment-p-func)
+         (funcall hs-inside-comment-p-func))
+  (t
   (save-excursion
     ;; the idea is to look backwards for a comment start regexp, do a
     ;; forward comment, and see if we are inside, then extend
@@ -692,7 +699,7 @@ hs-inside-comment-p
           (skip-chars-backward " \t\n\f")
           (end-of-line)
           (when (>= (point) q)
-            (list (and hideable p) (point))))))))
+            (list (and hideable p) (point))))))))))
 
 (defun hs-grok-mode-type ()
   "Set up hideshow variables for new buffers.
@@ -704,7 +711,7 @@ hs-grok-mode-type
            (bound-and-true-p comment-end))
       (let* ((lookup (assoc major-mode hs-special-modes-alist))
              (start-elem (or (nth 1 lookup) "\\s(")))
-        (if (listp start-elem)
+        (if (consp start-elem)
             ;; handle (START-REGEXP MDATA-SELECT)
             (setq hs-block-start-regexp (car start-elem)
                   hs-block-start-mdata-select (cadr start-elem))
@@ -850,14 +857,16 @@ hs-hide-all
      (syntax-propertize (point-max))
      (let ((spew (make-progress-reporter "Hiding all blocks..."
                                          (point-min) (point-max)))
-           (re (concat "\\("
-                       hs-block-start-regexp
-                       "\\)"
-                       (if hs-hide-comments-when-hiding-all
-                           (concat "\\|\\("
-                                   hs-c-start-regexp
-                                   "\\)")
-                         ""))))
+           (re (when (stringp hs-block-start-regexp)
+                 (concat "\\("
+                         hs-block-start-regexp
+                         "\\)"
+                         (if (and hs-hide-comments-when-hiding-all
+                                  (stringp hs-c-start-regexp))
+                             (concat "\\|\\("
+                                     hs-c-start-regexp
+                                     "\\)")
+                           "")))))
        (while (funcall hs-find-next-block-func re (point-max)
                        hs-hide-comments-when-hiding-all)
          (if (match-beginning 1)
@@ -869,7 +878,9 @@ hs-hide-all
 			 (hs-hide-block-at-point t))
 		 ;; Go to end of matched data to prevent from getting stuck
 		 ;; with an endless loop.
-                 (when (looking-at hs-block-start-regexp)
+                 (when (if (stringp hs-block-start-regexp)
+                           (looking-at hs-block-start-regexp)
+                         (eq (point) (match-beginning 0)))
 		   (goto-char (match-end 0)))))
            ;; found a comment, probably
            (let ((c-reg (hs-inside-comment-p)))
@@ -1008,7 +1019,8 @@ hs-minor-mode
   (setq hs-headline nil)
   (if hs-minor-mode
       (progn
-        (hs-grok-mode-type)
+        (unless (buffer-local-value 'hs-inside-comment-p-func (current-buffer))
+          (hs-grok-mode-type))
         ;; Turn off this mode if we change major modes.
         (add-hook 'change-major-mode-hook
                   #'turn-off-hideshow

--=-=-=--




Acknowledgement sent to Juri Linkov <juri@HIDDEN>:
New bug report received and forwarded. Copy sent to casouri@HIDDEN, bug-gnu-emacs@HIDDEN. Full text available.
Report forwarded to casouri@HIDDEN, bug-gnu-emacs@HIDDEN:
bug#75609; 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: Tue, 21 Jan 2025 02:30:02 UTC

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