-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
Add basic support for LSP snippets #5864
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey there, thanks a lot for submitting this PR, I really miss snippets at the moment, but it always seemed like a hard thing to implement. I hope you don't mind me leaving a comment, thought it might be of interest.
Note: we have a full snippet parser here: https://github.com/helix-editor/helix/tree/snippets It's just not tied into the LSP stack yet. |
3a59d0c
to
1606d72
Compare
Do you want me to close the PR and wait or the full snippet parser to land ? |
You could base your PR on top of that branch and use the snippet parser rather than a custom parser. It would be a good enough stopgap until full snippet support is developed |
Actually, @the-mikedavis looks like your branch already matches this PR's behaviour? (apart from jumping to the first tabstop and correctly indenting) |
I think it already jumps to the first tab stop here. As for indentation, I can add it. |
1606d72
to
f4e64d3
Compare
I have now rebased this PR with the changes from @the-mikedavis. 🥳 On top of the rebase I added the auto-indentation, sorting and merging of tabstops, removed the need for regex when parsing the snippets The support for snippet is now in a good state where only variable and Tab/S-Tab support isn't implemented. |
f4e64d3
to
1c548d8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes in 1c548d8 heavily regress many core editing operating in helix like appendmode (and also handle other details incorrectly like using byte indexing instead of char indexing). You should not be changing the core editing operations. Instead the placeholders should be stored on the Document
and specical cased in apply_impl
.
b2cef33
to
d885ca7
Compare
My bad, I didn't test it enough. I'm still new to the code base or even helix. I will try to do the special cased as said this week. For the moment, I've removed the offending commit. |
I'd implement this the simplest way possible for now (jump to first tabstop and drop all the snippet state). The idea is to use marks in the future (#3720) to keep track of each tabstop locations even as text edits occur. |
d885ca7
to
d348fa0
Compare
The pull request already jumps the cursor to the first tabstop. So I think it's ready for review.
That seems exactly what tabstops should be map to. Looking forward to see this being merged. |
I think removing the placeholder text for the first tabstop would be required for a MVP, deleting that would be quite annoying. Maybe if we want to keep this PR really simple you could simply remove the placeholder for the first tabstop by generating a second transaction that deletes it and apply it immedietly. That would probably be the easiest workaround and just take 5 lines of code. |
I tested this and it unlocks all the basic features of the HTML language server that didn't work before. You now get auto suggestions and auto tag completion :) I remember it was an issue in Neovim that you needed a special snippet plugin to solve. This PR adds a lot of value as it is. |
@David-Else Do I need to do some additional steps beside merging this PR to get auto suggestion and auto completion working? Cuz I have build from src merging this PR but it seems that those are not present. |
@H4ckint0sh I assume you have:
I just switched to this PR using GitHub CLI, rebuilt Helix and it worked right away. You need to be in a valid HTML file for it to work, here is what I was using to test: <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div>Make another div, you should get suggestions for span, div etc, then start to close it and it suggests the right closing tag</div>
</body>
</html> |
@pascalkuthe Here's what I hacked for deleting the first tabstop, I had to do a bit of range manipulation since the selection was too big at the right and was eating the next character. Do you have a better things in mind or should I push this ? |
Seems a bit odd that you would have to modify the ranges after the fact, it's probably because the returned ranges are end inclusive? |
Or we could do it the other way around (\cc @pascalkuthe) |
@archseer I think it's probably better to merge this PR first since some of the fixes from #5728 need to be applied to the logic from this PR (see #5864 (comment)). It's probably easier if I just do that in #5728 myself |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good 🚀
I left some minor comments
When accepting a snippet completion we automatically delete the placeholders for now as doing so manual is quite cumbersome. In the future we should keep these as a mark + virtual text that is automatically removed once the cursor moves there.
This refactors the snippet logic to be largely unaware of the rest of the document. The completion application logic is moved into generate_transaction_from_snippet which is extended to support dynamically computing replacement text.
936d98c
to
c2fab5e
Compare
Thank you very much for the fix/improvement! |
Thank you for flagging this! At first it seemed like an easy issue to fix, but I ended up uncovering some more subtle bugs in the current implementation. Urgau#7 is the fix. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll postpone Urgau#7 until this PR + Pascal's PR land.
I wanted to say, thank you @Urgau and @andriigrynenko for working on this! It's great to see basic snippet expansion finally land :)
Apologies, I've read this through more than once and my queston isn't answered, thus I'll ask. How do you test I think the idea is it hits the first tab stop |
Hello, I didn't find anything about it, is it now possible to tab to next position ? |
@noahfraiture you're looking for this PR #9801 |
This PR adds a basic support for LSP completion snippet based on https://github.com/helix-editor/helix/tree/snippets.
A snippet is a bit different from a normal completion in that it contains tab stops/placeholders (ie
$1, $2 or ${3:foo}
and$0
who is always the last one). A complete definition of the syntax can be found [here(https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#snippet_syntax). So when creating the transaction we parse the snippet input, create the output text with the correct indentation and create the selections for the placeholders.This PR brings the support for snippet in a good state where only variable, placeholder removal and Tab/S-Tab support isn't implemented for the moment, those should be feasible but I didn't wanted to do them in this PR.
I've tested multiple snippet with
rust-analyzer
, I recommend themacro_rules
snippet for testing as it uses multiple tab stops and is multi line.