all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* outline-mode treesitter support?
@ 2023-12-19 11:43 Huan Nguyen
  2023-12-19 13:00 ` Eli Zaretskii
  2023-12-19 17:14 ` Juri Linkov
  0 siblings, 2 replies; 11+ messages in thread
From: Huan Nguyen @ 2023-12-19 11:43 UTC (permalink / raw)
  To: emacs-devel

Are there any plans on making outline-mode take tree sitter nodes instead of regex?
Is it possible to add that functionality or would a new mode be necessary.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: outline-mode treesitter support?
  2023-12-19 11:43 outline-mode treesitter support? Huan Nguyen
@ 2023-12-19 13:00 ` Eli Zaretskii
  2023-12-19 13:25   ` Huan Nguyen
  2023-12-19 17:14 ` Juri Linkov
  1 sibling, 1 reply; 11+ messages in thread
From: Eli Zaretskii @ 2023-12-19 13:00 UTC (permalink / raw)
  To: Huan Nguyen; +Cc: emacs-devel

> From: Huan Nguyen <nguyenthieuhuan@gmail.com>
> Date: Tue, 19 Dec 2023 12:43:40 +0100
> 
> Are there any plans on making outline-mode take tree sitter nodes instead of regex?

Is there a tree-sitter grammar available somewhere for Outline mode?

> Is it possible to add that functionality or would a new mode be necessary.

It depends on how well the existing mode's features map into a
tree-sitter based one.



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: outline-mode treesitter support?
  2023-12-19 13:00 ` Eli Zaretskii
@ 2023-12-19 13:25   ` Huan Nguyen
  2023-12-19 13:42     ` Eli Zaretskii
  0 siblings, 1 reply; 11+ messages in thread
From: Huan Nguyen @ 2023-12-19 13:25 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel



> On Dec 19, 2023, at 14:00, Eli Zaretskii <eliz@gnu.org> wrote:
> 
>> From: Huan Nguyen <nguyenthieuhuan@gmail.com>
>> Date: Tue, 19 Dec 2023 12:43:40 +0100
>> 
>> Are there any plans on making outline-mode take tree sitter nodes instead of regex?
> 
> Is there a tree-sitter grammar available somewhere for Outline mode?
I am not aware of any. I am writing a treesitter based mode for a markup language.
It has been manageable to write increase/decrease heading levels and move headings up/down yourself. For folding I am was looking how I could do it but I only found outline-mode.
> 
>> Is it possible to add that functionality or would a new mode be necessary.
> 
> It depends on how well the existing mode's features map into a
> tree-sitter based one.
The features should be the same but they should work on treesitter nodes instead of regexp. The advantage is that it will be more “correct”.

Take the example nodes: 
(heading1 (content ...)) 
You may wish to hide the child content.

(heading1 
	(content
		(heading2 (content …))))
You may wish to promote heading2, removing it from its parent heading.

The problem I see in that is that not all treesitter grammars have this tree like structure. 
Doing it yourself is not that hard as I said before, so it is not a high priority for me.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: outline-mode treesitter support?
  2023-12-19 13:25   ` Huan Nguyen
@ 2023-12-19 13:42     ` Eli Zaretskii
  0 siblings, 0 replies; 11+ messages in thread
From: Eli Zaretskii @ 2023-12-19 13:42 UTC (permalink / raw)
  To: Huan Nguyen; +Cc: emacs-devel

> From: Huan Nguyen <nguyenthieuhuan@gmail.com>
> Date: Tue, 19 Dec 2023 14:25:01 +0100
> Cc: emacs-devel@gnu.org
> 
> > On Dec 19, 2023, at 14:00, Eli Zaretskii <eliz@gnu.org> wrote:
> > 
> >> From: Huan Nguyen <nguyenthieuhuan@gmail.com>
> >> Date: Tue, 19 Dec 2023 12:43:40 +0100
> >> 
> >> Are there any plans on making outline-mode take tree sitter nodes instead of regex?
> > 
> > Is there a tree-sitter grammar available somewhere for Outline mode?
> I am not aware of any. I am writing a treesitter based mode for a markup language.

Someone will have to write a grammar before an Emacs mode will be
practical.  For other TS modes, we didn't write the grammar: we used
existing ones.



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: outline-mode treesitter support?
  2023-12-19 11:43 outline-mode treesitter support? Huan Nguyen
  2023-12-19 13:00 ` Eli Zaretskii
@ 2023-12-19 17:14 ` Juri Linkov
  2023-12-19 18:31   ` Huan Nguyen
  1 sibling, 1 reply; 11+ messages in thread
From: Juri Linkov @ 2023-12-19 17:14 UTC (permalink / raw)
  To: Huan Nguyen; +Cc: emacs-devel

> Are there any plans on making outline-mode take tree sitter nodes instead of regex?

The last time this was discussed a year ago, and still no progress:
https://lists.gnu.org/archive/html/emacs-devel/2022-12/msg01010.html

> Is it possible to add that functionality or would a new mode be necessary.

Yes, now this is possible to do after 'outline-search-function'
was added in Emacs 29.  So you can use it to find the next outline heading
that corresponds to the next tree sitter node.



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: outline-mode treesitter support?
  2023-12-19 17:14 ` Juri Linkov
@ 2023-12-19 18:31   ` Huan Nguyen
  2023-12-20  7:50     ` Juri Linkov
  0 siblings, 1 reply; 11+ messages in thread
From: Huan Nguyen @ 2023-12-19 18:31 UTC (permalink / raw)
  To: Juri Linkov; +Cc: emacs-devel



> On Dec 19, 2023, at 18:14, Juri Linkov <juri@linkov.net> wrote:
> 
>> Are there any plans on making outline-mode take tree sitter nodes instead of regex?
> 
> The last time this was discussed a year ago, and still no progress:
> https://lists.gnu.org/archive/html/emacs-devel/2022-12/msg01010.html
> 
>> Is it possible to add that functionality or would a new mode be necessary.
> 
> Yes, now this is possible to do after 'outline-search-function'
> was added in Emacs 29.  So you can use it to find the next outline heading
> that corresponds to the next tree sitter node.

‘outline-search-function’ should be documented in C-h f outline-mode help buffer.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: outline-mode treesitter support?
  2023-12-19 18:31   ` Huan Nguyen
@ 2023-12-20  7:50     ` Juri Linkov
  2023-12-20 17:08       ` Juri Linkov
  0 siblings, 1 reply; 11+ messages in thread
From: Juri Linkov @ 2023-12-20  7:50 UTC (permalink / raw)
  To: Huan Nguyen; +Cc: emacs-devel

>>> Are there any plans on making outline-mode take tree sitter nodes instead of regex?
>>
>> The last time this was discussed a year ago, and still no progress:
>> https://lists.gnu.org/archive/html/emacs-devel/2022-12/msg01010.html
>>
>>> Is it possible to add that functionality or would a new mode be necessary.
>>
>> Yes, now this is possible to do after 'outline-search-function'
>> was added in Emacs 29.  So you can use it to find the next outline heading
>> that corresponds to the next tree sitter node.
>
> ‘outline-search-function’ should be documented in C-h f outline-mode help buffer.

‘outline-mode’ is irrelevant for tree sitter.  You can use tree sitter only with
‘outline-minor-mode’.

OK, one way to extract treesit information for outline-minor-mode is by using
‘treesit-simple-imenu’ because outline headings should correspond to imenu entries.

So I looked how to do this for example in ruby-ts-mode, but it's strange
that ruby-ts-mode doesn't use ‘treesit-simple-imenu-settings’: all ts-modes
use ‘treesit-simple-imenu-settings’, only ruby-ts-mode doesn't use it.

This means we can't use ‘treesit-simple-imenu’ for outline headings,
and need to implement a separate feature similar to ‘treesit-simple-imenu’.



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: outline-mode treesitter support?
  2023-12-20  7:50     ` Juri Linkov
@ 2023-12-20 17:08       ` Juri Linkov
  2023-12-21  4:03         ` Huan Nguyen
  0 siblings, 1 reply; 11+ messages in thread
From: Juri Linkov @ 2023-12-20 17:08 UTC (permalink / raw)
  To: Huan Nguyen; +Cc: emacs-devel

> OK, one way to extract treesit information for outline-minor-mode is by using
> ‘treesit-simple-imenu’ because outline headings should correspond to imenu entries.

I don't know if this is a good idea, but with

  (setq-local outline-search-function #'outline-search-imenu
              outline-level (lambda () 1))

this should do the trick:

#+begin_src emacs-lisp
(defun outline-search-imenu (&optional bound move backward looking-at)
  (unless imenu--index-alist
    (imenu--make-index-alist))
  (let* ((imenu-index (cdar imenu--index-alist))
         (imenu-positions (mapcar (lambda (i) (cdr i)) imenu-index)))
    (if looking-at
        (when (member (point-marker) imenu-positions)
          (set-match-data (list (pos-bol) (pos-eol)))
          t)
      (let ((found (if backward
                       (seq-find (lambda (p) (< p (pos-bol))) (nreverse imenu-positions))
                     (seq-find (lambda (p) (> p (pos-eol))) imenu-positions))))
        (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)))))
#+end_src



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: outline-mode treesitter support?
  2023-12-20 17:08       ` Juri Linkov
@ 2023-12-21  4:03         ` Huan Nguyen
  2024-01-10  7:19           ` Juri Linkov
  0 siblings, 1 reply; 11+ messages in thread
From: Huan Nguyen @ 2023-12-21  4:03 UTC (permalink / raw)
  To: Juri Linkov; +Cc: emacs-devel



> On Dec 20, 2023, at 18:08, Juri Linkov <juri@linkov.net> wrote:
> 
>> OK, one way to extract treesit information for outline-minor-mode is by using
>> ‘treesit-simple-imenu’ because outline headings should correspond to imenu entries.
> 
> I don't know if this is a good idea, but with
> 
>  (setq-local outline-search-function #'outline-search-imenu
>              outline-level (lambda () 1))
> 
> this should do the trick:
> 
> #+begin_src emacs-lisp
> (defun outline-search-imenu (&optional bound move backward looking-at)
>  (unless imenu--index-alist
>    (imenu--make-index-alist))
>  (let* ((imenu-index (cdar imenu--index-alist))
>         (imenu-positions (mapcar (lambda (i) (cdr i)) imenu-index)))
>    (if looking-at
>        (when (member (point-marker) imenu-positions)
>          (set-match-data (list (pos-bol) (pos-eol)))
>          t)
>      (let ((found (if backward
>                       (seq-find (lambda (p) (< p (pos-bol))) (nreverse imenu-positions))
>                     (seq-find (lambda (p) (> p (pos-eol))) imenu-positions))))
>        (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)))))
> #+end_src

Thanks for the example!


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: outline-mode treesitter support?
  2023-12-21  4:03         ` Huan Nguyen
@ 2024-01-10  7:19           ` Juri Linkov
  2024-01-24 17:23             ` Juri Linkov
  0 siblings, 1 reply; 11+ messages in thread
From: Juri Linkov @ 2024-01-10  7:19 UTC (permalink / raw)
  To: Huan Nguyen; +Cc: emacs-devel

>>> OK, one way to extract treesit information for outline-minor-mode is by using
>>> ‘treesit-simple-imenu’ because outline headings should correspond to imenu entries.
>>
>> I don't know if this is a good idea, but with
>>
>>  (setq-local outline-search-function #'outline-search-imenu
>>              outline-level (lambda () 1))
>>
>> this should do the trick:
>>
>> (defun outline-search-imenu (&optional bound move backward looking-at)
>>  (unless imenu--index-alist
>>    (imenu--make-index-alist))
>>  (let* ((imenu-index (cdar imenu--index-alist))
>> [...]
>
> Thanks for the example!

After trying to use this, I came to conclusion that imenu--index-alist
is unsuitable for outline-minor-mode because imenu has a different
hierarchy than the source files, so outline-level can be only 1.
But without different levels for outline-level it's quite useless.

However, in the opposite direction mapping the outline hierarchy
to imenu is possible, and outline-imenu-generic-expression
does this, but only to a flat list that is sorted alphabetically.



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: outline-mode treesitter support?
  2024-01-10  7:19           ` Juri Linkov
@ 2024-01-24 17:23             ` Juri Linkov
  0 siblings, 0 replies; 11+ messages in thread
From: Juri Linkov @ 2024-01-24 17:23 UTC (permalink / raw)
  To: Huan Nguyen; +Cc: emacs-devel

>>> (defun outline-search-imenu (&optional bound move backward looking-at)
>>>  (unless imenu--index-alist
>>>    (imenu--make-index-alist))
>>>  (let* ((imenu-index (cdar imenu--index-alist))
>
> After trying to use this, I came to conclusion that imenu--index-alist
> is unsuitable for outline-minor-mode because imenu has a different
> hierarchy than the source files, so outline-level can be only 1.
> But without different levels for outline-level it's quite useless.

Many ts-modes are already defining treesit-simple-imenu-settings that
can be reused or outlines.  We just need to add levels to all entries
found for imenu.

So here is a complete working implementation.  Then
with e.g. `M-x c-ts-mode` and `M-x outline-minor-mode`
it will put outlines on declarations and definitions.

#+begin_src emacs-lisp
(add-hook
 'prog-mode-hook
 (lambda ()
   (when (bound-and-true-p treesit-simple-imenu-settings)
     (setq-local treesit-outline-predicate
                 (lambda (node)
                   (seq-some
                    (lambda (setting)
                      (and (string-match-p (nth 1 setting) (treesit-node-type node))
                           (funcall (nth 2 setting) node)))
                    treesit-simple-imenu-settings)))
     (setq-local treesit-outline-levels
                 (treesit-outline-levels
                  (treesit-induce-sparse-tree
                   (treesit-buffer-root-node)
                   treesit-outline-predicate)
                  0))
     (setq-local outline-search-function #'treesit-search-outline
                 outline-level
                 (lambda ()
                   (or (alist-get (point) treesit-outline-levels nil nil
                                  (lambda (m k) (eq (marker-position m) k)))
                       1))))))

(defun treesit-outline-levels (node level)
  (let* ((ts-node (car node))
         (children (cdr node))
         (subtrees (mapcan (lambda (node)
                             (treesit-outline-levels node (1+ level)))
                           children))
         (marker (when ts-node
                   (set-marker (make-marker)
                               (save-excursion
                                 (goto-char (treesit-node-start ts-node))
                                 (search-forward (or (treesit-defun-name ts-node) ""))
                                 (pos-bol))))))
    (cond
     ((null ts-node)
      subtrees)
     (subtrees
      (cons (cons marker level) subtrees))
     (t
      (list (cons marker level))))))

(defun treesit-search-outline (&optional bound move backward looking-at)
  (let ((positions (mapcar #'car treesit-outline-levels)))
    (if looking-at
        (when (member (point-marker) positions)
          (set-match-data (list (pos-bol) (pos-eol)))
          t)
      (let ((found (if backward
                       (seq-find (lambda (p) (< p (pos-bol))) (nreverse positions))
                     (seq-find (lambda (p) (> p (pos-eol))) positions))))
        (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)))))
#+end_src



^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2024-01-24 17:23 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-12-19 11:43 outline-mode treesitter support? Huan Nguyen
2023-12-19 13:00 ` Eli Zaretskii
2023-12-19 13:25   ` Huan Nguyen
2023-12-19 13:42     ` Eli Zaretskii
2023-12-19 17:14 ` Juri Linkov
2023-12-19 18:31   ` Huan Nguyen
2023-12-20  7:50     ` Juri Linkov
2023-12-20 17:08       ` Juri Linkov
2023-12-21  4:03         ` Huan Nguyen
2024-01-10  7:19           ` Juri Linkov
2024-01-24 17:23             ` Juri Linkov

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.