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

Use a hook for resolving completion items #9668

Merged
merged 1 commit into from
Feb 23, 2024

Conversation

the-mikedavis
Copy link
Member

Previously we used the IdleTimeout event to trigger LSP completion/resolveItem requests. We can now refactor this to use an event system hook instead and lower the timeout.

Connects #9629

Previously we used the IdleTimeout event to trigger LSP
`completion/resolveItem` requests. We can now refactor this to use an
event system hook instead and lower the timeout.
@the-mikedavis the-mikedavis added A-language-server Area: Language server client S-waiting-on-review Status: Awaiting review from a maintainer. labels Feb 19, 2024
Copy link
Member

@pascalkuthe pascalkuthe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, great that you are tackling moving stuff to the event system. I actually totally forgot this used the idle timeout

} else {
self.trigger = Some(item);
self.request = None;
Some(Instant::now() + Duration::from_millis(150))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that you don't want to introduce 10 different settings, but what about low_latency = true which will set all these annoying debounces to zero?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be fine to have a config section dedicated to timeouts. As we tackle the items in #9629 we'll be hard-coding a lot of debounce constants. Something like:

[editor.timeout] # or maybe 'editor.debounce'
lsp.auto-complete = 250
lsp.signature-help = 120
lsp.resolve-completion-item = 150
highlight-picker-preview = 150

seems fine to me but I'm not sure how @archseer feels about it. In any case we would always advise setting the constant to something non-zero, and would probably enforce that in the code

Copy link
Member

@dead10ck dead10ck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, thanks!

@dead10ck dead10ck merged commit b7b6f30 into master Feb 23, 2024
6 checks passed
@dead10ck dead10ck deleted the completion-resolve-async-hook branch February 23, 2024 03:37
@the-mikedavis the-mikedavis mentioned this pull request Mar 2, 2024
pascalkuthe added a commit that referenced this pull request Apr 22, 2024
While moving completion resolve to the event system in #9668 we introduced what
is essentially a "DOS attack" on slow LSPs. Completion resolve requests were
made in the render loop and debounced with a timeout. Once the timeout expired
the resolve request was made. The problem is the next frame would immediately
request a new completion resolve request (and mark the old one as obsolete but
because LSP has no notion of cancelation the server would still process it). So
we were in essence sending one completion request to the server every 150ms and
only stopped if the server managed to respond before we rendered a new frame.
This caused overload on slower machines/with slower LS.

In this PR I revamped the resolve handler so that a request is only ever
resolved once. Both by checking if a request is already in-flight and by marking
failed resolve requests as resolved.
archseer pushed a commit that referenced this pull request Apr 22, 2024
While moving completion resolve to the event system in #9668 we introduced what
is essentially a "DOS attack" on slow LSPs. Completion resolve requests were
made in the render loop and debounced with a timeout. Once the timeout expired
the resolve request was made. The problem is the next frame would immediately
request a new completion resolve request (and mark the old one as obsolete but
because LSP has no notion of cancelation the server would still process it). So
we were in essence sending one completion request to the server every 150ms and
only stopped if the server managed to respond before we rendered a new frame.
This caused overload on slower machines/with slower LS.

In this PR I revamped the resolve handler so that a request is only ever
resolved once. Both by checking if a request is already in-flight and by marking
failed resolve requests as resolved.
Vulpesx pushed a commit to Vulpesx/helix that referenced this pull request Jun 7, 2024
While moving completion resolve to the event system in helix-editor#9668 we introduced what
is essentially a "DOS attack" on slow LSPs. Completion resolve requests were
made in the render loop and debounced with a timeout. Once the timeout expired
the resolve request was made. The problem is the next frame would immediately
request a new completion resolve request (and mark the old one as obsolete but
because LSP has no notion of cancelation the server would still process it). So
we were in essence sending one completion request to the server every 150ms and
only stopped if the server managed to respond before we rendered a new frame.
This caused overload on slower machines/with slower LS.

In this PR I revamped the resolve handler so that a request is only ever
resolved once. Both by checking if a request is already in-flight and by marking
failed resolve requests as resolved.
Chirikumbrah pushed a commit to Chirikumbrah/helix that referenced this pull request Jun 15, 2024
While moving completion resolve to the event system in helix-editor#9668 we introduced what
is essentially a "DOS attack" on slow LSPs. Completion resolve requests were
made in the render loop and debounced with a timeout. Once the timeout expired
the resolve request was made. The problem is the next frame would immediately
request a new completion resolve request (and mark the old one as obsolete but
because LSP has no notion of cancelation the server would still process it). So
we were in essence sending one completion request to the server every 150ms and
only stopped if the server managed to respond before we rendered a new frame.
This caused overload on slower machines/with slower LS.

In this PR I revamped the resolve handler so that a request is only ever
resolved once. Both by checking if a request is already in-flight and by marking
failed resolve requests as resolved.
smortime pushed a commit to smortime/helix that referenced this pull request Jul 10, 2024
While moving completion resolve to the event system in helix-editor#9668 we introduced what
is essentially a "DOS attack" on slow LSPs. Completion resolve requests were
made in the render loop and debounced with a timeout. Once the timeout expired
the resolve request was made. The problem is the next frame would immediately
request a new completion resolve request (and mark the old one as obsolete but
because LSP has no notion of cancelation the server would still process it). So
we were in essence sending one completion request to the server every 150ms and
only stopped if the server managed to respond before we rendered a new frame.
This caused overload on slower machines/with slower LS.

In this PR I revamped the resolve handler so that a request is only ever
resolved once. Both by checking if a request is already in-flight and by marking
failed resolve requests as resolved.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-language-server Area: Language server client S-waiting-on-review Status: Awaiting review from a maintainer.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants