microsoft / language-server-protocol

Defines a common protocol for language servers.
https://microsoft.github.io/language-server-protocol/
Creative Commons Attribution 4.0 International
11.08k stars 772 forks source link

A way for a LS to declare its project association cardinality #674

Open mickaelistria opened 5 years ago

mickaelistria commented 5 years ago

With the XML language server and many others, a same LS can be used for any matching file on filesystem and no new instance is required. At the moment, the only specified concept regarding multiplicity, association and spawning language servers is through workspaceFolders ( #281 , #289 ). But for the LS that have no interest at all in workspaceFolders, it seems strange to declare this compatibility. Instead, the spec could have as a ServerCapability a flag describing whether it can serve arbitrary files, ignoring the rootUri and workspaceFolders.

mickaelistria commented 5 years ago

More concretey, how does VSCode decide.to spawn a new LS or to re use an existing one for a given file?

LaurentTreguier commented 5 years ago

For VSCode, there has to be an extension that bridges VSCode with the LS. It's up to the extension to decide how and when to spawn new language server instances.

mickaelistria commented 5 years ago

Thanks for the insight @LaurentTreguier . I think this state is rather suboptimal, a more generic way to decide whether to spawn a LS or not could be achieved with some extra declarations in the Language Server. The workspaceFolders are already an answer in some cases, but it's also not optimal. What about a field serverInstanceScope in ServerCapabilities that could take values such as anyFile or projectFiles

LaurentTreguier commented 5 years ago

This could be useful. Although VSCode allows implementors to spawn servers as they please, some other editors don't allow this. However, in cases like VSCode, since it's the extension author's responsibility to start the server, it would also still be the author responsibility to keep track of the server and properly re-use it, regardless of serverInstanceScope.

mickaelistria commented 5 years ago

in cases like VSCode, since it's the extension author's responsibility to start the server, it would also still be the author responsibility to keep track of the server and properly re-use it, regardless of serverInstanceScope.

Maybe VSCode would one day be able to provide an API wrapping this and taking care of spawning the server as described if necessary. So extenders would provide a function describing how to start the LS and connect to it, and VSCode would use it when necessary. It's how Eclipse LSP4E works at the moment, and integrating an existing language server is really easy with this approach: it's mostly declarative (bind content-type with Language Server definition) and only 1 basic piece of code is required to define what's the command-line to start the LS.

dbaeumer commented 5 years ago

I am not sure if this should be a property or something the server declares in the doc. Consider the case where a user opens a workspace with two folders. Should we start one server and then wait what the initialize result tells us and then may be start a second?

mickaelistria commented 5 years ago

Declaring in the doc puts the responsibility and difficulty of handling the multiplicity and lifecycle of language servers to the integration hand. I think the number of cases is finite enough to aim for something that can be automated by the client. But it's indeed not trivial as your example question points out.

Ideally, I think that before sending an initialize that has a rootURI, the language server could/should send (maybe as a notification) a note about it's multiplicity/scope capabilities. Some data like scopeCapability: "root" | "root-less" addiitonally to the declaration of workspaceFoldersCapabilities. I think with those 2 cases, the client could know how to handle most cases, and would be able to reliably decide whether to spawn a new instance of the LS or reuse an existing one.

Should we start one server and then wait what the initialize result tells us and then may be start a second?

Pragmatically,itI would be fine from my POV and easy enough to implement in LSP4E. It would only require an additional serverCapability without altering the flow of messages. LSP4E -and other clients- would just have to avoid spawning the same LS too fast. In LSP4E, it's somehow already what we do as we check the workspaceFolders capability of started LS to decide whether to spawn a new one or reuse it.