-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Better LSP conformance #5516
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
Better LSP conformance #5516
Conversation
|_, _| (), | ||
); | ||
if self.config.client_caps.dynamic_watched_files { | ||
let save_registration_options = lsp_types::TextDocumentSaveRegistrationOptions { |
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.
Why do we only register for didSave if the client is watching the files? Aren't they separate things?
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 client sets the workspace/didChangeWatchedFiles/dynamicRegistration
capability to false
it means that the server cannot use client/registerCapability
for workspace/didChangeWatchedFiles
, doesn't it?
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.
I think so... but textDocument/didSave
isn't controlled by workspace/didChangeWatchedFiles
. I'm not sure of the relationship here.
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.
Yes, you are absolutely right, this is my mistake. I cannot understand how I managed to confuse different capabilities.
I already asked to rollback the PR.
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 spec is incredibly confusing around this sort of thing :( and you are correct in that we are not checking static/dynamic registrations correctly.
I think that this and the diagnostics bug I probably introduced a few days ago (and the call hierarchy issue I fixed awhile back) highlight the need for more precise tests on our LSP layer.
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.
@olegtk I tried Preview5. Same problem (textDocument/didOpen
goes before initialized
):
C->S: {"jsonrpc":"2.0","id":2,"method":"initialize","params":{...}}
S->C: {"jsonrpc":"2.0","id":2,"result":{...,"serverInfo":{"name":"rust-analyzer","version":"57b4ec4"}}
C->S: {"jsonrpc":"2.0","method":"textDocument/didOpen","params":{...}}
C->S: {"jsonrpc":"2.0","method":"initialized","params":{}}
I've tried to catch textDocument/didOpen
via ILanguageClientMiddleLayer, wait until the server is fully initialized (ILanguageClient.OnServerInitializedAsync called) and resend didOpen notification. It works, but right after textDocument/didOpen
VS sends textDocument/documentSymbol
(also before initialized
) and I did not find a way to catch and delay this request (ILanguageClientMiddleLayer does not work).
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.
Hmm, that's not a known issue... can you please point to your ILanguageClient implementation?
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.
I don't have a fully functional ILanguageClient, just a quick sketch (enough to reproduce didOpen\initialized on my system):
public class ContentDefinition {
public const string RustContentTypeName = "Rust";
[Export]
[Name(RustContentTypeName)]
[BaseDefinition(CodeRemoteContentDefinition.CodeRemoteContentTypeName)]
internal static ContentTypeDefinition RustContentTypeDefinition { get; }
[Export]
[FileExtension(".rs")]
[ContentType(RustContentTypeName)]
internal static FileExtensionToContentTypeDefinition RustFileExtensionDefinition { get; }
}
[Export(typeof(ILanguageClient))]
[ContentType(ContentDefinition.RustContentTypeName)]
public class Client : ILanguageClient{
public string Name => "VSRust";
public IEnumerable<string> ConfigurationSections => null;
public object InitializationOptions => null;
public IEnumerable<string> FilesToWatch => null;
public event AsyncEventHandler<EventArgs> StartAsync;
public event AsyncEventHandler<EventArgs> StopAsync;
public async Task<Connection> ActivateAsync(CancellationToken token) {
await Task.Yield();
var info = new ProcessStartInfo {
FileName = @"E:\Projects\Rust\rust-analyzer\target\debug\rust-analyzer.exe",
Arguments = "",
RedirectStandardInput = true,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
};
info.Environment.Add("RA_WAIT_DBG", "1");
info.Environment.Add("RA_LOG", "1");
var process = new Process { StartInfo = info };
if( process.Start() ) {
return new Connection(process.StandardOutput.BaseStream, process.StandardInput.BaseStream);
}
return null;
}
public async Task OnLoadedAsync() {
var tmp = StartAsync;
if( tmp != null ) {
await tmp.InvokeAsync(this, EventArgs.Empty);
}
}
public Task OnServerInitializedAsync() {
return Task.CompletedTask;
}
public Task OnServerInitializeFailedAsync(Exception e) {
return Task.CompletedTask;
}
}
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.
@olegtk Perhaps it's not the best place to continue discussion. In case you need more details please drop me an email to [email protected].
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.
Actually you are right, @vsrs, it's a bug in VS LSP client. It's tracked now internally. Thanks!
bors r+ |
No worries, reverted! |
Thanks. |
Just noting this is an actual problem in joaotavora/eglot#526. Though I'm thinking of starting to support this dynamic registration anyway, maybe other clients suffer from the same problem. By the way, what is the purpose of this dynamic registration? Is it to check for changes to |
yup, def our bug, fixed in #7241 We only use dynamic registration stuff for didSave (to reload cargo.toml) and watched files (to notice changes to .rs after branch switches and such). tbh, I don't understand why the dynamic infra exists in the first place -- this two cases could have been just a separate "watch these files" request, but instead they are handled via this nested RPC contraption :-( {
"jsonrpc":"2.0",
"id":2,
* "method":"client/registerCapability",
"params":{
"registrations":[{
"id":"workspace/didChangeWatchedFiles",
* "method":"workspace/didChangeWatchedFiles",
"registerOptions":{"watchers":[{"globPattern":"/home/matklad/tmp/hello/**/*.rs"}]}
}]
}
} |
Thanks! I don't know what you mean by "dynamic infra". Am I to understand that you are now sending a request for |
The whole "dynamic registration of capabilities" part of the lsp -- we don't use dynamic registration anywhere else, and I don't see why we would ever want to. We have to use it here though, because there's no other way to enable these notifications. Before #7241, we were sending these two registrations unconditionally (which violates the protocol). Now we only send |
Ah right, that makes sense. Yes, I agree with you. I also find that part of LSP kind of strange/over-engineered (tho I might be missing something).
Right, and the way that RLS does it is to dynamically register the capability for the Eglot supports that and reports that it supports EDIT: my question is:
Right. That is a correct fix, regardless of anything else. |
I am fairly confident that it is indeed strange, based both on my personal experience developing IDEs, and on studding the Dart protocol: https://htmlpreview.github.io/?https://github.com/dart-lang/sdk/blob/master/pkg/analysis_server/doc/api.html |
At the moment rust-analyzer does not fully conform to the LSP. This PR fixes two LSP related issues:
textDocument/didSave
registration even if the client does not support it.