monaco-languageclient
monaco-languageclient copied to clipboard
Error: Unable to read file
Hello team,
When I try to use Peek References feature to see all the references of the function declared in the code but it throws the below error message:
Unable to read file '/workspace/file.java' (Error: Unable to resolve nonexistent file '/workspace/file.java')
I’m using [email protected] and [email protected].
Code:
import * as monaco from 'monaco-editor';
import { initServices } from 'monaco-languageclient/vscode/services';
import { MonacoLanguageClient } from 'monaco-languageclient';
import { WebSocketMessageReader, WebSocketMessageWriter, toSocket } from 'vscode-ws-jsonrpc';
import { CloseAction, ErrorAction, MessageTransports } from 'vscode-languageclient';
let editor = null;
let languageClient = null;
let webSocket = null;
const startClient = async (value, language, fileUri) => {
await initServices({});
editor = monaco.editor.create(editorNode, {
minimap: {
enabled: false,
},
theme: "vs-dark",
});
let editorModel = monaco.editor.createModel(
value,
language,
monaco.Uri.parse(fileUri)
);
editor.setModel(editorModel);
webSocket = initLspConnection(`ws://localhost:8080/${language}`);
};
const initLspConnection = (url, language): WebSocket => {
webSocket = new WebSocket(url);
webSocket.onopen = async () => {
const socket = toSocket(webSocket);
const reader = new WebSocketMessageReader(socket);
const writer = new WebSocketMessageWriter(socket);
languageClient = createLanguageClient({
reader,
writer,
}, language);
await languageClient.start();
reader.onClose(async () => await languageClient.stop());
};
return webSocket;
};
const createLanguageClient = (transports, language) => {
return new MonacoLanguageClient({
name: "Sample Language Client",
clientOptions: {
workspaceFolder,
documentSelector: [language],
errorHandler: {
error: () => ({ action: ErrorAction.Continue }),
closed: () => ({ action: CloseAction.DoNotRestart }),
},
},
connectionProvider: {
get: () => {
return Promise.resolve(transports);
},
},
});
};
// calling this on language change
const onChange = async (language, fileUri, value) => {
await dispose();
let editorModel = monaco.editor.createModel(
value,
language,
monaco.Uri.file(fileUri)
);
editor.setModel(editorModel);
webSocket = initLspConnection(`ws://localhost:8080/${language}`);
};
const dispose = async () => {
if (languageClient) {
await languageClient.dispose();
languageClient = null;
}
if (webSocket) {
webSocket.close();
webSocket = null;
}
};
startClient("", 'java', myFilePath)
can you please tell me how can I enable the peek references feature? It works in official monaco editor by default but not with the monaco-vscode-api.
Are the references in the same file?
Anyway, the issue is that you use the monaco.editor.createModel syntax to create the model, which create a standalone model not "linked" to a file on a virtual filesystem.
You better create the file on the virtualfilesystem, then use the createModelReference instead
If you want to find references in other files, every files should exist on the memory filesystem
@CGNonofr yes, the references are in the same file. In the official monaco editor package, this feature works by using creatModel syntax so I thought it will work here as well.
In my setup, it’s quite complicated to use async createModelReference that’s why I’m using createModel. Is there any way to make it work using createModel?
If you want to full explanation:
- in monaco-editor, the textModelService (responsible to find or create the model associated with the file uri) is overriden with a dumb implementation that just returns any created model on that uri
- with this package, the VSCode implementation is restored to be able to reference non-open files if the model service override is used
Unfortunately, the model-service override is flagged as required here and I don't think you can not be using it (@kaisalmen do you confirm)?
@CGNonofr Thanks for your explanation!
I have some more questions around createModelReference usage.
When you say 'virtual filesystem’ does that mean the file should exist on the server?
What about languages that don’t require a file to exist on the server, for example, HTML, which provides intellisense using a web worker rather than via LSP? And what if, in some cases, I don’t want to use LSP, just want to use what monaco-editor provides by default and in that case, no file will exist on server. should I still use createModelReference? What should I do in this case?
can you please help me understand when should I use createModelReference and when should I use createModel?
One more thing: why is it not recommended to use second param of createModelReference?
When you say 'virtual filesystem’ does that mean the file should exist on the server?
What I mean by virtual filesystem is the fileSystemProvider registered in the file service. In most cases and by default, it uses a RegisteredFileSystemProvider that is empty by default and allows to registered some static files in it (with content and save callback)
By if you use a remote Language Server, it's your responsability to make sure the virtual filesystem client-side is synchronized with the filesystem accessible to the remote language server. It's the tricky part, and there is multiple ways of achieving it depending on your needs. You can for instance replace the default filesystem implementation by one of yours
What about languages that don’t require a file to exist on the server, for example, HTML, which provides intellisense using a web worker rather than via LSP?
I'm not sure what you are talking about: the VSCode html extension or the monaco worker
The HTML VSCode extension is actually using LSP, the server just runs in a webworker and the web extension makes sure the worker server has access to the VSCode virtual filesystem
The monaco worker does pretty much the same, except it relies on the list of open models using the monaco-editor api instead of the vscode virtual filesystem
And what if, in some cases, I don’t want to use LSP, just want to use what monaco-editor provides by default and in that case, no file will exist on server. should I still use createModelReference? What should I do in this case?
The monaco intellisense workers are only able to see open models, which can be fine.
The issue with createModel is you can't call it twice on the same uri, so if you create your model this way, then the intellisense ask for a references on that model, it will try to create that model once again and will crash.
As said before, the standalone implementation of the textModelService works well with that, because when a references is created, it just return an immortal references to the existing model, or throw an error
So you either need to keep the standalone textModelService, or switch to createModelReference. Keep in mind that the first one won't allow to open files not already open
I'm not sure what can prevent you from using createModelReference. I guess that's because you're storing the model in your state somewhere. The alternative is to never store models, but only the file uris, and call createModelReference only to feed the editor or play with it a bit, then release it when not required anymore
I'm not sure what you are talking about: the VSCode html extension or the monaco worker
I’m talking about the html css workers that we import from this package: @codingame/monaco-vscode-standalone-html-language-features
If we use this worker for html then it provides the intellisense without keeping the html file in server, right? But I think references feature won’t work if I use createModel, right?
One question: I’m not able to understand from the readme when should I dispose the model reference. Should I dispose it immediately after extracting the textEditorModel from the reference as I don't need it for anything else except the editor model data. Or should I dispose it when I dispose an actual model i.e. on editor unmount?
If we use this worker for html then it provides the intellisense without keeping the html file in server, right? But I think references feature won’t work if I use createModel, right?
It's not really about the workers. Either you enable the model service override and you have to use createModelReference, or you don't and using createModel is fine
Btw, I don't know what "the server" mean to you, we are talking about something fully client side here
One question: I’m not able to understand from the readme when should I dispose the model reference. Should I dispose it immediately after extracting the textEditorModel from the reference as I don't need it for anything else except the editor model data. Or should I dispose it when I dispose an actual model i.e. on editor unmount?
I think the name is pretty straighforward: it's a reference to the model: it need to be kept as long as you need the model. The model will be destroyed as soon as there is no reference left on it
Okay, got it! We need to keep the model reference until we need the editor text model.
We don’t need to dispose the model separately. If we dispose all the references to that model, the model will be automatically dispose.
Thanks for the detailed answer!
@shivam6543 are you ok to close the issue?