-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Support snippet-less completion #2518
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
Comments
Thanks for opening this issue. As mentioned in #1705, not providing plain text completion is a protocol violation, so "clients should be improved" is not a valid statement.
As a maintainer of such a client and someone with a strong opinion that goes against snippets, here's my .02c: I'm a vim user. Snippets in vim are expanded on something called
So the instead, ycmd maintainers, unanimously, settled for a third option - not implementing snippets.
So, I haven't looked at the rust-analyzer code, but a client like ycmd would expect
Now I didn't mean to sound harsh, in case I did. It's just that a lot of servers assume snippets are supported, even though it can be argued that they provide a pretty horrible user experience. EDIT:
Would that make insertion text just |
Yes. As I've said, that would be a good initial implementation, which would primarily focus on plumbing the required flags. For the final implementation, a corresponding flag should be added to the internal CompletionConfig, and than this setting need to be honored everywhere where we use snippets. After that, we either should assert here that we don't see a compleiton with a snippet, or we should just not add such completions. |
I've actually figured a much neater way to do this: introduce an unforgable I've implemented this idea in #4116 No the only thing left is the actual plumbing to fetch the cap from the client.... |
4117: Honor snippet capability r=matklad a=matklad closes #2518 bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
Plumbing implemented in #4117 Here's example of completion with a snippet: And here's the same completion without the snippet: |
In your example I would still argue that the completion is probably completing too much. It’s unexpected that selecting ‘size’ competes a whole line of text including a function declaration. I kind of get it. It’s boilerplate, so let’s write it for the user. My concern is that sort of thing is divisive and opinionated. Perhaps that’s intentional (if so, so be it), but certainly my users are unlikely to expect that and would likely be model-breaking for completion systems and users accustomed to more natural word expansion. The original point put across by Boris is that completion systems doing too much breach’s workflow because when stuff happens that you don’t expect you end up having to rewind. Let’s say you develop in N languages and N-1 behave one way, eg like clangd or jdt.ls or gopls) and the Nth one behaves like this. The challenge for the user in that case is to switch gears. We would like to avoid having the user switch gears and offer consistent powerful experience across languages. Anyway just my 2p. Tl:dr there are a large quantity of users that don’t expect the completion system to complete more than a word at a time. It’s probably worth considering that group. |
As usual, the user is (almost) always right, and, if some users complain about this feature, we'll introduce a feature flag, like, for example, we did for automatic With my "unsolicited advice giver" hat on ( :-) ), I think for ide-like tools it's generally good to:
I did add support for features which I, personally, don't use and find counter-productive, like argument snippets (yes, I hate stupid snippets myself), which, I believe, only exists because parameter hint UI is universally horrible (IntelliJ's version is kind of ok, actually, but the API used to implement it is very crufty). From re-reading original comment here, I get the impression that the primary reason for not supporting snippets is not that "users expect a single word", but that vim expects a single word, and that it's a pain to work around this limitation. So, to me, the path that maximizes user happiness (without taking work needed into account), is:
|
No, vim plugins can adequately support snippets. I have even implemented it for YCM. But, as you say "provide opinionated defaults" - we tried it, we evaluated it, and we decided we don't like it as it doesn't fit well with our philosophy and the mental model our users have of what we provide. Add to that the complexity of doing it well, the fact there's only 2 of us and neither of us really want it, and we decided against it. Similarly to you, if we have 1000s of users asking for it, we might rethink, but so far not so many. The "option" we offer is to use my fork. Mileage variance notwithstanding. Our point was really that we made this decision and we declared that decision to the Language Server using capabilities. We expect that decision to be honoured. We could just as well have merged my snippets branch and offered the user the ability to globally disable it by, again, declaring in the capabilities that we don't support them (this prevents the user having to configure this for each and every project/language combination in unique, marvellous and usually undocumented ways). Anyway, as you say, that's water under the bridge. The capability is now honoured (thanks!). I've tested But getting back to it, my suggestion about the function-declaration was largely orthogonal to that, and comes back to the original philosophy of largely getting out of the way and assuming users know what to type (it's mentioned here from 2013 http://val.markovic.io/articles/youcompleteme-a-fast-as-you-type-fuzzy-search-code-completion-engine-for-vim), but more that the consistency of experience across languages is a truly powerful thing. YCM has been providing consistent experience across languages for years, and i think our users appreciate that, so we're generally in favour of minimising surprising behaviours. Like i said it was really just a take-it-or-leave-it thought. In this case, opinionated default = complete full declaration, feature option=don't. On a side note, i'd like to test the "full function declaration" completion because it may hit edge cases in the textEdit expansion - would you be willing to let me know a simple test case for it ? I don't rust, so i'd be grateful if there's a place i can trigger it (e.g. in rust-analyzer source code). |
Obviously we care more about providing a great experience for Rust than about providing a consistent experience across languages. But I want to push back a bit on the "surprising" part -- the completion is labeled
trait Foo {
fn bar(&self, x: u64) -> f32;
}
struct S;
impl Foo for S {
// (type bar here)
} I think that should be enough to trigger it (if you put it into |
did notice something odd though (you can briefly see it in the demo). when selecting a macro, while the label contains the You can see here that the 'newText' does not contain the
Seems wrong to me? Expected? |
Kind of expected: |
but the label and what's inserted don't match....i mean the label looks like the right thing to insert to me (and that's what Note: Sorry for the comparison to rls. I realise apples/pairs, but it's in relation to the suggestion that rust-analyzer be the "official" LS for rust, which i'm fine with, just YCM uses rls by default (as the "supported" LS) and should that decision go ahead, we'd want to switch to rust-analyzer too. |
In general, label and insert text don't need to match. For example, when importing a macro, like in use std::debug_assert; the In this case, I didn't add
We do, but only the file is saved. For compiler provided fixits, we just run compiler once in a while, like the old-school flymake/flycheck/ale(?). In the end, we hope to provide the same fixits from in-memory model, but we are not there yet. |
(We do provide the "implement missing trait items" fixit though even without saving, we just don't show a diagnostic!) |
I see, is it based on
|
Oh right. so a code-action in the broad sense. I'll try it. |
Well, i just get an error when running that. Apologies, that's off-topic for this conversation, so posting in case you're interested. Feel free to hide this comment (and the previous 2)
our log:
|
Ah yeah, most (if not all) of our code actions require support from the client (i.e. that it implements the |
:( |
@flodiebold I apologize if this is off topic, but can you say more about that (or point me to more info about that)? I've just set up rust-analyzer with vim using vim-lsp, and I'm trying to test with the "fill match arms" code action. It fails with this error:
In the full error output I see the expected text of the match arms coming back, so this does seem to be a client issue as you alluded to, but I can't find more information about how this is supposed to work. |
RA responds to Your client is trying to handle that
That requires the server to implement Instead, rust-analyzer expects clients to know about if code_action_command[ 'command' ][ 'command' ] == 'rust-analyzer.applySourceChange':
code_action_command[ 'edit' ] = code_action_command.pop( 'command' )[ 'arguments' ][ 0 ][ 'workspaceEdit' ]
return self.CodeActionLiteralToFixIt( request_data, code_action_command ) Except for the name, this is the exact same thing I had to do for |
Some clients don't support completions snippets. It can be argued that clients generally should be improved to support snippets, but
eval
field of a debugger)So, we should support this use-case. Specifically, we should only send snippet completions if supports them.
A simplest fix here (and a good initial implemtation) is change code around here to just strip
$i
snippet markers from text edit, if the client doesn't support snippets. A similar "fixup" approach is used for folding ranges.However in general it seems like the core completion engine should just provide different completions depending on whether snippets are enable or not. This should be done via feature flags (example), and requires some design to make sure that we don't twice as much code, but still provide best possible completions with and without snippets.
The text was updated successfully, but these errors were encountered: