-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Support textDocument/diagnostic specification (Pull diagnostics) #11315
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
base: master
Are you sure you want to change the base?
Conversation
dbed6e4
to
13f048b
Compare
85600d2
to
29c5318
Compare
Thanks again for the reviews! The request is currently only being send on document changes, which makes a terrible user experience 😄 Is there a way to send this request when a document is opened, or should a workspace diagnostic event be send when the language server (which supports this feature) is started? Edit: By the way, i am using this branch daily for C# development, since it allows me to use the same language server as the C# vscode extension. So i am keeping the branch up to date with |
I did some experiments with this on roslyn language server. It might be that this language server just behaves weird (which it does on other stuff), but sending I also noticed that responses can either be a full or an related unchanged document report. At the moment, since we only listening on changes, we only get the full reports. This means that when i eg. rename something, i will not see diagnostics on related documents until i make a change. I am not sure if the specification suggest to pull diagnostics every time a document is viewed, or if we should pull diagnostics for all open documents on changes to a document. Edit: Pulling diagnostics for all open documents seems to work fine actually. |
My plan is to send pull diagnostics request:
|
ac7aabf
to
9e667bd
Compare
Edit: This is no outdated. I also pull blocking when a document is opened or changed to buffer. I chose this model because i thought pulling for all open documents on edit was too aggressive. Pull diagnostics for language servers Document ids are being passed around, and i do some cloning of ids.
|
97a7124
to
32b2077
Compare
32b2077
to
1df9b76
Compare
I've been trying this PR to see if it'll solve some issues using the ESLint LS from
Of note, you do have to be using |
1df9b76
to
4177ba6
Compare
Thanks for testing!
I see the same behaviour with roslyn language server. I think this is because we are requesting diagnostics before the language server is ready. I was hoping that this would be the language servers responsibility. I am not sure what to do about this.
I fixed this by skipping the diagnostics request if the document id is not in the editor. Edit:
I am actually (without knowing) been using |
70daf02
to
44c5453
Compare
It looks like the crash is fixed now, thank you. I'd be curious on why the diagnostic request is trying to happen on a missing document ID (is there a memory leak somewhere?), but a little defensive programming didn't hurt anyone. I've been testing this PR against v4.10.0 and so far it's been working (unlike the master branch, since eslint needs this now I think), although I am still getting the issue where it doesn't pick up the first open file. With my testing just now, it seems that it also doesn't pick up if you open helix blank and then open a file via the picker, you then have to re-open the file (or make an edit) before it starts showing anything. IMO I think functionally it's fine for this PR, but it may be worth opening an issue afterwards as a follow-up to at least document that this is known dodgey behaviour. |
I looked into it, and i am not sending the pull diagnostics request, because of a race between the event, and the launching the language server (and registering capabilities). The event wins 😄
I am not completely sure why. I think part of it was because i was doing this asynchronous, where i collected all document_ids in a hashset, and then send all notifications after a debounce. I changed this to a synchronous hook instead. |
747f539
to
ea69bd5
Compare
ea69bd5
to
5e3c811
Compare
event: Self::Event, | ||
timeout: Option<tokio::time::Instant>, | ||
) -> Option<tokio::time::Instant> { | ||
if timeout.is_none() { |
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 logic here does not make sense to me. The no_inter_file_dependency timeout does not really work. What I would expect is the following:
- have a debuounce of 125ms until we refresh diagnostics for the current document
- if there are lsps with inter-file dependencies then refresh all open documents registered with one of the inter-file LSPs active for the current document.
This would be structured as the following:
- change event triggers a short debounce (125ms) and at the end requests diagnostic locally
- when the local debounces finishes and the set of active language servers with inter-file dependencies is not-empy, we send another event (containing the set of active lsp with inter-file dependencies and the active document) to a second handler with a larger debounce (500ms?) that will request diagnostics for all documents for those lsps (and exclude the document that orginated the request)
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.
also: if there is a previous request running we must cancel it and need to track with each request for which document version it was requested and cancel if the version doesn't match
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.
and in this handler we likely only want to pull for visible documents.
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.
Good points.
I have made some changes:
- there are now two handlers:
- one for the edited document
- one for all visible documents with language servers with interfile dependency capability
- previous running requests are cancelled
- the language server client holds a list of ongoing requests for documents
- when new diagnostics are requested all ongoing requests for that document is cancelled
I am not satisfied with the way that the language server return a future and the progress token, and it is then then callers responsibility to mark the request as done. I think this could be handled inside the language server client. I will give it a try.
But is this roughly the way you expect this to work?
editor.document(document_id), | ||
editor.language_server_by_id(language_server_id), | ||
) { | ||
pull_diagnostics_for_document(doc, language_server); |
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 can lead to runaway requests. We should not be making a new request right away since the cancellation is usually caused by a new edit for which we also make a new request anyways.
We should instead send an even to the handler here (which needs to track for which revision we already made a request and only rerequest if it makes sense)
job::dispatch_blocking(move |editor, _| { | ||
let documents = editor.documents.values(); | ||
|
||
for document in documents { |
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.
if the server supports it we should use a workspace diagnostic request when pulling all documents.
@pascalkuthe Thanks for the review. It sounds like this needs some more features:
While i do agree that this would be great features to have, i am personally only invested in basic pull diagnostic support. I absolutely understand why this should be implemented, i just do not have the time (or skills 😄 ). I have been updating this branch for quite some time and will continue to do so, but i don't think i will be able to implement these features in the near future. |
5ad5525
to
585c6c7
Compare
Pascal and I can take the branch forward as we find time to work on it. I have some changes locally I was working on to track the ongoing requests anyways. We wouldn't mind getting something relatively simple in as a first step but there are some changes we'll want to make to ensure we don't spam the language server or allow duplicate in-flight requests |
Thanks. I appreciate your work 😃 I did play around with the cancel request. The result is great. I was able to reduce the debounce to 125 ms without issues, but I am not sure if the code holding ongoing requests is ideal. edit: Fat fingered the close with comment button. |
c9ca4ee
to
3c37ddf
Compare
b44e1a3
to
07940ce
Compare
Closes #7757, if workspace diagnostics is not a requirement. I have not yet found a language server which supports this capability.
Handling of response was originally done by @woojiq in #7900. I was not able to include their git history since their branch has been deleted.
Tested with language servers:
eslint
version >4.10.0csharp-language-sever
version >4.12.0ruby-lsp
rust-analyzer
version >2025-03-03
Diagnostics are pulled when a document is changed for each language server with pull diagnostics feature with an async hook after a debounce period.
Diagnostics are also pulled when a document is opened, when changed to buffer and when a language server is successfully initiated. This is done without debounce.