monaco-editor实现SQL代码补全
最近使用monaco-editor来实现SQL编辑器,为了提升用户体验,需要实现代码补全。研究后发现了实现方法,因此这里Mark下。
内置补全?
YES,默认monaco-editor是内置了一些语言支持,比如JavaScript
、TypeScript
、CSS
、JSON
、HTML
。 对于已内置支持的语言。 只需要将编辑器语言设置为javascript
,就可以实现代码补全了。
而比如SQL语言是没有内置支持的,当我们将编辑器语言设置为sql
,只可以实现语法高亮。
monaco.editor.create(editorElRef.current, {
...
language: 'sql',
...
autoClosingBrackets: 'always',
autoClosingOvertype: 'always',
autoClosingQuotes: 'always',
})
自定义补全?
比如SQL语言,如果想自动补全只能走自定义补全的方式解决。
调研发现可以通过monaco.languages.registerCompletionItemProvider
方法来注册对应语言的补全逻辑。
registerCompletionItemProvider方法可以定义当不同的输入上下文情况下,提供给用户的补全选项列表,当然该方法也支持异步返回,因此比如请求后台实现补全也是可行的。
registerCompletionItemProvider vs registerInlineCompletionsProvider
仔细看API会发现,补全相关的方法有两个。一般来说我们需要实现的都是registerCompletionItemProvider
,那么两者什么区别呢。
registerCompletionItemProvider提供的补全项是弹出选项列表,正如文章一开始贴出的图片,而registerInlineCompletionsProvider提供的补全项是直接显示在光标位置后
在ZSH里的话,就类似于autosuggestion
与autocompletion
的区别。
举例子
以下即实现最简单的SQL高亮,在特定的输入情况下,进行SQL关键字,数据库名称,表名称,字段名称的补全提示。
monaco.languages.registerCompletionItemProvider('sql', {
triggerCharacters: ['.', ' '],
provideCompletionItems: function (model, position) {
let suggestions: any[] = [];
const { lineNumber, column } = position;
const textBeforePointer = model.getValueInRange({
startLineNumber: lineNumber,
startColumn: 0,
endLineNumber: lineNumber,
endColumn: column,
});
const tokens = textBeforePointer.toLocaleLowerCase().trim().split(/\s+/);
const lastToken = tokens[tokens.length - 1]; // 获取最后一段非空字符串
const word = model.getWordUntilPosition(position);
const range = {
startLineNumber: position.lineNumber,
endLineNumber: position.lineNumber,
startColumn: word.startColumn,
endColumn: word.endColumn,
};
if (lastToken.endsWith('.')) {
suggestions = [...tableSuggest];
} else if (textBeforePointer.endsWith(' ')) {
if (textBeforePointer.match(/from\s+$/i)) {
suggestions = [...databaseSuggest];
} else if (textBeforePointer.match(/where\s+$/i)) {
suggestions = [...columnSuggest];
} else {
suggestions = [...sqlKeywordsSuggest];
}
} else {
suggestions = [...sqlKeywordsSuggest];
}
console.log('suggestions', suggestions);
return {
suggestions: suggestions.map(item => ({
...item,
range,
})),
};
},
})
写在最后
通过上述方法即了解了如何在monaco-editor中实现SQL代码补全,延伸下该方法,实际上也可以通过AI服务实现SQL代码补全,毕竟Monaco提供的补全注册方法是支持异步返回的。