前言
最近在搞一个在线python编辑代码的功能,因为平时都在用vscode在码代码所以就用了monacoEditor作为在线代码的库。目前为止遇到的问题都来自于自动完成建议项这功能,在这里记录下方便以后查看,有遇见类似问题的朋友也可以参考下。
问题1:建议项需要异步
因为在线编辑是用jupyter作为线上语言服务,而jupyter可以根据当前输入code返回代码提示项。
前端要解决的问题就是能否异步获取这些提示项。查看了下官网文档发现provideCompletionItems该方法需返回ProviderResult类型,而ProviderResult支持Thenable,那问题就很好解决了。实现方法如下(我们用settimeout模拟异步请求,在https://microsoft.github.io/monaco-editor/playground.html?source=v0.36.1#example-creating-the-editor-hello-world中把代码复制到对应地方就能看到效果,输入t等1秒就能看见suggest dialog内容)
monaco.editor.registerCommand(
"editor.suggest",
(accessor, ...args) => {
// DO SOMETHING
console.log(args)
}
);
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,
command: id.command || undefined,
range: {
startLineNumber: position.lineNumber,
startColumn: wordUntilPosition.startColumn,
endLineNumber: position.lineNumber,
endColumn: wordUntilPosition.endColumn - 1,
},
}));
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
suggestions
})
}, 1000)
})
return promise;
}
},
});
const completionTriggerKeywords = [
{
label: 'est1',
kind: monaco.languages.CompletionItemKind.Function,
insertText: 'Test1',
description: '1.1, 1.2, 1.3',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
command: {
id: "editor.suggest",
arguments: ['est1']
}
},
{
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',
}
];
monaco.editor.create(document.getElementById("container"), {
value: " ",
language: "java"
});
问题2:在用户选择了建议项提供回调
客户希望当他选择了suggest dialog中的某些提示项以后对编辑器中的一些code做操作。如下:
当选择用"提示项1"时,希望把print(“test code”)这串代码清空(或者去请求远程服务器上的数据等等)。我需要告诉程序,用户什么时候触发了选择提示项这一动作。搜索引擎上搜索半天都没有给出我想要的效果,幸运的是GitHub上偶然间看到别人也问过类似的问题。这里的解决方案分两个步骤:
- 需要在monaco中注册一个命令
window.monaco.editor.registerCommand(
"editor.suggest",
(accessor, ...args) => {
// DO SOMETHING
console.log(args)
}
);
- 在provideCompletionItems返回的suggestions中添加一个command参数, arguments就是传递参数
const suggestions = [
{
label: 'est1',
kind: monaco.languages.CompletionItemKind.Function,
insertText: 'Test1',
description: '1.1, 1.2, 1.3',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
command: {
id: "editor.suggest",
arguments: ['est1']
}
}]
运行上面 问题1 的代码,打开浏览器控制台,在选择est1时就能调用注册的“editor.suggest”命令。