monaco-editor version: 0.20.0
Browser: Chrome
OS: Windows
Reproduction steps:
ctrl left click on IdentifierA in line 1
=> IdentifierA in line 3 blinks and Cursor jumps to line 3 => OK!
ctrl + MouseOver on IdentifierB in line 2
=> Identifier B is underlined; small widget pops up showing reference "another IdentifierB" => OK!
I was able to fix this bug:
a) insert
editor.setModel(model);
in standaloneCodeServiceImpl.ts after line 43
b) replace
return null;
whith
return monaco.editor.getModels().find(model => model.uri.toString() === resource.toString());
in Method StandaloneCodeEditorServiceImpl.findModel
Instead of b) it would certainly be better to use SimpleEditorModelResolverService, but i don't know how to get a reference of it so i better refrain from making a pull request on base of my amateur work.
By the way:
I'm writing an online-IDE with compiler for my students. Without monaco editor this would not be possible:
Editor Playground html:
<div id="container" style="height:100%;"></div>
Editor Playground css:
none
Editor Playground js:
const editor = monaco.editor.create(document.getElementById("container"), {});
const model1 = monaco.editor.createModel("identifierA\nIdentifierb\nanother IdentifierA", "python", monaco.Uri.from({
scheme: "inmemory",
path: "file1.macc",
}))
const model2 = monaco.editor.createModel("another Identifierb", "python", monaco.Uri.from({
scheme: "inmemory",
path: "file2.macc",
}))
editor.setModel(model1)
monaco.languages.registerDefinitionProvider("python", {
provideDefinition: (model, position, token) => {
if (position.lineNumber == 1) {
return {
uri: model1.uri,
range: {
startLineNumber: 3,
startColumn: 9,
endLineNumber: 3,
endColumn: 20
}
}
}
if (position.lineNumber == 2) {
return {
uri: model2.uri,
range: {
startLineNumber: 1,
startColumn: 9,
endLineNumber: 1,
endColumn: 20
}
}
}
}
});
I think it would not be a good idea to implement this feature generally; or at least it should be configurable to keep the current behavior. I would assume most use cases use a single editable model (the one that's shown), accompanied by zero or more additional models.
For example: We add several models to the editor (all .js, or .d.ts files) to provide code completion for complex scenarios, but would never ever ever want a user to navigate there in the same editor instance by invoking "Go to definition". Because that would mean we are now in a state that is absolutely meaningless to the user, and additionally there is no way for the user to get back to the old model.
However, I see a need to provide functionality like this - even in our use case. We would like for the user to "Go to definition" for specific models. Not in the same editor instance, but rather in a new tab. Today we accomplish that by hijacking the openEditor function on the StandaloneCodeEditorServiceImpl class. If the original function returns null we just check if it is a valid model to jump to, and then open a new tab displaying that code, but leaving the original editor in the same state.
Playground code:
monaco.editor.createModel("const foo = 1;", "javascript", monaco.Uri.file("foo.js"));
const editor = monaco.editor.create(document.getElementById("container"), {
value: `function hello() {
alert('Hello world!');
}
hello();
foo`,
language: "javascript"
});
const editorService = editor._codeEditorService;
const openEditorBase = editorService.openCodeEditor.bind(editorService);
editorService.openCodeEditor = async (input, source) => {
const result = await openEditorBase(input, source);
if (result === null) {
alert("intercepted")
console.log("Open definition for:", input);
console.log("Corresponding model:", monaco.editor.getModel(input.resource));
}
return result; // always return the base result
};
By adjusting the code a bit I would assume you could use the same technique to open the found editor model in the same editor instance (the source parameter is a ICodeEditor instance).
The downside is that this is not an official API. So the question is could there be an official API endpoint that enables registering some kind of provider/handler that kicks in when the standard implementation does not find a model (i.e. the if block in my hacky implementation)? If we settle on an approach and I find some time, I would be happy to provide a PR.
Thoughts?
Dear Mr. Pahnke,
thank you for your proposal! I'm able to achieve the desired functionality with this code:
const editorService = editor._codeEditorService;
const openEditorBase = editorService.openCodeEditor.bind(editorService);
editorService.openCodeEditor = async (input, source) => {
const result = await openEditorBase(input, source);
if (result === null) {
alert("intercepted")
console.log("Open definition for:", input);
console.log("Corresponding model:", monaco.editor.getModel(input.resource));
console.log("Source: ", source);
source.setModel(monaco.editor.getModel(input.resource));
}
return result; // always return the base result
};
So an official API endpoint that enables registering some kind of provider/handler that kicks in when the standard implementation does not find a model would be a good solution.
Most helpful comment
Dear Mr. Pahnke,
thank you for your proposal! I'm able to achieve the desired functionality with this code:
So an official API endpoint that enables registering some kind of provider/handler that kicks in when the standard implementation does not find a model would be a good solution.