unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: "João Távora" <joaotavora@gmail.com>
To: Dmitry Gutov <dmitry@gutov.dev>
Cc: 72705@debbugs.gnu.org
Subject: bug#72705: 31.0.50; eglot--dumb-tryc Filters out too much
Date: Thu, 22 Aug 2024 17:59:01 +0100	[thread overview]
Message-ID: <87o75kwl2i.fsf@gmail.com> (raw)
In-Reply-To: <06cfce49-33ff-41a2-b999-469c4a0009c0@gutov.dev> (Dmitry Gutov's message of "Thu, 22 Aug 2024 03:41:57 +0300")

Dmitry Gutov <dmitry@gutov.dev> writes:

> Like with the previous discussions about Eglot in Emacs 29, I think
> there will be a lot of users who just use the version of it that comes
> with the release, without upgrading.

Hopefully upgrading should be a matter of M-x eglot-upgrade-eglot.

But no problem on my side.  In a separate "don't merge" commit, look
into editing the etc/EGLOT-NEWS there which I've already bumped to
1.17.30 (the version of Eglot to be bundled with Emacs 30).  I'll then
copy that text to master eventually and release 1.17 to GNU Elpa.

>> Unfortunately, if the the two ints were named "foo_bar_1" and
>> "foo_bar_2" it would also complete to foo_bar_, which is wrong in the
>> general case, since that text is not a fully formed completion.
>> exit-function cannot run here.
>
> Is it really a problem?

Yes.  Start 'clangd --completion-style=detailed' in this thingy.cpp C++
file:

   int foobar(int x, char c) {
     return x + c;
   }
    
   int foobar(int x, float f) {
     return x + f;
   }
    
   int main() {
     foob<cursor here>
   }

if you press C-M-i here this will expand to the partial 'foobar(int x, '
which doesn't make C/C++ syntactic sense in that context.  Emacs is just
inserting the LSP "label", which as the name implies, is just for
displaying, not for inserting.  The goal of these two completions is to
expand a snippet and the snippet can only be expanded through the exit
function.  Even if we complexified Eglot's capf to insert the
'insertText' instead of the 'label' (assuming it existed), we'd be
inserting a partial snippet skeleton, even more nonsensical in C/C++.

> completing to 'foo_bar_' keeps the popup active, so I just press RET
> to pick the first completion.

With the above 'foobar(int x, ' example and with bare C-M-i it's even
worse: it's hard (if not impossible) to complete to the full completion
and thus get the desired snippet expansion because the common prefix of
both completion labels ends with a space.

> It seems to me that performing *some* completion is better than always
> returning the original input, isn't it?

No, not always.  LSP just wasn't thought with the "partial completion"
scenario in mind.

> Do you have an example of a language server and a scenario where this
> becomes a problem?

The above.

>> The current state does not do this, and chooses one of the two
>> completions indiscrimately.  This is, I think, the original bug you
>> reported here.  So this is clearly a win.  To underline it and defend
>> against regresison, I suggest to also assert that the *Completions*
>> buffer popped up.
>
> Sure.

Great.

>> Though, maybe not going so far as asserting the there
>> are exactly those two completions in that order -- doing it
>> "graphically" might prove too brittle.
>
> An alternative might be to use a completion-all-completions call, to
> assert the full list of completions. Or some completions that are in
> it anyway.

Yes, I generally prefer "end-to-end" tests using interactive interfaces.
So unless you're duplicating the test I think this part should be
skipped.  But your call.

>> +(ert-deftest eglot-test-try-completion-inside-symbol ()
>> +  "Test completion table inside symbol, with only prefix matching."
>> +  (skip-unless (executable-find "clangd"))
>> +  (eglot--with-fixture
>> +      `(("project" . (("coiso.c" .
>> +                       ,(concat
>> +                         "int foobar;"
>> +                         "int main() {foo123")))))
>> +    (with-current-buffer
>> +        (eglot--find-file-noselect "project/coiso.c")
>> +      (eglot--wait-for-clangd)
>> +      (goto-char (- (point-max) 3))
>> +      (should
>> +       (equal
>> +        '("foo123" . 3)
>> +        (completion-try-completion
>> +         "foo123"
>> +         (nth 2 (eglot-completion-at-point)) nil 3))))))
>> I don't understand the point of this last test.  Are you checking
>> that
>> nothing changes?  What are you guarding against?
>
> With the input, I'm describing the actual prefix and suffix that get
> used. It might help someone who comes later to understand this
> separate case. Indeed "nothing happens", it's just that something did
> happen with the previous version of my patch, and we're testing
> against that.

Fine.  So maybe be a little bit more explicit in the comment or
docstring about what you _don't_ want to happen.  AFAIU, you don't want
'foobar123' or 'foobar' to be the result of that completion.

> Might be more interesting to have a similar example where the prefix
> changes while the (non-emtpy) suffix stays the same, but I think we
> aren't going to support this in this c-style.
>
>> Finally, an interesting test could be the rust-analyzer one from the
>> issue 1339 issue, which starts with.
>> fn main() {
>>      let v: usize = 1;
>>      1234.1234567890
>> }
>> I've manually checked that neither the v.c1234.12345676890 nor the
>> v.count_on1234.1234567890 case has regressed.
>
> Yep, that's the one I fixed in the last revision.
>
> It's the same case as '("foo123" . 3) in the test above, isn't it?

I don't think so.  In a rust-analyzer hello world (which you can make
with cargo init, if I'm not mistaken), both

   v.c<cursor>1234.12345676890
   v.count_on<cursor>1234.12345676890

should expand to

   v.count_ones()<cursor>.1234567890

In the first case, you'll have to manually select "count_ones" from the
completions buffer.  The expansion and removal of the 1234 happens via
LSP text edits, which are enacte by the :exit-function.  This scenario
wasn't working a while ago and I'd like to protect it against
regression.

João





  reply	other threads:[~2024-08-22 16:59 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-08-19  1:51 bug#72705: 31.0.50; eglot--dumb-tryc Filters out too much Dmitry Gutov
2024-08-19  9:22 ` João Távora
2024-08-19 11:39   ` Dmitry Gutov
2024-08-19 12:59     ` João Távora
2024-08-20  2:08       ` Dmitry Gutov
2024-08-20  9:40         ` João Távora
2024-08-21  0:30           ` Dmitry Gutov
2024-08-21 16:52             ` João Távora
2024-08-22  0:41               ` Dmitry Gutov
2024-08-22 16:59                 ` João Távora [this message]
2024-08-22 23:16                   ` Dmitry Gutov
2024-08-23 10:23                     ` João Távora
2024-08-25  2:49                       ` Dmitry Gutov
2024-08-25  9:53                         ` João Távora
2024-08-25 15:56                           ` Dmitry Gutov
2024-08-25 23:40                           ` Dmitry Gutov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87o75kwl2i.fsf@gmail.com \
    --to=joaotavora@gmail.com \
    --cc=72705@debbugs.gnu.org \
    --cc=dmitry@gutov.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).