Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Snippet based completion inserts text twice #82

Closed
amol-mandhane opened this issue Aug 20, 2018 · 8 comments
Closed

Snippet based completion inserts text twice #82

amol-mandhane opened this issue Aug 20, 2018 · 8 comments

Comments

@amol-mandhane
Copy link

When snippet based completion is triggered, the completion text is inserted twice with snippets enabled on second text.

I think the part of (delete-region (car bounds) (point)) in :exit-function is the culprit. I locally replaced it with (delete-backward-char (length obj)) and it works fine.

@joaotavora
Copy link
Owner

It's very odd that I can't reproduce this. Can you present a reproduction recipe from Emacs -Q? Still I will consider your solution, which isn't bad.

@amol-mandhane
Copy link
Author

amol-mandhane commented Aug 20, 2018

I'm running this in a stripped down version of emacs 26 config with only helm, company, yas, and eglot packages. I'm doing this with eglot master HEAD code with clangd language server in C++.

@joaotavora
Copy link
Owner

Can you remove helm from the equation?

@joaotavora
Copy link
Owner

Assuming you've got everything installed with package.el, you could start emacs with

emacs -Q -f package-initialize -f global-company-mode -f yas-global-mode path-to-cpp-file -f eglot

@amol-mandhane
Copy link
Author

Same issue with emacs -Q

@joaotavora
Copy link
Owner

Same issue with emacs -Q

That's very odd. Also, normally when I request an emacs -Q recipe I am requesting a way to reproduce the problem exactly as it happened to you, so that I can rule out external interference. By just saying you have the same issue, it doesn't help me much.

Can you provide the actual line you used and the steps to start eglot? Alternatively, can you start with the steps that I give below, in the Eglot checkout directory and with Emacs 26.1?

PATH+=':~/Downloads/2018-05/cquery-v20180302-x86_64-unknown-linux-gnu/bin' \
emacs -Q -f package-initialize -f yas-global-mode -f global-company-mode -L . -l eglot ~/Source/Arduino/avr-tutorial/stepper.cpp -f eglot

The result, in a gif:

peek 2018-08-20 19-50

By the way, clangd-6.0 doesn't provide any snippets for me, so I had to use cquery, as you see above. Which exact version of clangd are you using?

@amol-mandhane
Copy link
Author

Figured out the issue. The solution I suggested should solve it.

The command I'm running is

emacs -Q  -f package-initialize -l eglot --eval "(progn (add-to-list 'eglot-server-programs '(c++-mode . (\"/usr/bin/clangd\" \"--limit-results=50\"))) (setq company-backends '(company-capf)))" -f global-company-mode -f yas-global-mode <cpp-file-name> -f eglot

I also added some message statements to the exit-function and I discovered that the bounds variable is incorrect. So, delete-region is not deleting what we want to delete. Tracing the bound variable reveals that it is taken from bounds-of-thing-at-point. What is actually happening is that exit-function is taking the bounds-of-thing-at-point to delete after completion, not before. So, if the inserted completion label to delete contains multiple "things", exit-function is going to delete just one of them and insert the snippet.

For instance, following is the relevant stuff in my completionItem.

(...
:insertText "AppendPartialToCord(${1:Cord *output})"
:label " AppendPartialToCord(Cord *output) const"
...)

So, eglot inserts the label and puts point at the end of "const" in the label it just inserted. Then, it takes bounds-of-thing-at-point, which returns the bounds of "const" and deletes the const instead of deleting the entire completion label that it just inserted. Then it inserts the snippet text. The combined result of which renders the effect of inserting the text twice.

The solution I suggested doesn't make the assumption that the label will contain exactly one "thing". That's why it should work.

@joaotavora
Copy link
Owner

What is actually happening is that exit-function is taking the bounds-of-thing-at-point to delete after

Indeed. Company unexpectedly (and needlessly) calls this function more than once.

That's why it should work.

I never said it didn't. But I make it a point to understand a problem before I apply any solution.

Should be fixed with a fix similar to yours.

bhankas pushed a commit to bhankas/emacs that referenced this issue Sep 18, 2022
…ppet completions

Suggested by Amol Mandhane.

* eglot.el (eglot-completion-at-point): Use length of obj in
:exit-function
bhankas pushed a commit to bhankas/emacs that referenced this issue Sep 19, 2022
…ppet completions

Suggested by Amol Mandhane.

* eglot.el (eglot-completion-at-point): Use length of obj in
:exit-function
bhankas pushed a commit to bhankas/emacs that referenced this issue Sep 19, 2022
Suggested by Amol Mandhane.

* eglot.el (eglot-completion-at-point): Use length of obj in
:exit-function

#82: joaotavora/eglot#82
jollaitbot pushed a commit to sailfishos-mirror/emacs that referenced this issue Oct 12, 2022
Suggested by Amol Mandhane.

* eglot.el (eglot-completion-at-point): Use length of obj in
:exit-function

GitHub-reference: close joaotavora/eglot#82
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants