LSP
LSP copied to clipboard
Multiple session and request handling
The new version of Volar (Vue Language Features) is expected to run in Vue files alongside a typescript server (LSP-typescript, for example). This seems to create issues with handling of some requests since some requests are supposed to go to LSP-volar and some to LSP-typescript. For example within a script tag like:
<script lang="ts">
export default {
methods: {
getSomething(key: string): HTMLElement {
// ...
}
}
}
</script>
- "expand selection" request should go to LSP-volar
- "go to definition" should go to LSP-typescript
We have prioritity_selector which can force all requests go to one or the other but in this case it doesn't help because we need different behavior for different requests and scopes are not sufficient for determining which one to trigger.
Observing VSCode, it seems like triggering "go to definition" triggers requests both to Volar (which returns an empty list) and its internal Typescript server (note that it's not technically LSP-based in there).
But then I also see some issues with expand selection in VSCode that I don't see in ST. For example here it incorrectly expands selection to just set or Timeout in setTimeout:
https://github.com/user-attachments/assets/14374961-7651-4bee-9662-01ecaac96bbc
So not sure what is the best way for handling this issue.
Thanks for the info @rchl .
I feel a bit down that Volar decided to require LSP clients to invest time and thoughts just to make it work. We stumbled upon a few language servers that required a bit of client side code, but this is not the same. There are a few language servers that gives priority to VS Code, to only work there by default, and they do not take into account other LSP clients, I do not encourage that.
I would not with invest my time in adopting this approach. I cannot say that Volar is not following the spec. But deciding what request should be handled by what server is not something that is seen so far. Why does Volar do that?
Sorry for the ping @johnsoncodehk, is there a discussion on GitHub where we can get some insights on why things are done the way they are done?
To be fair it can run independently from LSP-typescript when changing the hybridMode setting to false. Though that's less memory efficient and maybe with some other downsides.
Regardless of Volar, I'm thinking that it makes sense to request data from multiple servers for requests that return a list of things (definition, references etc). We are already doing it for things like code actions after all.
I misunderstood the issue.
Is the request is to send a request to all language servers supporting the capability?
Initially I thought the the request is to introduce a mechanism to orchestrate certain requests to certain language servers.
Initially I thought the the request is to introduce a mechanism to orchestrate certain requests to certain language servers.
I've intended to describe the problem in this issue rather than suggesting specific solution. So what you've mentioned could potentially be a solution but likely not the most optimal. Requesting Location's from multiple capable servers seems like the correct thing to do though.
I don't use multiple servers at the same time, but I imagine for definitions, references, etc. to merge the responses would not be very useful, because then you would have duplicate results everywhere. In particular if you use "goto definition" on a symbol, instead of directly scrolling to the location or opening the file, it would then always open the command palette first with the available results. So it would require an additional step with user input.
For cases where there are two servers running that handle similar functionality (pyright and pylsp for example) it could be a problem indeed. It's solvable by disabling relevant capabilities or server settings though.
I'm thinking more of cases like Single File Components where there are multiple servers running to handle different parts of the file. That case would benefit from this feature and there should be no issues since then only one of the servers should respond with non-empty response for any particular location.
I'm thinking more of cases like Single File Components where there are multiple servers running to handle different parts of the file.
Okay. But shouldn't this already be possible? The "Goto" features use best_session which should select the appropriate session via the best scope name match for the position:
https://github.com/sublimelsp/LSP/blob/a6b17a4aa4d10d8ddc225413d221c4241b877f8b/plugin/core/registry.py#L24-L33
For example a <style> block in a HTML file has the scope text.html.basic source.css.embedded.html and
>>> sublime.score_selector('text.html.basic source.css.embedded.html', 'text.html.basic')
6
>>> sublime.score_selector('text.html.basic source.css.embedded.html', 'source.css')
32
If LSP-typescript and LSP-volar use the same base "selector", shouldn't it work if one of them increases the priority for script blocks via "priority_selector"?
If LSP-typescript and LSP-volar use the same base
"selector", shouldn't it work if one of them increases the priority for script blocks via"priority_selector"?
Check my initial comment for the exact case where this wouldn't work.
Oh, right. I guess then it would need something to set the priority for a given position and for each request type individually.
Still I think just sending requests to all sessions and then merging all responses would be the wrong approach. It works for things like code actions and diagnostics because those are more or less unique to each language server.
I think I can manage that by just disabling conflicting capabilities for the vue server as part of enabling "hybrid mode" (which will be done on explicit action and stored in project settings).
rename/prepareRename is another functionality that shows the issue with LSP-vue/LSP-typescript running together - https://github.com/sublimelsp/LSP-vue/issues/164
I suppose in that case it would be somewhat reasonable to try every server until non-empty response is provided.