monaco-languageclient
monaco-languageclient copied to clipboard
@typefox/monaco-editor-react - multiple files, one lsp websocket connection
Greetings!
I have a problem with @typefox/monaco-editor-react, that I can't make it work with multiple opened files that share one WS connection to a lsp server. Whenever I open the second file it tries to initialize already opened connection and I get this in the console:
after that the popup with suggestions starts to display "loading" and nothing more in both editors. Moreover onTextChanged callback is triggered for the first editor exclusively. The lsp connection looks fine and continues to send/receive requests though.
So the question: is it even possible to use MonacoEditorReactComp so that it can handle one connection for multiple files?
I use custom SharedWorker that initializes WS connection and serves as a proxy between the lsp server and the language client itself:
- worker.ts
declare const self: SharedWorkerGlobalScope;
const connectedPorts = new Set<MessagePort>();
const ws = new WebSocket('wss://address/to/lsp');
ws.onmessage = e => connectedPorts.forEach(port => port.postMessage(JSON.parse(e.data)));
self.addEventListener('connect', e => {
const port = e.ports[0];
connectedPorts.add(port);
port.onmessage = e => {
ws.send(JSON.stringify(e.data));
};
});
export {};
- index.ts file with the worker instantiation
export default new SharedWorker(new URL('./worker.ts', import.meta.url), { type: 'module', name: 'Julia LSP Server' });
- user-config.ts
import * as vscode from 'vscode';
import lspWorker from './lsp-worker';
export const userConfig = {
languageClientConfig: {
options: {
name: 'Julia Language Server',
$type: 'WorkerDirect',
worker: new Worker(new URL('', import.meta.url), { type: 'module' }),
messagePort: lspWorker.port
},
clientOptions: {
documentSelector: ['julia'],
workspaceFolder: {
index: 0,
name: 'workspace',
uri: vscode.Uri.parse('/workspace')
}
}
},
wrapperConfig: {
editorAppConfig: {
languageId: 'julia',
codeUri: `/workspace/${fileName}.jl`
}
}
};
Have to say that if I unmount a component with the first editor before mounting the second one it works fine. But I need to keep them opened in order to preserve their contexts in case the user walks through the tabs with these editors.
I tried to search the answer in the examples folder and here, in issues, but had no luck. Thanks in advance.
Hi @apathoid thank you for reporting this. Can you share a repository, so I can re-produce this?
Have you tried this without the proxy (reduce the complexity first and see if it works)? How do you open the second file? When you use a worker, there is no need for a web-socket connection, btw.
I have a remote lsp server that is maintained by our backend team. This is the reason why I need a WS connection (if I understood your last statement correctly). I establish it inside a SharedWorker, because I want to be able to use the same WS connection across multiple editors (and browser tabs) with the same language.
Here is the example of what I'm trying to achieve. There is no real lsp server there, but the idea and behavior are nearly identical to what I have in my real app.
If you create one file you'll see the 'initialize' message in the dev tools and then, when you open the second file, you'll get the exactly same message. In the real app it looks like this:
when I open the first file
when I open the second file
Also I can't open two editors simultaneously: they just double requests and only one of them remains functioning (the second one doesn't trigger onTextChanged callback):
What you are trying to do is plugging multiple clients on the same language server connection, which is not supported out of the box.
You may need something like https://github.com/CodinGame/languageserver-mutualized
You can probably run it in a shared worker even though it was designed to run in node
@CGNonofr, thank you. I'll give it a try