Subject: Re: bug#62029: 29.0.60; Allow users to customize eldoc buffer separator

From: João Távora <[email-masked]>
Date: Sat, 15 Apr 2023 10:41:50 +0100

Dmitry Gutov <[email-masked]> writes:

> On 14/04/2023 03:04, João Távora wrote:
>> Dmitry Gutov <[email-masked]> writes:
>> 
>>> On 14/04/2023 02:01, João Távora wrote:
>> 
>>>> And you liked the result with no problems?  If so, that's a good
>>>> datapoint.  You will have seen "bouncing" of the echo area, I presume.
>>>
>>> I'm still vague on what your patch to elisp-mode.el does, but at least
>>> I'm not seeing any particular breakage.
>> My patch to elisp-mode.el that I showed Yuan Fu makes the two
>> function
>> elisp-eldoc-funcall and elisp-eldoc-var-docstring send very rich
>> information to the *eldoc* buffer, but only summarized information to
>> the echo area, via the new :echo option in newer ElDoc 1.14.0.  This
>> allows users who have eldoc-documentation-compose as the strategy to
>> have the buffer on the side and see it update with full docstrings of
>> the things they are navigating, organized with a suitable separator.
>> This is why I suggested you try M-x eldoc-doc-buffer along with your
>> tests.
>
> Okay, I see it now. I think it doesn't look optimal, for example, when
> point is on a variable, it lists just the name and the docstring. C-h
> v has a much richer display which might be worth reusing here (or more
> parts of it, at least). But those are details.

Yes, yes.  The problem is how to get that rich content.  The defun case
has a describe-function-1 helper, but sadly no such helper for
variables.  I could just invoke help.el wholesale, as company does.  But
that has a bug that it stomps in the *Help* buffer.  I agree it's just
details.

> To sum up, if I may, you have reached the conclusion that the doc
> buffer should look different, and its text needs to be produced 
> differently, than the notifications in the echo area. (*)

They are usually produced in the same way, and ideally should.  Only the
display is different according to the viewport.  The echo area is a an
extreme case of a very constrained port.  But the plan for ElDoc is for
backends to send even more structured text to eldoc-display-functions
and have them do any kind of markup, fontification, etc.
eldoc-echo-area-display uses :echo if available now, but the main thing
I fixed in ElDoc 1.14 was its sharing and cutting of the same *eldoc*
buffer.  Each display function should have its own working space.

>>>> Elisp
>>>> in de facto an exception.
>>>
>>> Do we have some sort of statistics or overview on that issue? E.g. if
>>> we take only eldoc functions that are relatively old-ish (crossing out
>>> lsp-mode and eglot, I mean).
>> I'm not aware of many.  SLY has a eldoc-documentation-function that
>> prints multiline content, and SLY users have never complained about it.
>
> At certain point users start to self-select, especially if they don't
> know how things could be better/different. As evidenced just by the
> other bug report with the blinkage in the echo area which should be
> apparent to anybody with graphical Emacs.
>
> So "users of package xxx don't complain about yyy" is not as strong an
> argument as "almost all packages out there use approach yyy".

I don't know to be honest.  And then not all packages are equally
popular.  

> I've done it before, and the results definitely aren't representative
> of the whole community (like 10 responses or so), but they has been
> convincing enough for me to abandon the particular idea I had. ;-(

The very vast majority of users don't care, and will accept the
developers criteria as to what he or she chose is best.  As for the ones
that do care, whether with positive or negative feelings, you only hear
about a minority of them, and always biased to the negative.  So as your
little experiment showed you're walking in a foggy swamp, with a
blindfold, inside a box.

> You could have a different result, though.

Doubt it.

>>> Or, if we change the default value of eldoc-documentation-strategy,
>>> someone with the diametrically opposite preferences from you would
>>> customize eldoc-echo-area-use-multiline-p to 1 and have that work in
>>> all modes. Or set it to 2, to have some middle ground. Etc.
>> OK I see.  Well I don't think it's a tragedy to do that with
>> emacs-lisp-mode-hook instead.  We're only talking about the people
>> familiar with "new" ElDoc features, which is arguably a very small
>> group, because -- unless they are using my patch to Yuan Fu -- these
>> features aren't yet very developed in Elisp-mode.  So the likelyhood of
>> that backlash is very low.
>
> The patch will make it in soon enough, right? I'm not sure I
> understand this argument.

What patch.  I was describing the risks of simply setting
eldoc-echo-area-use-multiline-p to 1 in elisp mode, which are very
small.

>> If I understand your preference for "put it closer to the input",
>> that'd
>> just be another function in eldoc-display-functions.  Yuan Fu's
>> eldoc-box is such an example.
>
> Might be. If signature info is annotated with a particular key, which
> that display function will pick up. But I'm not sure how to make it so
> that the other display functions ignore it.

You start passing structured text.  See the docstring of
eldoc-documentation-functions:

    To call the CALLBACK function, the hook function must pass it an
    obligatory argument DOCSTRING, a string containing the
    documentation, followed by an optional list of arbitrary
    keyword-value pairs of the form (:KEY VALUE :KEY2 VALUE2...).
    The information contained in these pairs is understood by members
    of `eldoc-display-functions', allowing the
    documentation-producing backend to cooperate with specific
    documentation-displaying frontends.

> Further, though, the siginfo could become a structured piece of data,
> rather than a string (e.g. I recall an interface where the user could
> switch between overloads using arrow keys). That is unlikely to fit
> eldoc's model at all.

Yes, ElDoc is a "at point documentation system", it's not a completion
system.

> It does not bootstrap, unfortunately. Or otherwise build:
>
>   load("progmodes/elisp-mode")
>   load("loadup.el")
> Eager macro-expansion failure: (wrong-type-argument listp t)
>
> And that's in a clean new worktree.

Oof that's bad.  My fault?  I'll have a look.

>>>> Starting from there, we could
>>>> modify it so that this e-d-function only echoes and doesn't send
>>>> anything to the *eldoc* buffer, while elisp-eldoc-fucall and
>>>> elisp-eldoc-var-docstring to the inverse.
>>>
>>> That reminds me of some of my older messages where I insisted the
>>> eldoc-buffer thingy should have its own separate hook. Oh well.
>> To be clear, what I'm thinking of is to have _3/4_ functions in
>> elisp-mode's e-d-functions
>>    elisp-eldoc-funcall
>>    elisp-eldoc-var-docstring
>>    elisp-eldoc-failover-funcal-to-var
>
> Note that this one is easy enough to do for Elisp because both
> functions are synchronous and you can determine the success of
> elisp-eldoc-funcall by its return value. Not so easy to do for eldoc
> functions in general (e.g. to do a similar failover for Eglot).

That's impossible in general.  The thing you're waiting to fail over
from might never arrive.  That's why member of eldoc-doc-functions are
supposed to make an educated promise that they will call the callback in
the return value.  If that promise is upheld, it's not much harder to
combine to eldoc-documentation-functions into one.

(defun eldoc-race (fns) "Combine FNS into a race"
  (lambda (callback)
    (let* (winner-found
           (newcb (lambda (&rest r)
                    (unless winner-found
                      (apply callback r)
                      (setq winner-found t)))))
      (mapc (lambda (f) (funcall f newcb)) fns))))

Obviously you can have a million different rules for these "races".

In practice, I've never seen someone discontent with the default
eldoc-documentation-compose though.  Saw lots of complaints about "echo
are flooding" and "enormous echo areas".  I recommended
eldoc-echo-area-use-multiline-p be used, and people were content.  But
it wasn't very clean, so what we have is cleaner now.

>>    flymake-eldoc-function (optional, depends on Flymake mode)
>> By default, in Emacs -Q, the first 2 send _nothing_ to echo (via the
>> new
>> ElDoc :echo feature) are but send rich info to other
>> eldoc-display-functions.  The special
>> elisp-eldoc-failover-funcall-to-var sends _only_ to the echo area (and
>> only ever one line).
>
> Nice. Let me get back to this later down in this email (**).

It's nice but not perfect.  Nothing can be.  If you look closely,
there's just as much backward compatibility breakage as there is by
changing e-e-a-use-multiline-p to t in elisp-mode.  I.e. a happy user of
eldoc-documentation-compose today will be equally disappointed tomorrow
(she won't see funcall and variable together as usual).  She will also
have to do changes to her config to get that back.

And this second idea of mine is way, waaay more complicated, than the
first.  And just for the sake of not stomping on a user customizable
variable which, which would have the same (very minor) negative effect,
in fact I think _exactly the same_.

And this second idea of mine yet to be put into code;-)

> Perhaps the former would reuse the existing set of
> combinator/strategies, [...]
> This separation could still [...]
> I'm not going to bother with a patch because backward compatibility,
> and blah, 

Yes, I understand this, but the consequence downside is that your case
is weakened because other brains can't see the advantages as clearly as
your brain does.  And all brains make mistakes.  Code doesn't.

> and the current approach can obviously function too, though
> in a more complicated way.

IMO, that can only be asserted when comparing the two things side by
side, with actual examples.  Frequently some things are easy to do in
one approach and harder in the competing approach, and vice versa.  In
my brain it is your solution which _sounds_ way more complicated.  The
key word is "sound" which I have to use because I'm hearing words inside
my brain as I read your writing.  I'm not seeing your solution function
in front of me, and described in non-ambiguous Elisp language with
working examples.

João