Language service
LanguageService is what an editor asks of the language side, in protocol shapes. @adecore/editor-react takes one; the app writes it over its servers. It can route a document to one server or several, start servers on demand, or reach a remote machine. An LspSession is not one itself: a session is one server, and a service is everything a project's documents can ask.
The interface
| Group | Members |
|---|---|
| Documents | openDocument(document), changeDocument(uri, changes), closeDocument(uri) |
| Providers | supports(method, uri), providerOptions(method, uri), onProvidersChanged(listener) |
| Diagnostics | onDiagnostics(listener), with DiagnosticsReports |
| Requests | One per feature of LspDocument, with the uri first, plus workspaceSymbols and executeCommand |
Every request takes LanguageRequestOptions: a signal, and parallel: true for requests of one feature that should run side by side instead of each cancelling the one before, such as counting the references of several declarations. Map it to cancelPrevious: false when the service hands a request to an LspDocument.
What a service promises
openDocumentopens the document, or joins it when another client of the service has it open; the text it gets then replaces what is held.changeDocumentappliesContentChanges in order and raises the version by one.closeDocumentlets go; a service shared by several clients closes the server's document after the last one.- An answer for a text that moved on rejects with
StaleResultError. A method nothing supports rejects with anLspErrorof-32601, and a server that is not up with-32002. onProvidersChanged(uri)fires when what a document can ask changed: its server came up, registered a capability or asked for a refresh. The editor features ask once when a document opens, so fire it when a server comes up for a document that is already open.- A
DiagnosticsReporthas theuri, thesource(which server), an optionalversionand thediagnostics. A report replaces the earlier one of the same source, so give each server a stable source and send an empty report when its problems are gone. - A completion item, code action, lens or hint resolves on the server that produced it, and so does the command of an action.
The package ships no service over processes. A small one over a single session hands each method to the open LspDocument, keeps a count of clients per URI, and turns session.onCapabilitiesChanged and onDiagnostics into the two events. Server discovery, installing, starting and permissions stay in the app.
Vue and TypeScript
A Vue file has two servers: the Vue language server for the template and TypeScript for the scripts. bridgeVueTypeScript(vue, typescript) relays the Vue server's tsserver/request notifications to the TypeScript server's typescript.tsserverRequest command and sends the answer back, null when TypeScript failed, so Vue never waits forever. Attach it before the Vue session initializes, open each .vue document in both sessions, TypeScript first, and dispose the bridge before the sessions. The TypeScript server needs the Vue plugin configured; the bridge does not do that.
const bridge = bridgeVueTypeScript(vue, typescript);
await typescript.initialize();
await vue.initialize();vueServerOrder(method, text, params) says which of the two to ask first for a request, the other being the fallback when the first does not support the method: TypeScript first inside a <script> block, an interpolation or a v-, : or @ attribute, and for inlay hints; Vue first everywhere else. isVueExpression(text, offset) is the lexical test behind it. Neither is a Vue parser.