-
Notifications
You must be signed in to change notification settings - Fork 811
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
workspace/configuration
is impossible to implement on the client side
#972
Comments
To clarify the question a little: as a client implementor, when the server requests If the expected behaviour is for the client to have intrinsic knowledge of what I realise that the actual configuration is server-specific (and user-supplied), that that's different. We're talking about how a generic client should handle a request from a server for configuration. The protocol seems to say that 'it's the client's responsibility to do the mapping', but mapping of what to what exactly. So, let's assume (as the protocol does) that there is a client-side mechanism for allowing user-supplied configuration in some manner. I feel that the under-specification of this in the protocol is perhaps a mistake, but nonetheless given that it's a JSON protocol, let's assume that there must be some configuration mechanism that can specify an arbitrary JSON value. That seems not impossible. That assumed, there are a number of places in which the client must supply configuration to the server:
The later appears to introduce a new concept 'sections'. Given the above, what is the sort of "prototypical" expectation of a client ? As Boris says, it appears that the expectation of at least 3 servers surveyed differs: Rust-analyzer:
Gopls:
Lua-Language-Server:
I think we'd all agree that clients should not have intrinsic knowledge of servers and vice-versa, as the whole "solving the matrix problem" requires that. In summary, what we're asking for is clarity on what a client implementation should or must do and should or must provide in terms of user-specified configuration that allows it to implement a LSP client without having a priori knowledge of (or require a posteriori implementation for) specific language server implementations. |
The implementation I use inside VS Code can be found here: https://github.com/microsoft/vscode-languageserver-node/blob/master/client/src/configuration.ts#L46 This is a generic implementation that simply treats every section as an entry in the configuration store. Since the VS Code store is JSON as well converting the properties is fairly simple. However I also know that for some settings a generic mapping is not enough especially if a server needs to read settings it is not necessarily owning. In the VS Code libs I therefore allow clients to plugin into the settings reading using a middleware layer. I do agree that this might require to ship some specific code or configuration per [IDE, LS] tuple but it is far away from the n x m matrix that we had before where each language features needed to be implemented for every IDE. Some additional words to configuration. There are two model:
If anyone has an idea how to better spec section I am fully open for recommendations. What I do want to avoid is to spec a settings model inside LSP since this is something every client has its own view on :-). |
@dbaeumer Thanks for replying.
Alright, I see the problem now. The same, generic implementation, in our client would work only for rust-anlyzer. For gopls, we don't store the
I have to disagree here. As long as sections are "arbitrary" in the specs and server implementers tailor them exactly to vscode, there are exactly two options:
I'm sure you can see how neither of the two are doable.
This model was perfectly implementable by clients and >80% of servers still rely on it, thankfully. The deprecation, if I'm not mistaken, is not mentioned in the specs.
That sounds reasonable. Rigid config is not necessary for client-side implementability.
What rust-analyzer is doing is conforming and implementable, so let's go with that. On
|
I have additional opinions. Currently in the specification, "section" is defined as a string type, and there is only a comment "The configuration section asked for." For example, ESlint language server sends an empty string as section. |
I worked around this problem by changing the structure of server settings in the kak-lsp LSP client, see kakoune-lsp/kakoune-lsp#511. Previously, kak-lsp users could simply set an arbitrary object for initializationOptions / didChangeConfiguration. Now we wrap this object in a "section". So instead of {
"go": {
"command": "/path/to/gopls",
"settings": {
"build.buildFlags": []
}
},
"rust": { "command": "rls" }
} kak-lsp users need to write {
"go": {
"command": "/path/to/gopls",
"settings_section": "gopls",
"settings": {
"gopls": {
"build.buildFlags": []
}
}
},
"rust": { "command": "rls" }
} which is unfortunate, but it's simplest way to support all language servers. The value of
I very much agree with that. This would work nicely for servers like {
"julia.format.indent": 4,
"julia.lint.call": true,
"some unrelated config": 123
} where we can't send correct So my suggested solution would be add this small contract to the LSP spec:
The nice part is that this change does not affect servers who only ever use settings from It seems fine to make This would require changes to language servers like
yeah, but it is only reasonable to allow creating a single object that contains all of a server's settings, independently of which requests the server supports Of course an alternative solution would be to just force deprecation of |
That's not a bad API, but isn't backwards compatible. Our starting point was the same - users could pass anything through
I had warned you this was ugly. I just couldn't think of a better way that is backwards compatible and allows for potential catering to server's wishes. If it weren't for rust-analyzer forcing us to support
Can you really deprecate/remove things in LSP? No protocol version is negotiated, so you have no idea what version of specification a server (or client) has been written against. More or less, this makes you remain both forward and backward compatible. For example, our client is "pushing" config, yet can claim
That still doesn't help with underspecification. What is |
Right, for compatibility we'd need a different name, say
Same, we mainly added it for Lua/Julia/gopls. It would be nice if all servers implemented the old configuration methods because they don't have this problem, and they are enough for most use cases. |
The solution to the n x m matrix problem in this case would be a section of the initialization message where the server announces its configuration schema (option names, types and descriptions). |
For reference: https://microsoft.github.io/language-server-protocol/specifications/specification-3-15/#workspace_configuration
This makes it impossible for the client to implement
workspace/configuration
in a generic way. It absolutely requires server-specific knowledge, which turns the "LSP is the solution to the matrix problem" mantra on its head. More specifically:Rust-analyzer
section
isrust-analyzer
server_settings[ 'rust-analyzer' ]
Gopls
section
isgopls
server_settings
Lua-language-server
section
s areLua
,files.associations
andfiles.exclude
server_settings
, and no clue what for the other twoSince a generic implementation is impossible, can we define what
section
actually means?The text was updated successfully, but these errors were encountered: