-
Notifications
You must be signed in to change notification settings - Fork 131
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
Partial update #103
Partial update #103
Conversation
Thank you for the PR @njuCZ ! It looks pretty good on the first sight, but I will read it more thoroughly 🔜 One other test case that may be worth adding is text with some unicode characters, to ensure that byte-position is calculated correctly in such case too. The logic may be error-prone in this context especially because LSP uses UTF-16 and HCL is always encoded as UTF-8. I'm not saying it is a problem here, but the encoding differences is something worth extra attention. I also want to try this out with a few clients/IDEs which support it, just as a sanity check.
I can see why that would be convenient in this context, but also I think that there is some value in not using pointers as they can lead to crashes, when I also tried to keep it aligned with interfaces within HCL itself, which practically doesn't use |
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.
In addition to the inline comments:
- There is a few tests failing in
langserver/handlers
.- Perhaps we should look into centralizing the server capabilities struct somewhere and just marshal it into the test data to make these tests less fragile as I imagine we will be adding many new capabilities often and it feels wrong to keep fixing these tests because of that. - but I'm happy for that to be addressed in a separate PR.
- As discussed via Slack I'm happy for you to merge
fileChange
andtestChange
ininternal/filesystem
tests - I would prefer us to avoid exporting
fileChange
out of thefilesystem
package- Maintaining interface is usually easier (from compatibility perspective) than maintaining a struct and it also makes handling of internal state more difficult, since we'd either need to add some more methods and/or constructor, export all fields etc.
- Interfaces can help avoiding import cycles as they could be more easily extracted into their own package with very few dependencies, as opposed to any real struct/implementation.
- A little copying is better than a little dependency
@radeksimko I have refined the codes according to your suggestions. Please have a look again |
There are few things we discussed outside of GitHub, which I'm going to describe here just for posterity. (1) The fork of I have created #117 and #118 to discuss the problem in more generic way, but I reckon that will take some time & effort to tackle, so I'd suggest you to just create a new struct in (2) When partially updating a document, the ordering of requests/responses matters and we need a way of guaranteeing that. I believe the best way to address this would be implementing a priority queue when applying any partial changes to a document which would be taking changes in the form of Non-partial changes should not fall into any queue though - they should IMO be processed the exact same way they are processed now and keep benefiting from the simple parallelism. There is a few edge cases related to this approach worth discussing - see below. Missing versionsThis may occur e.g. when the server crashes mid-flight and starts again, while the client still preserves versions of the document. e.g. server would receive versions Presumably we'd be queueing I'm not sure what's a sensible timeout, but I would be conservative and keep it pretty low as I assume that document updates should generally be quick. Duplicate versionsThis could happen due to misconfiguration where e.g. client runs in 2 or more instances while talking to the same server in the same session, or simply client sending the same request twice for any reason. This would more often be a bug on the client side, but I've seen that happening a few times and we have to reflect it somehow. e.g. server would receive versions We could just ignore the second I appreciate with the above this would probably grow into much bigger chunk of work you may originally expected and I'd be happy to take it over if you don't feel confident about implementing the proposal - just let me know. Also I'm open to alternative ideas! Either way thank you for all your work so far, which helped uncover these bugs 🐛 🙏 |
#120 resolves the (2) problem in slightly different and far less complex way - pretty much the way you proposed originally via Slack 😄 - by setting concurrency to The only major problem left to solve here seems to be (1) and I think we could take the shortcut I proposed - just add a new struct to |
@radeksimko thanks for your suggestion. I have refined the PR, please have a look again |
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 is looking pretty good and it looks like it already helped me discover a bug in coc.nvim
which skipped a version completely, see log. I will report it later upstream.
I left you mostly minor comments inline, the only major things is the error handling and version incrementing, otherwise it works well!
@radeksimko thanks for your review. Hope the version missing issue is rare for most editors. Besides I wonder it's the version 9 message lost or just the editor send the wrong version (not strictly incremental) |
Co-authored-by: Radek Simko <radek.simko@gmail.com>
Co-authored-by: Radek Simko <radek.simko@gmail.com>
Co-authored-by: Radek Simko <radek.simko@gmail.com>
🤔 I would argue that such behaviour would be fine for non-partial updates, but since partial updates send deltas which need to be applied in the right order then there should be a way of guaranteeing that order and consistency. |
agreed, maybe we could have a whitelist to decide partial update or full update or make a config for user to choose? |
What I meant by way of guaranteeing order and consistency is that I assume this is built into the protocol and we're essentially just adding guardrails to enforce this assumption. If it turns out that assumption is wrong (e.g. because we receive a bug report) then we can react accordingly and apply different assumptions, but I think this gives us a starting point.
I think the decision whether to use partial updates should be between the client and the server and how they communicate their capabilities. Such settings would be also quite difficult to communicate to the user. Most users are IMO looking at settings generally from the perspective of "getting things done" and from that perspective they may not be aware of how LSP works nor that there is even such thing as "updating document". How document is updated in memory is an implementation detail for them and it I think it should stay that way. |
I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. |
fix #34
add support for file partial update.
func (fc *fileChange) Range() hcl.Range
to return a pointer, which is convenient to check whether to apply full content replace or partial update, but it seems need to change the interface and other parts, please confirm whether I should do in this way.