* bug#58431: 29.0.50; [Eglot] Add "breadcrumb.el" feature based on imenu.el/project.el services @ 2022-10-11 9:17 João Távora 2022-10-11 15:38 ` Yuan Fu ` (2 more replies) 0 siblings, 3 replies; 12+ messages in thread From: João Távora @ 2022-10-11 9:17 UTC (permalink / raw) To: 58431; +Cc: eliz Hello, This request for a "breadcrumb" feature started in Eglot's bug tracker: https://github.com/joaotavora/eglot/discussions/988 Put it short, a breadcrumb is a summarized indication of the full path to the current location of point within a source file. So if I have a file 'baz.cpp' inside a directory 'bars' of a project directory 'foo' and that file contains: class Baz { int quux() { return 42; // point here } // or here }; Then the breadcrumb would read: foo > bars > baz.cpp > Baz > quux If I move my point to outside quux(), the breadcrumb should now read: foo > bars > baz.cpp > Baz The preferred location of this breadcrumb readout should be the headerline. In the original Eglot request, users are requesting this UI feature for the Eglot LSP client. But this doesn't have any LSP-specific interactions. It can and should be done entirely by using the services provided by imenu.el and project.el. Eglot already integrates with Imenu, so as soon as this hypothetical breadcrumb.el is in place, then Eglot users can take advantage of it. This is similar to which-func.el, which displays the trailing element of the breadcrumb in the headerline. Perhaps the breadcrumb feature can be thought of as an augmentation of which-func.el's functionality. I don't have a strong opinion there. João PS: Eli, I'm CCing you to underline this as just an example of a UI feature that is requested for Eglot, but belongs somewhere else. In this case, I believe there is 0 additional integration needed in eglot.el: it can be realized independently of the backend which feeds into Imenu (perhaps tree-sitter?) and project.el. ^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#58431: 29.0.50; [Eglot] Add "breadcrumb.el" feature based on imenu.el/project.el services 2022-10-11 9:17 bug#58431: 29.0.50; [Eglot] Add "breadcrumb.el" feature based on imenu.el/project.el services João Távora @ 2022-10-11 15:38 ` Yuan Fu 2022-10-11 23:50 ` João Távora 2023-04-08 19:47 ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-04-18 18:10 ` bug#58431: 29.0.50; [Eglot] Add "breadcrumb.el" feature based, " Adam Porter 2 siblings, 1 reply; 12+ messages in thread From: Yuan Fu @ 2022-10-11 15:38 UTC (permalink / raw) To: João Távora; +Cc: eliz, 58431 > In the original Eglot request, users are requesting this UI feature for > the Eglot LSP client. But this doesn't have any LSP-specific > interactions. It can and should be done entirely by using the services > provided by imenu.el and project.el. > > Eglot already integrates with Imenu, so as soon as this hypothetical > breadcrumb.el is in place, then Eglot users can take advantage of it. > > This is similar to which-func.el, which displays the trailing element of > the breadcrumb in the headerline. Perhaps the breadcrumb feature can be > thought of as an augmentation of which-func.el's functionality. I don't > have a strong opinion there. I think which-func is closer to breadcrumb conceptually and api-wise: Both which-func and breadcrumb are about the current function, while imenu is about a list of _all_ functions/sections. We could just allow which-func-function to accept a list of function names. In fact, the which-func function of tree-sitter powered python.el already generates a breadcrumb, I just joined all the function names along the path with “/“. > > João > > PS: Eli, I'm CCing you to underline this as just an example of a UI > feature that is requested for Eglot, but belongs somewhere else. In > this case, I believe there is 0 additional integration needed in > eglot.el: it can be realized independently of the backend which feeds > into Imenu (perhaps tree-sitter?) and project.el. I agree, Emacs provides the framework/UI, and tree-sitter/eglot/future magic plug in. Yuan ^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#58431: 29.0.50; [Eglot] Add "breadcrumb.el" feature based on imenu.el/project.el services 2022-10-11 15:38 ` Yuan Fu @ 2022-10-11 23:50 ` João Távora 2022-10-12 6:22 ` Yuan Fu 2023-05-12 13:09 ` João Távora 0 siblings, 2 replies; 12+ messages in thread From: João Távora @ 2022-10-11 23:50 UTC (permalink / raw) To: Yuan Fu; +Cc: eliz, 58431 Yuan Fu <casouri@gmail.com> writes: >> In the original Eglot request, users are requesting this UI feature for >> the Eglot LSP client. But this doesn't have any LSP-specific >> interactions. It can and should be done entirely by using the services >> provided by imenu.el and project.el. >> >> Eglot already integrates with Imenu, so as soon as this hypothetical >> breadcrumb.el is in place, then Eglot users can take advantage of it. >> >> This is similar to which-func.el, which displays the trailing element of >> the breadcrumb in the headerline. Perhaps the breadcrumb feature can be >> thought of as an augmentation of which-func.el's functionality. I don't >> have a strong opinion there. > > I think which-func is closer to breadcrumb conceptually and api-wise: > Both which-func and breadcrumb are about the current function, while > imenu is about a list of _all_ functions/sections. I think there is a slight misunderstanding here. The information stored in imenu is what which-func.el uses by default. See this comment in which-func.el ;; This package prints name of function where your current point is ;; located in mode line. It assumes that you work with the imenu ;; package and `imenu--index-alist' is up to date. Moreover, imenu--index-alist is not a list, but a tree (of which a flat list is a particular case). M-x which-function-mode works for any Eglot-managed buffer, but Eglot doesn't have any code specific to which-func.el. How can this be? Well, Eglot stores the tree information is gets from LSP in Imenu's imenu--index-alist and that information serves many Imenu frontends -- which-func.el being just one of them. Moreover, the breadcrumb that the Eglot user is requesting -- and which I am describing in detail -- also needs information that is owned by project.el, namely the project root. Let's use some M-x artist-mode magic to explain what is in place and what I am proposing. +---+----+ +---------+ +----------+ |eglot.el| |python.el| | ruby.el | +---+----+ +---+-----+ +----+-----+ | | | | | | | v | | +----------+ | +------->| imenu.el |<--------+ +-+--------+ | +--------------+ | | +-------------------+ \->|which-func.el | | |(already working) | | +-------------------+ | | +-------------------+ \->|speedbar.el | | |(also working) | | +-------------------+ | | +-------------------+ \->|... | | +-------------------+ +--------------+ | | project.el | | o-------------------o +--------------+ \->|breadcrumb.el | / |(proposed addition)|<------------ o-------------------o So, Eglot already stores its LSP-gathered information "inside" imenu's data structures using imenu-create-index-function. As does the current python.el, ruby.el, antlr-mode.el, cc-mode and many others when they are used without Eglot. which-func.el get this information from imenu and uses it for the limited purpose of showing only the leaf of the tree where the point is at. breadcrumb.el would function similarly, but instead use it to show the _full path_ of that tree up until the leaf of the tree where the point is at. It would then prepend the path to the file by getting it from project.el. > which-func-function to accept a list of function names. In fact, the > which-func function of tree-sitter powered python.el already generates > a breadcrumb, I just joined all the function names along the path with > “/“. You can use that strategy in your new Python mode, but it seems misguided to me. You'll be supporting which-func.el directly instead of indirectly, thus missing out on other imenu-using client frontends like speedbar, "treemacs", M-x imenu or others. They will not work out-of-the-box with your new mode. Therefore, my advice is that you keep the tree structure you get from tree-sitter intact and stored in imenu--index-alist via imenu-create-index-function -- see the docstring imenu--index-alist -- then let the imenu clients compose a breadcrumb iff they so desire. breadcrumb.el would be such a client, that would work in your tree-sitter powered python mode and in many other contexts. João ^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#58431: 29.0.50; [Eglot] Add "breadcrumb.el" feature based on imenu.el/project.el services 2022-10-11 23:50 ` João Távora @ 2022-10-12 6:22 ` Yuan Fu 2022-10-12 8:30 ` João Távora 2023-05-12 13:09 ` João Távora 1 sibling, 1 reply; 12+ messages in thread From: Yuan Fu @ 2022-10-12 6:22 UTC (permalink / raw) To: João Távora; +Cc: eliz, 58431 > On Oct 11, 2022, at 4:50 PM, João Távora <joaotavora@gmail.com> wrote: > > Yuan Fu <casouri@gmail.com> writes: > >>> In the original Eglot request, users are requesting this UI feature for >>> the Eglot LSP client. But this doesn't have any LSP-specific >>> interactions. It can and should be done entirely by using the services >>> provided by imenu.el and project.el. >>> >>> Eglot already integrates with Imenu, so as soon as this hypothetical >>> breadcrumb.el is in place, then Eglot users can take advantage of it. >>> >>> This is similar to which-func.el, which displays the trailing element of >>> the breadcrumb in the headerline. Perhaps the breadcrumb feature can be >>> thought of as an augmentation of which-func.el's functionality. I don't >>> have a strong opinion there. >> >> I think which-func is closer to breadcrumb conceptually and api-wise: >> Both which-func and breadcrumb are about the current function, while >> imenu is about a list of _all_ functions/sections. > > I think there is a slight misunderstanding here. > > The information stored in imenu is what which-func.el uses by default. > See this comment in which-func.el > > ;; This package prints name of function where your current point is > ;; located in mode line. It assumes that you work with the imenu > ;; package and `imenu--index-alist' is up to date. > > Moreover, imenu--index-alist is not a list, but a tree (of which a flat > list is a particular case). > > M-x which-function-mode works for any Eglot-managed buffer, but Eglot > doesn't have any code specific to which-func.el. How can this be? > Well, Eglot stores the tree information is gets from LSP in Imenu's > imenu--index-alist and that information serves many Imenu frontends -- > which-func.el being just one of them. > > Moreover, the breadcrumb that the Eglot user is requesting -- and which > I am describing in detail -- also needs information that is owned by > project.el, namely the project root. > > Let's use some M-x artist-mode magic to explain what is in place > and what I am proposing. > > +---+----+ +---------+ +----------+ > |eglot.el| |python.el| | ruby.el | > +---+----+ +---+-----+ +----+-----+ > | | | > | | | > | v | > | +----------+ | > +------->| imenu.el |<--------+ > +-+--------+ > | > +--------------+ > | > | +-------------------+ > \->|which-func.el | > | |(already working) | > | +-------------------+ > | > | +-------------------+ > \->|speedbar.el | > | |(also working) | > | +-------------------+ > | > | +-------------------+ > \->|... | > | +-------------------+ +--------------+ > | | project.el | > | o-------------------o +--------------+ > \->|breadcrumb.el | / > |(proposed addition)|<------------ > o-------------------o > > So, Eglot already stores its LSP-gathered information "inside" imenu's > data structures using imenu-create-index-function. As does the current > python.el, ruby.el, antlr-mode.el, cc-mode and many others when they are > used without Eglot. > > which-func.el get this information from imenu and uses it for the limited > purpose of showing only the leaf of the tree where the point is at. > > breadcrumb.el would function similarly, but instead use it to show the > _full path_ of that tree up until the leaf of the tree where the point > is at. It would then prepend the path to the file by getting it from > project.el. > >> which-func-function to accept a list of function names. In fact, the >> which-func function of tree-sitter powered python.el already generates >> a breadcrumb, I just joined all the function names along the path with >> “/“. > > You can use that strategy in your new Python mode, but it seems > misguided to me. You'll be supporting which-func.el directly instead of > indirectly, thus missing out on other imenu-using client frontends like > speedbar, "treemacs", M-x imenu or others. They will not work > out-of-the-box with your new mode. > > Therefore, my advice is that you keep the tree structure you get from > tree-sitter intact and stored in imenu--index-alist via > imenu-create-index-function -- see the docstring imenu--index-alist -- > then let the imenu clients compose a breadcrumb iff they so desire. > > breadcrumb.el would be such a client, that would work in your > tree-sitter powered python mode and in many other contexts. > > João Thanks for your explanation! I didn’t know which-func can just use imenu--index-alist. I already have support for imenu, just need to let which-func do its thing. What you said for breakcumb.el makes total sense. It sounds pretty straightforward, just get file path from project.el and function path from imenu and put them together. I can work on it later if no one come around and adopt it, I’ve got a lot of stuff on my plate already ;-) Yuan ^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#58431: 29.0.50; [Eglot] Add "breadcrumb.el" feature based on imenu.el/project.el services 2022-10-12 6:22 ` Yuan Fu @ 2022-10-12 8:30 ` João Távora 0 siblings, 0 replies; 12+ messages in thread From: João Távora @ 2022-10-12 8:30 UTC (permalink / raw) To: Yuan Fu; +Cc: eliz, 58431 Yuan Fu <casouri@gmail.com> writes: > Thanks for your explanation! I didn’t know which-func can just use > imenu--index-alist. I already have support for imenu, just need to let > which-func do its thing. Yup. > What you said for breakcumb.el makes total sense. It sounds pretty > straightforward, just get file path from project.el and function path > from imenu and put them together. Yes, that's exactly it. It should be reasonably straightforward yes. Maybe, to make a fancy breadcrumb, with icons like lsp-mode's we will need some small augmentations to imenu--index-alist, but I don't see that as a big difficulty. > I can work on it later if no one > come around and adopt it, I’ve got a lot of stuff on my plate already > ;-) Same here. Drop a line a line if start working on this, so we don't duplicate each other's work. João ^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#58431: 29.0.50; [Eglot] Add "breadcrumb.el" feature based on imenu.el/project.el services 2022-10-11 23:50 ` João Távora 2022-10-12 6:22 ` Yuan Fu @ 2023-05-12 13:09 ` João Távora 2023-05-17 21:31 ` Yuan Fu 1 sibling, 1 reply; 12+ messages in thread From: João Távora @ 2023-05-12 13:09 UTC (permalink / raw) To: Yuan Fu, Jeremy Bryant, Daniel Martín, Adam Porter; +Cc: eliz, 58431 On Wed, Oct 12, 2022 at 12:49 AM João Távora <joaotavora@gmail.com> wrote: > Let's use some M-x artist-mode magic to explain what is in place > and what I am proposing. > > +---+----+ +---------+ +----------+ > |eglot.el| |python.el| | ruby.el | > +---+----+ +---+-----+ +----+-----+ > | | | > | | | > | v | > | +----------+ | > +------->| imenu.el |<--------+ > +-+--------+ > | > +--------------+ > | > | +-------------------+ > \->|which-func.el | > | |(already working) | > | +-------------------+ > \->|... | > | +-------------------+ +--------------+ > | | project.el | > | o-------------------o +--------------+ > \->|breadcrumb.el | / > |(proposed addition)|<------------ > o-------------------o > I've now created https://github.com/joaotavora/breadcrumb with exactly this architecture. Suggest everyone interested check it out. Propose we add it to ELPA. It is not Eglot-specific so it needn't depend on Eglot (but I've tested it with Eglot and it works well). João ^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#58431: 29.0.50; [Eglot] Add "breadcrumb.el" feature based on imenu.el/project.el services 2023-05-12 13:09 ` João Távora @ 2023-05-17 21:31 ` Yuan Fu 0 siblings, 0 replies; 12+ messages in thread From: Yuan Fu @ 2023-05-17 21:31 UTC (permalink / raw) To: João Távora Cc: Adam Porter, Jeremy Bryant, eliz, 58431, Daniel Martín > On May 12, 2023, at 6:09 AM, João Távora <joaotavora@gmail.com> wrote: > > On Wed, Oct 12, 2022 at 12:49 AM João Távora <joaotavora@gmail.com> wrote: > >> Let's use some M-x artist-mode magic to explain what is in place >> and what I am proposing. >> >> +---+----+ +---------+ +----------+ >> |eglot.el| |python.el| | ruby.el | >> +---+----+ +---+-----+ +----+-----+ >> | | | >> | | | >> | v | >> | +----------+ | >> +------->| imenu.el |<--------+ >> +-+--------+ >> | >> +--------------+ >> | >> | +-------------------+ >> \->|which-func.el | >> | |(already working) | >> | +-------------------+ > >> \->|... | >> | +-------------------+ +--------------+ >> | | project.el | >> | o-------------------o +--------------+ >> \->|breadcrumb.el | / >> |(proposed addition)|<------------ >> o-------------------o >> > > I've now created https://github.com/joaotavora/breadcrumb with > exactly this architecture. Suggest everyone interested > check it out. Propose we add it to ELPA. It is not > Eglot-specific so it needn't depend on Eglot (but I've tested > it with Eglot and it works well). Looks good! It doesn’t seem possible for a major mode to give breadcrumb a custom “imenu-alist” that’s different from what it gives to Imenu? It might be useful because it’s common for major modes to add a category layer in the imenu alist, like Function > xxx and Class > xxx instead of xxx along; and there might be other reasons the major mode want the breadcrumb to be different from Imenu. In general it might be useful for breadcrumb to have it’s own interface, with project and Imenu adapters come with it out-of-the-box. Yuan ^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#58431: 29.0.50; [Eglot] Add "breadcrumb.el" feature based on imenu.el/project.el services 2022-10-11 9:17 bug#58431: 29.0.50; [Eglot] Add "breadcrumb.el" feature based on imenu.el/project.el services João Távora 2022-10-11 15:38 ` Yuan Fu @ 2023-04-08 19:47 ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-04-18 18:10 ` bug#58431: 29.0.50; [Eglot] Add "breadcrumb.el" feature based, " Adam Porter 2 siblings, 0 replies; 12+ messages in thread From: Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-04-08 19:47 UTC (permalink / raw) To: João Távora; +Cc: eliz, 58431 João Távora <joaotavora@gmail.com> writes: > > This is similar to which-func.el, which displays the trailing element of > the breadcrumb in the headerline. Perhaps the breadcrumb feature can be > thought of as an augmentation of which-func.el's functionality. I don't > have a strong opinion there. I see this feature as an augmentation of which-func.el. The purpose is to show what is the current defun, but the how and where (mode line or header line) is a configuration option. In recent versions of IDEs and text editors another header line UI to show the current function is getting popular, something like our old Sticky Function mode. As with this breadcrumb UI, I think its logic belongs more to which-func-mode.el and shouldn't be coupled to Semantic. ^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#58431: 29.0.50; [Eglot] Add "breadcrumb.el" feature based, on imenu.el/project.el services 2022-10-11 9:17 bug#58431: 29.0.50; [Eglot] Add "breadcrumb.el" feature based on imenu.el/project.el services João Távora 2022-10-11 15:38 ` Yuan Fu 2023-04-08 19:47 ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-04-18 18:10 ` Adam Porter 2023-04-18 18:26 ` João Távora 2 siblings, 1 reply; 12+ messages in thread From: Adam Porter @ 2023-04-18 18:10 UTC (permalink / raw) To: 58431; +Cc: Eli Zaretskii, João Távora, Daniel Martín Daniel Martín <mardani29 <at> yahoo.es> writes: >> This is similar to which-func.el, which displays the trailing element of >> the breadcrumb in the headerline. Perhaps the breadcrumb feature can be >> thought of as an augmentation of which-func.el's functionality. I don't >> have a strong opinion there. > > I see this feature as an augmentation of which-func.el. The purpose is > to show what is the current defun, but the how and where (mode line or > header line) is a configuration option. > > In recent versions of IDEs and text editors another header line UI to > show the current function is getting popular, something like our old > Sticky Function mode. As with this breadcrumb UI, I think its logic > belongs more to which-func-mode.el and shouldn't be coupled to Semantic. FWIW, this sounds similar to the topsy.el library I published on MELPA a couple of years ago. It aims to provide similar (or better) functionality than semantic-stickyfunc-mode without using Semantic. https://github.com/alphapapa/topsy.el If any of its code would be helpful, I'd be glad to "donate" it to ELPA/Emacs. ^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#58431: 29.0.50; [Eglot] Add "breadcrumb.el" feature based, on imenu.el/project.el services 2023-04-18 18:10 ` bug#58431: 29.0.50; [Eglot] Add "breadcrumb.el" feature based, " Adam Porter @ 2023-04-18 18:26 ` João Távora 2023-04-20 4:27 ` Adam Porter 0 siblings, 1 reply; 12+ messages in thread From: João Távora @ 2023-04-18 18:26 UTC (permalink / raw) To: Adam Porter; +Cc: Eli Zaretskii, 58431, Daniel Martín [-- Attachment #1: Type: text/plain, Size: 832 bytes --] On Tue, Apr 18, 2023 at 7:10 PM Adam Porter <adam@alphapapa.net> wrote: > FWIW, this sounds similar to the topsy.el library I published on MELPA a > couple of years ago. It aims to provide similar (or better) > functionality than semantic-stickyfunc-mode without using Semantic. Had a look, but doesn't seem to work with Imenu directly. That's a goal here, because it makes this work for Eglot and also any other non-Eglot client that already defines an imenu. Also seems to have a slightly different goal. The goal here, is for the headerline to show the current position in terms of the intervals it intersects in the imenu tree, which may be a deep hierarchical tree in some languages. Here's what I've come up with: it's fresh out of the oven :-) (meaning probably buggy, but hopefully hot) João [-- Attachment #2: breadcrumb.el --] [-- Type: text/x-emacs-lisp, Size: 7109 bytes --] ;;; breadcrumb.el --- imenu-based breadcrumb paths -*- lexical-binding: t; -*- ;; Copyright (C) 2023 João Távora ;; Author: João Távora <joaotavora@gmail.com> ;; Version: 0.0.1alpha ;; Keywords: ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: ;;; ;;; M-x breadcrumb-mode in any buffer where you have imenu capability ;;; (which are a lot of them, though said capability varies) ;;; ;;; Works even better for a recent Eglot (I think Eglot 1.14+), ;;; because it adds extra region info the the traditional imenu ;;; struct, `imenu--index-alist'. But there should be interesting ;;; stuff in older Eglot too. ;;; ;;; This _should_ be faster than which-func.el due to good caching ;;; strategies. But I haven't measured. ;;; ;;; This also takes care not to over-call `imenu-make-index-alist', ;;; which could be slow. The variable `breadcrumb-idle-delay' ;;; controls that. ;;; ;;; Relies a lot on this double-dashed imenu function, but that is ;;; really not a double-dashed function. ;;; ;;; Code: (require 'cl-lib) (require 'imenu) (cl-defun bc-bisect (a x &key (from 0) (to (length a)) key from-end) "Compute index to insert X in sequence A, keeping it sorted. If X already in A, the resulting index is the leftmost such index, unless FROM-END is t. KEY is as usual in other CL land." (cl-macrolet ((search (from-end key) `(cl-loop while (< from to) for mid = (/ (+ from to) 2) for p1 = (elt a mid) for p2 = ,(if key `(funcall key p1) `p1) if (,(if from-end '< '<=) x p2) do (setq to mid) else do (setq from (1+ mid)) finally return from))) (if from-end (if key (search t key) (search t nil)) (if key (search nil key) (search nil nil))))) (defun bc--path-1 (index-alist pos) (cl-labels ((search (nodes &optional path) (cl-loop for n in nodes for reg = (get-text-property 0 'breadcrumb-region (car n)) when (<= (car reg) pos (cdr reg)) return (search (cdr n) (cons (car n) path)) finally (cl-return path)))) (nreverse (search index-alist)))) (defvar-local bc--path-2-cache nil) (defun bc--path-2 (index-alist pos) (cl-labels ((dfs (n &optional path) (setq path (cons (car n) path)) (if (consp (cdr n)) (mapc (lambda (n) (dfs n path)) (cdr n)) (setq bc--path-2-cache (vconcat bc--path-2-cache `[,(cons (cdr n) path)]))))) (unless bc--path-2-cache (mapc #'dfs index-alist) (setq bc--path-2-cache (cl-sort bc--path-2-cache #'< :key #'car))) (unless (< pos (car (aref bc--path-2-cache 0))) (let ((res (bc-bisect bc--path-2-cache pos :key #'car :from-end t))) (unless (zerop res) (reverse (cdr (elt bc--path-2-cache (1- res))))))))) (defun bc-path (index-alist pos) "Get breadcrumb for position POS given INDEX-ALIST." (if (get-text-property 0 'breadcrumb-region (caar index-alist)) (bc--path-1 index-alist pos) (bc--path-2 index-alist pos))) (defvar-local bc--last-update-tick 0) (defvar bc--header-line-key [header-line mouse-1]) (defun bc--format-node (p) (let ((reg (get-text-property 0 'breadcrumb-region p))) (if reg (propertize p 'mouse-face 'header-line-highlight 'help-echo "Go here" 'keymap (let ((m (make-sparse-keymap))) (define-key m bc--header-line-key (lambda (&rest _e) (interactive) (push-mark) (goto-char (car reg)))) m)) p))) (defvar bc-idle-time 1 "Control idle time before requesting new breadcrumbs.") (defvar-local bc--idle-timer nil) (defun bc--alist () (let ((nochangep (= (buffer-chars-modified-tick) bc--last-update-tick)) (buf (current-buffer))) (cond ((and nochangep imenu--index-alist) imenu--index-alist) (t (setq bc--last-update-tick (buffer-chars-modified-tick)) (when bc--idle-timer (cancel-timer bc--idle-timer)) (setq bc--idle-timer (run-with-idle-timer bc-idle-time nil (lambda () (when (buffer-live-p buf) (with-current-buffer buf (setq bc--last-update-tick (buffer-chars-modified-tick)) (let ((non-essential t) (imenu-auto-rescan t)) (imenu--make-index-alist t) (setq bc--path-2-cache nil) (force-mode-line-update t))))))))))) (defun bc-path-for-header-line () (cl-loop with alist = (bc--alist) for (p . more) on (bc-path alist (point)) collect (bc--format-node p) when more collect " > ")) (defvar bc-header-line-format '(:eval (bc-path-for-header-line))) (define-minor-mode bc-mode "Header lines with breadcrumbs." :init-value nil (if bc-mode (add-to-list 'header-line-format bc-header-line-format) (setq header-line-format (delq bc-header-line-format header-line-format)))) (defun bc-jump () "Like M-x `imenu', but breadcrumb-powered." (interactive) (let (cands choice) (cl-labels ((fmt (strs) (mapconcat #'identity strs " > ")) (dfs (nodes &optional path) (cl-loop for n in nodes for newpath = (cons (car n) path) for pos = (or (car (get-text-property 0 'breadcrumb-region (car n))) (and (number-or-marker-p (cdr n)) (cdr n))) when pos do (push (cons (fmt (reverse newpath)) pos) cands) do (dfs (cdr n) newpath)))) (imenu--make-index-alist) (dfs imenu--index-alist) (unless cands (user-error "Sorry, no breadcrumb items to jump to.")) (setq choice (cdr (assoc (completing-read "Index item? " cands nil t) cands #'string=))) (push-mark) (goto-char choice)))) (provide 'breadcrumb) ;;; breadcrumb.el ends here ;; Local Variables: ;; read-symbol-shorthands: (("bc-" . "breadcrumb-")) ;; End: ^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#58431: 29.0.50; [Eglot] Add "breadcrumb.el" feature based, on imenu.el/project.el services 2023-04-18 18:26 ` João Távora @ 2023-04-20 4:27 ` Adam Porter 2023-04-20 9:22 ` João Távora 0 siblings, 1 reply; 12+ messages in thread From: Adam Porter @ 2023-04-20 4:27 UTC (permalink / raw) To: João Távora; +Cc: Eli Zaretskii, 58431, Daniel Martín Hi João, On 4/18/23 13:26, João Távora wrote: > On Tue, Apr 18, 2023 at 7:10 PM Adam Porter <adam@alphapapa.net> wrote: > >> FWIW, this sounds similar to the topsy.el library I published on MELPA a >> couple of years ago. It aims to provide similar (or better) >> functionality than semantic-stickyfunc-mode without using Semantic. > > Had a look, but doesn't seem to work with Imenu directly. That's a goal > here, because it makes this work for Eglot and also any other non-Eglot > client that already defines an imenu. Yes, it doesn't use any Imenu functions currently. It's an interesting idea, though. > Also seems to have a slightly different goal. The goal here, is for > the headerline to show the current position in terms of the intervals > it intersects in the imenu tree, which may be a deep hierarchical > tree in some languages. For most modes, that's true. For buffers using `magit-section-mode', the `topsy--magit-section' function does return a breadcrumbs-style list that shows the hierarchy of sections. Also, my other package that's just for Org, org-sticky-header, does show a breadcrumbs-style list of ancestor headings. > Here's what I've come up with: it's fresh out of the oven :-) > > (meaning probably buggy, but hopefully hot) Thanks. I tried it, and I'm not sure if it's doing what you intend, but it doesn't seem to do what I need; that is, it doesn't show the beginning of the top-level form that encloses the line at the top of the window. ^ permalink raw reply [flat|nested] 12+ messages in thread
* bug#58431: 29.0.50; [Eglot] Add "breadcrumb.el" feature based, on imenu.el/project.el services 2023-04-20 4:27 ` Adam Porter @ 2023-04-20 9:22 ` João Távora 0 siblings, 0 replies; 12+ messages in thread From: João Távora @ 2023-04-20 9:22 UTC (permalink / raw) To: Adam Porter; +Cc: Eli Zaretskii, 58431, Daniel Martín Adam Porter <adam@alphapapa.net> writes: > For most modes, that's true. For buffers using `magit-section-mode', > the `topsy--magit-section' function does return a breadcrumbs-style > list that shows the hierarchy of sections. Also, my other package > that's just for Org, org-sticky-header, does show a breadcrumbs-style > list of ancestor headings. I don't use Magit. If its buffer support Imenu in any way, then breadcrumb should do something. >> Here's what I've come up with: it's fresh out of the oven :-) >> (meaning probably buggy, but hopefully hot) > > Thanks. I tried it, and I'm not sure if it's doing what you intend, > but it doesn't seem to do what I need; that is, it doesn't show the > beginning of the top-level form that encloses the line at the top of > the window. Its impossible for me to know what you are trying to do with it doing with this description. Is this in a file? Can you show the file? If it's not a file, can you describe how I can test what you're testing? João ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2023-05-17 21:31 UTC | newest] Thread overview: 12+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2022-10-11 9:17 bug#58431: 29.0.50; [Eglot] Add "breadcrumb.el" feature based on imenu.el/project.el services João Távora 2022-10-11 15:38 ` Yuan Fu 2022-10-11 23:50 ` João Távora 2022-10-12 6:22 ` Yuan Fu 2022-10-12 8:30 ` João Távora 2023-05-12 13:09 ` João Távora 2023-05-17 21:31 ` Yuan Fu 2023-04-08 19:47 ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-04-18 18:10 ` bug#58431: 29.0.50; [Eglot] Add "breadcrumb.el" feature based, " Adam Porter 2023-04-18 18:26 ` João Távora 2023-04-20 4:27 ` Adam Porter 2023-04-20 9:22 ` João Távora
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.