neoclide / coc.nvim

Nodejs extension host for vim & neovim, load extensions like VSCode and host language servers.
Other
24.33k stars 956 forks source link

Nested snippet expansion breaks initial snippet placeholder navigation #156

Closed oblitum closed 5 years ago

oblitum commented 5 years ago

Is your feature request related to a problem? Please describe. I'm in general not liking the current implementations for function argument snippets that are being provided by several code completers because they're very limited. For example, for int foo(int a, int b), if I accept the snippet for foo call with another snippet completion for a inner foo call as argument, this happens: foo(foo(4, 2), <placeholder jumps of first snippet don't work anymore!>int b), which means, I'll have to edit and remove the remaining int b by hand, without snippet's jump and selection. That's very bad.

Describe the solution you'd like I can't say whether there's a best solution but I'd like at least to disable these snippets for function arguments so that I can just stick to echodoc.vim for example. LanguageClient-neovim provides g:LanguageClient_hasSnippetSupport = 0 to help on that, for example.

Describe alternatives you've considered Alternative means of dealing with arguments are described here:

chemzqm commented 5 years ago

The language server could provide an option to disable snippet feature, but I don't know if there's such option for clangd.

There is signature help support with coc, you can use something like:

autocmd CursorHoldI,CursorMovedI * silent! call CocActionAsync('showSignatureHelp')
oblitum commented 5 years ago

The language server could provide an option to disable snippet feature, but I don't know if there's such option for clangd.

The issue is not the server providing the parameter information but how the client is doing it in the user interface. The problem I've mentioned is solely related to client implementation, which in this case is coc.

oblitum commented 5 years ago

There is signature help support with coc, you can use something like:

autocmd CursorHoldI,CursorMovedI * silent! call CocActionAsync('showSignatureHelp')

Thanks for this info.

chemzqm commented 5 years ago

It's not additionalTextEdit actually, it's snippet returned from language server, coc just expand the snippet on completion confirm. I think that clangd should not return label with function parameters so that user could just insert function name by use <C-n>, and it should return one item for function overloads, it's not possible for neovim/vim to resolve different complete item with same label as expected for now. And that's how tsserver works like.

chemzqm commented 5 years ago

You can't disable snippet feature of coc, language server like coc-json requires snippet to work.

oblitum commented 5 years ago

It's not additionalTextEdit actually, it's snippet returned from language server, coc just expand the snippet on completion confirm.

Changed title, I may have used the wrong term.

I think that clangd should not return label with function parameters so that user could just insert function name by use <C-n>, and it should return one item for function overloads, it's not possible for neovim/vim to resolve different complete item with same label as expected for now. And that's how tsserver works like.

In the list of links I've provided at the issue, some of them do that. Clang provides per parameter info and prototypes after ( and ,, this is implemented in their signatureHelp support. It's an option of the client to insert the whole function prototype with argument placeholders (and display the multiple prototypes) or just display and insert the function name and provide the compatible overloads, show the current argument, etc, while the user inserts the arguments.

You can't disable snippet feature of coc, language server like coc-json requires snippet to work.

That's sad, I can use LanguageClient-neovim (g:LanguageClient_hasSnippetSupport = 0) and vim-lsp fine coupled with ncm2, because I'm not obligated to use snippets. As I proved at my example, argument snippets are very limited since they work just for the first expansion, after that they get broken and I have to edit function calls removing the snippet text arguments that come with it.

chemzqm commented 5 years ago

That's sad, I can use LanguageClient-neovim (g:LanguageClient_hasSnippetSupport = 0)

As I've said, that would break other language server from working, clangd should provide the option to disable snippet or not provide params in label of complete items, they should be exists in detail field of completion item.

The signatureHelp could be improved, trigger character is not respected for now, it's a bug.

Another solution is create a coc extension with completion middlewire to fix this issue with clangd, the hack of get function name from label would possibly break other language server used by coc.

oblitum commented 5 years ago

As I've said, that would break other language server from working, clangd should provide the option to disable snippet or not provide params in label of complete items, they should be exists in detail field of completion item.

OK, I didn't verify the source code and implementation of clangd yet to see whether it's providing full prototype where should just be the function name. It's weird though because other LSP completers are working fine at providing just a function name for the insertion text. I've tried with ncm2 both vim-lsp and LanguageClient-neovim, using clangd and ccls, which is another server. Currently I'm not even using clangd, I'm using ccls, but the problem, when using coc, still remains.

chemzqm commented 5 years ago

They just spilt the label to get the part of function name, coc not doing that since coc does completion resolve on select change of completion item and it requires the word of vim completion item to be unique (until vim could emit selected complete item on completion item change).

If I do the split, dup should be true for vim completion item and it's possible of wrong resolved complete item.

oblitum commented 5 years ago

I've changed the title to point to the actual issue. If it can be fixed while still having snippets, then OK.

chemzqm commented 5 years ago

It's possible to improve nested snippet, but would require some time, should be easier if you can use an option from clangd to disable snippet https://reviews.llvm.org/D51214?id=162370.

oblitum commented 5 years ago

Nice, and thanks for pointing that issue. Sadly ccls should then be suffering from same problem maybe?...

oblitum commented 5 years ago

I'm a long time YouCompleteMe user but I'm looking for options now, hence I'm trying these several new ones, but I'm doing my tests just with a minimal setup just to give the completion plugins a try. That's the reason I've picked just one language for now, c++, and I'm trying with both clangd and ccls.

I've hit this issue with them and I'm assuming you're right about it involving server implementation, so I'm expecting that for other languages I won't experience the same issue of the title? Or that at least the issue can be avoided somehow, full prototype not being inserted for other languages being one behavior that would solve it.

chemzqm commented 5 years ago

You may or may not, there's no guarantee.

Different language server could have different problems when working with vim, and that's why coc support extensions which could use middleware to fix those problems.

oblitum commented 5 years ago

Oh well, OK... I suspect I'll hit this for all languages and few will have servers where I can disable this, and it's a bad route in any way because I would then need to do it (configuration) server per server.

chemzqm commented 5 years ago

You don't need to disable snippet as long as the function params not exists in label, which should be in detail field as tsserver.

Or wait for vim/neovim support emit selected completion item, then we can do split for function name.

oblitum commented 5 years ago

They just spilt the label to get the part of function name, coc not doing that since coc does completion resolve on select change of completion item and it requires the word of vim completion item to be unique (until vim could emit selected complete item on completion item change).

If I do the split, dup should be true for vim completion item and it's possible of wrong resolved complete item.

OK. So I'm understanding that it's also a problem due to how coc has its completion resolve dependent upon the (neo)vim limitations on item selection. Due to how (neo)vim is contrived on information on "item emit", I'd rely the design and uniqueness of items on another data and event rather than selection and completion-item word. This constrains the core of the completion engine based on a detail of the editor, if I'm understanding it right.

But, anyway, that just an opinion.

chemzqm commented 5 years ago

There's no event for completion item select in vim/neovim, so coc have to rely on unique word of complete item for correct completion resolve on select change.

I've just added the option coc.preferences.splitLabelForWord which make coc split label to get function name, just like other vim's language client, which also disable completion resolve on completion item change for that source. Build from source to use it until new release is available.

oblitum commented 5 years ago

OK, thanks. Sadly, as you said, there's an issue when that's true now, not all overloads are displayed and signatureHelp on the command line (from autocmd CursorMovedI * silent! call CocActionAsync('showSignatureHelp') ) will just show the prototype for the single overloaded that gets displayed in the popup menu. I don't have the same problem with echodoc and ncm2, the popup menu show all prototypes and echodoc helps with permanently displaying the signature for the item that was selected (works when nested too), even though the word inserted for the overloads being duplicated.

chemzqm commented 5 years ago

Just fixed that, forget to add dup property.

oblitum commented 5 years ago

@chemzqm great! that's almost near echodoc, but still echodoc is doing better because it's showing the correct selected overload, CocActionAsync('showSignatureHelp') solution just show the first, not one different I select from the menu when there are multiple overloads for a function.

oblitum commented 5 years ago

And another thing is that for C++ what's shown in the command line is a bit strange than echodoc, I get foo(int x, int y) -> int(int x, int y) there, where I'd expect just foo(int x, int y) -> int or foo(int x, int y).

chemzqm commented 5 years ago

echodoc using abbr field of vim's completion item on complete done, but coc using the result from language server, the server should return all overload signatures and coc could show them all.

oblitum commented 5 years ago

Could coc remember and associate which overload is the one I've selected in the menu and use that information to just show in the command line the one related with my selection? (This is just one solution, on my YouCompleteMe fork and on vim-clangd it's completely different approach that uses the preview window for overload display and signatureHelp on popup).

chemzqm commented 5 years ago

I get foo(int x, int y) -> int(int x, int y) there, where I'd expect just foo(int x, int y) -> int or foo(int x, int y).

It should be just the result from language server, checkout the output channel: https://github.com/neoclide/coc.nvim/wiki/Debug-language-server#using-output-channel

oblitum commented 5 years ago

It should be just the result from language server, checkout the output channel: https://github.com/neoclide/coc.nvim/wiki/Debug-language-server#using-output-channel

OK.

chemzqm commented 5 years ago

Could coc remember and associate which overload is the one I've selected in the menu and use that information to just show in the command line the one related with my selection?

I think the answer is no for now, since it's not standard to include function signature in complete item.

chemzqm commented 5 years ago

You can ask echodoc to make use of virtual text feature of neovim, so you can have better experience with it.

oblitum commented 5 years ago

I think the answer is no for now, since it's not standard to include function signature in complete item.

OK. IMO it could be put in the new user_data field, maybe.

chemzqm commented 5 years ago

It's not related to the field of vim's complete item, it's just not included in specification of LSP: https://microsoft.github.io/language-server-protocol/specification

oblitum commented 5 years ago

OK, it was just a confusion, I thought you meant that because Vim's data structure is also called complete_item.

oblitum commented 5 years ago

You can ask echodoc to make use fo virtual text feature of neovim, so you can have better experience with it.

Cool, I didn't know this feature existed. But I think @Shougo should probably be aware of it already. The one related that I'm following but seems to never land is the one on floating windows.

oblitum commented 5 years ago

But from the last message on the issue tracker it seems it's almost there :)

oblitum commented 5 years ago

Could coc remember and associate which overload is the one I've selected in the menu and use that information to just show in the command line the one related with my selection?

I think the answer is no for now, since it's not standard to include function signature in complete item.

Just to avoid confusion on that, I just noticed that the prototypes I was seeing in the command line were coming after trigger character for signatureHelp, the command line is showing signatureHelp (not for chosen item in menu, but ok) that you have just committed and I didn't know it was already available. I thought I was still seeing a result from autocmd CursorMovedI * silent! call CocActionAsync('showSignatureHelp').

oblitum commented 5 years ago

Just for anyone interested reading this, to overcome the issues with wrong prototype (meaning non selected and/or exquisite declaration) on the command line, echodoc still works as expected with coc, one just needs now to avoid signatureHelp triggers using "coc.preferences.triggerSignatureHelp":false.

oblitum commented 5 years ago

I just realized an awesome thing, even with "coc.preferences.splitLabelForWord": true, I can still expand the snippet if I want to, with <c-y>. I'm trying this plus echodoc, it's nice having both things working (though nested snippet expansion still doesn't work, but at least it's not removed entirely).

chemzqm commented 5 years ago

I've removed coc.preferences.splitLabelForWord, it's not needed any more, coc could fix insert text after select change.

oblitum commented 5 years ago

@chemzqm the current behavior now is that I'm getting a bunch of whitespace inserted when I browse the menu items:

14 21 25_12-11-18

oblitum commented 5 years ago

@chemzqm Besides that, I was really like having this behavior for coding:

session-1 I could expand snippet or not at my option, having it input just the function name was also nice because after inserting parentheses, the arguments for the selected prototype would still show up in echodoc (it also shows when using the snippet with <c-y>).

I hope the new planned behavior (it's not working for me yet because of whitespace) will not remove that workflow. Having snippets enforced upon user is bad because they're flawed when you're writing nested calls, which is a very common practice. You end up in the end forcing the user to edit/remove final placeholders of outer calls by hand.

chemzqm commented 5 years ago

I hope the new planned behavior (it's not working for me yet because of whitespace) will not remove that workflow.

It's not, but has support for completion resolve on select change, so you can have documentation in floating window when it's supported.

chemzqm commented 5 years ago

the current behavior now is that I'm getting a bunch of whitespace inserted when I browse the menu items:

I can't reproduce this issue, but I've added the cursor move after text change, so it might be fixed.

oblitum commented 5 years ago

@chemzqm ok, I just tried it. I don't have whitespaces anymore but now echodoc stopped working, and coc.vim reports on the command line just the type S when I browse the menu for the member functions.

oblitum commented 5 years ago

In the gif above, I was getting "match 1 of 2", etc, where now I'm just getting S (plus no more echodoc).

chemzqm commented 5 years ago

I don't have whitespaces anymore but now echodoc stopped working

echodoc assumes that function name should be word of complete item, you should disable this line https://github.com/Shougo/echodoc.vim/blob/master/autoload/echodoc/util.vim#L297

chemzqm commented 5 years ago

In the gif above, I was getting "match 1 of 2", etc, where now I'm just getting S

It's expected, S is from detail of resolved complete item that echoed by coc.nvim, it should be in preview window when possible.

oblitum commented 5 years ago

hmm, ok. Well you may be building future ground, but for now it simply got way more confuse than it was. Doesn't make much sense to have that type there.

oblitum commented 5 years ago

I mean, why the type of s, the variable being accessed, is useful as detail, dunno. I know it may just be the data that the server sends. If it were at least the type result of the function or member, OK, but the type of the variable being accessed, not useful, there's a specific use for that in hover feature.

chemzqm commented 5 years ago

I mean, why the type of s, the variable being accessed, is useful as detail, dunno.

Clangd use returns type of function as detail for function complete item, but tsserver would have function signature in detail, which is more useful. So it's problem of clangd.

chemzqm commented 5 years ago

I think the reason is when using clangd in VSCode, it always expand function as snippet, so they don't think it's necessary to add function signature in detail.

oblitum commented 5 years ago

Problem is that I'm not getting signature of the function nor the type of its result. I'm getting something that's not useful, the type of the variable for which I'm accessing its members. Such information is useful generally in "get type" and mouse hover features, when one wants to know the type of s. That isn't needed when it's being accessed.