Subject: bug#71367: 30.0.50; ELPA package breadcrumb causes Emacs freeze when editing json file

From: Tassilo Horn <[email-masked]>
Date: Thu, 06 Jun 2024 16:29:49 +0200

João Távora <[email-masked]> writes:

>> I understand all that.  My point is that, given how little we use
>> vectors in our Lisp code, having to implement that in one or two
>> places is not a big deal, and doesn't necessarily mean we need a
>> general-purpose primitive.
>
> I just said if someone comes with a breadcrumb.el solution, I'd like
> to see it well encapsulated as an ADT, not mixed with the graph
> algorithm.  I don't care if Emacs keeps skipping this basic util for
> whatever reason.

Before turning to algorithm optimizations, I think there is some simpler
bug somewhere.  I wanted to understand how the graph imenu--in-alist (or
what (breadcrumb--ipath-alist) returns) looks like, so I've created a
simple test.json file:

--8<---------------cut here---------------start------------->8---
{
  "root": [
    {
      "foo": 1,
      "bar": "test1"
    },
    {
      "foo": 2,
      "bar": "test2"
    }
  ]
}
--8<---------------cut here---------------end--------------->8---

At the same time, I've had my sample mirrorstatus.json open and did M-:
stuff like M-: (pp (breadcrumb--ipath-alist)) here and there to get some
printed representations.  And somehow now my imenu--in-alist and
breadcrumb--ipath-plain-cache values in the test.json buffer contains
markers in both test.json AND mirrorstatus.json!

--8<---------------cut here---------------start------------->8---
imenu--index-alist is a variable defined in ‘imenu.el’.
...
Value:
(("root"
  (#(" " 0 1
     (breadcrumb-siblings #1=
                          ((#("active" 0 1 (breadcrumb-siblings #1#))
                            . #<marker at 137 in mirrorstatus.json>)
                           (#("completion_pct" 0 1 (breadcrumb-siblings #1#))
                            . #<marker at 159 in mirrorstatus.json>)
                           (#("country" 0 1 (breadcrumb-siblings #1#))
                            . #<marker at 188 in mirrorstatus.json>)
                           (#("country_code" 0 1 (breadcrumb-siblings #1#))
                            . #<marker at 218 in mirrorstatus.json>)
                           (#("delay" 0 1 (breadcrumb-siblings #1#)) . #<marker
                            at 246 in mirrorstatus.json>)
  ...
   . #<marker at 5 in test.json>)
  ("foo" . #<marker at 27 in test.json>) ("bar" . #<marker at 43 in test.json>)
  ("foo" . #<marker at 77 in test.json>) ("bar" . #<marker at 93 in test.json>)))
Local in buffer test.json; global value is nil
--8<---------------cut here---------------end--------------->8---

That's surely now how its supposed to be.  But I don't see how one can
get there.  I can only imagine a timer acting on the wrong buffer but
the breadcrumb--idle-timer is buffer-local and the timer function
ensures it runs on the buffer the timer was activated for...

Bye,
Tassilo