Actually I'm looking into a way in which I can achieve all these following cases.
1 - I can provide only custom suggestions. If no suggestion is present. Then nothing(blank) should be shown as suggestion.
2 - I can provide only Monaco default suggestion(words existing in the editor).
3 - I can provide custom suggestion + Monaco default suggestion(words existing in the editor).
What's the current existing behavior?
1 - I can achieve first case by returning a suggestion or a blank suggestion.
2 - I can achieve second case by not returning any suggestion(not even the blank suggestion object).
Is there's a way to achieve third case?
I don't believe 3 is currently doable.
But from reading the code here -- https://github.com/microsoft/vscode/blob/8758dc9dddf95f358eb93c969353e5cf245ed1e4/src/vs/editor/contrib/suggest/suggest.ts#L180-L181 -- I can deduce that the word completion provider is in a different group than the custom completion provider and once you return a result, the process stops and it doesn't get invoked.
I could not figure out what creates the grouping, but I can see here -- https://github.com/microsoft/vscode/blob/8758dc9dddf95f358eb93c969353e5cf245ed1e4/src/vs/editor/common/services/editorWorkerServiceImpl.ts#L76 -- that the word completion provider is registered with * as a selector.
You could potentially try to register your completion provider with * as well, and then check the passed in model and check if it has your language and only return results if it is your language... Perhaps that would make it that your custom completion provider is placed in the same group as the default word completion provider?
Thanks for the help. I will look into this.
hi, akshay-zz, did you find any ways to solve this problem?
I meet this same problem in my project锛亀ish your repley, thx!
hi, akshay-zz, did you find any ways to solve this problem?
Right now I'm not working into this. But soon will try to achieve this as per hint given by @alexdima .
I think something like this could help. I haven't tested the else part. Right now I'm not working on this. But if someone can try to achieve this and share with us, then that would be great. Even thought this trick does not satisfy third case completely. But I think this will help and by doing little work around by summing up word suggestion and server suggestion we can achieve the third case.
monaco.languages.registerCompletionItemProvider('csharp', {
triggerCharacters:["."],
autoIndent:true,
provideCompletionItems: function(model, position) {
var word = model.getWordUntilPosition(position);
var range = {
startLineNumber: position.lineNumber,
endLineNumber: position.lineNumber,
startColumn: word.startColumn,
endColumn: word.endColumn
};
// hit server only when dot is pressed (not for any other character)
if ((word.word).length<1 ) {
// fetch suggestion from server
var pos = getLengthTillWhereCusrorIsPresent(position);
return fetchSuggestion(pos).then(function(res) {
return {
suggestions:res
}
})
} else {
// give suggestion from cache
//return { suggestions : createDependencyProposals() }
var word = model.getWordAtPosition(position);
var replace = !word ? Range.fromPositions(position) : new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn);
var insert = replace.setEndPosition(position.lineNumber, position.column);
const client = this._workerManager.withWorker();
const words = client.textualSuggest(model.uri, position);
if (!words) {
return undefined;
}
return {
suggestions: words.map((word): modes.CompletionItem => {
return {
kind: modes.CompletionItemKind.Text,
label: word,
insertText: word,
range: { insert, replace }
};
})
};
} // else end
}
});
Haven't tested else part and quite sure will fail. Just added to give a approach if anyone love to work on this. Else part code is taken from here
I think something like this could help. I haven't tested the else part. Right now I'm not working on this. But if someone can try to achieve this and share with us, then that would be great. Even thought this trick does not satisfy third case completely. But I think this will help and by doing little work around by summing up word suggestion and server suggestion we can achieve the third case.
monaco.languages.registerCompletionItemProvider('csharp', { triggerCharacters:["."], autoIndent:true, provideCompletionItems: function(model, position) { var word = model.getWordUntilPosition(position); var range = { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: word.startColumn, endColumn: word.endColumn }; // hit server only when dot is pressed (not for any other character) if ((word.word).length<1 ) { // fetch suggestion from server var pos = getLengthTillWhereCusrorIsPresent(position); return fetchSuggestion(pos).then(function(res) { return { suggestions:res } }) } else { // give suggestion from cache //return { suggestions : createDependencyProposals() } var word = model.getWordAtPosition(position); var replace = !word ? Range.fromPositions(position) : new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn); var insert = replace.setEndPosition(position.lineNumber, position.column); const client = this._workerManager.withWorker(); const words = client.textualSuggest(model.uri, position); if (!words) { return undefined; } return { suggestions: words.map((word): modes.CompletionItem => { return { kind: modes.CompletionItemKind.Text, label: word, insertText: word, range: { insert, replace } }; }) }; } // else end } });Haven't tested else part and quite sure will fail. Just added to give a approach if anyone love to work on this. Else part code is taken from here
@akshay-zz This code is not working as the 'this' in const client = this._workerManager.withWorker(); doesnt point to 'WordBasedCompletionItemProvider' and thus it throws error
Haven't tested else part and quite sure will fail. Just added to give a approach if anyone love to work on this. Else part code is taken from here.
@Pranomvignesh I never said it will work.
@akshay-zz I just added my point about why the else part will fail, so that in future the users wont need to work it out to find out what went wrong
Has any one able to find a solution for this ? I am also stuck looking for a solution for scenario 3.
I came up with this hack...not the most efficient, but does the job.
I have my snippets combined with words already typed in the editor.
https://gist.github.com/cnayan/23cfde150a83f33a5e4da3b59284ea2b
The below simple method (could be a hack ) worked for me without much tweaking and merging. Copy paste to monaco playground to check it in action. I used the "range" property. I had to disable consistent-return of eslint as there is nothing in the else part of the "if" check ( I believe you can return empty array [] there and check ).
monaco.languages.registerCompletionItemProvider('java', {
provideCompletionItems: (model, position) => {
const wordBeforePosition = model.getWordUntilPosition({
lineNumber: position.lineNumber,
column: position.column - 1,
});
const wordUntilPosition = model.getWordUntilPosition(position);
if (wordBeforePosition.word.trim() === '' || wordUntilPosition.word.trim() === '') {
const keywords = completionTriggerKeywords;
const suggestions = keywords.map(id => ({
label: id.label,
kind: id.kind,
description: id.description,
documentation: id.description,
insertText: id.insertText,
detail: id.description,
insertTextRules: id.insertTextRules,
range: {
startLineNumber: position.lineNumber,
startColumn: wordUntilPosition.startColumn,
endLineNumber: position.lineNumber,
endColumn: wordUntilPosition.endColumn - 1,
},
}));
return {suggestions};
}
},
});
const completionTriggerKeywords = [
{
label: 'Test1',
kind: monaco.languages.CompletionItemKind.Function,
insertText: 'Test1',
description: '1.1, 1.2, 1.3',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
},
{
label: 'Test2',
kind: monaco.languages.CompletionItemKind.Function,
insertText: 'Test2',
description: '2.1',
},
{
label: 'Test3',
kind: monaco.languages.CompletionItemKind.Function,
insertText: 'Test3',
description: '3.1, 3.2, 3.3',
},
{
label: 'Test4',
kind: monaco.languages.CompletionItemKind.Function,
insertText: 'Test4',
description: '4.1',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
},
{
label: 'Test5',
kind: monaco.languages.CompletionItemKind.Function,
insertText: 'Test5',
description: '5.1',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
},
{
label: 'Test6',
kind: monaco.languages.CompletionItemKind.Function,
insertText: 'Test6',
description: '6.1',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
},
];
monaco.editor.create(document.getElementById("container"), {
value: " ",
language: "java"
});
There could be some unseen issues, but this could be a good starter for someone looking for a solution.
Most helpful comment
I don't believe 3 is currently doable.
But from reading the code here -- https://github.com/microsoft/vscode/blob/8758dc9dddf95f358eb93c969353e5cf245ed1e4/src/vs/editor/contrib/suggest/suggest.ts#L180-L181 -- I can deduce that the word completion provider is in a different group than the custom completion provider and once you return a result, the process stops and it doesn't get invoked.
I could not figure out what creates the grouping, but I can see here -- https://github.com/microsoft/vscode/blob/8758dc9dddf95f358eb93c969353e5cf245ed1e4/src/vs/editor/common/services/editorWorkerServiceImpl.ts#L76 -- that the word completion provider is registered with
*as a selector.You could potentially try to register your completion provider with
*as well, and then check the passed in model and check if it has your language and only return results if it is your language... Perhaps that would make it that your custom completion provider is placed in the same group as the default word completion provider?