最近使用monaco-editor来实现SQL编辑器,为了提升用户体验,需要实现代码补全。研究后发现了实现方法,因此这里Mark下。
内置补全?
YES,默认monaco-editor是内置了一些语言支持,比如JavaScript
、TypeScript
、CSS
、JSON
、HTML
。 对于已内置支持的语言。 只需要将编辑器语言设置为javascript
,就可以实现代码补全了。
而比如SQL语言是没有内置支持的,当我们将编辑器语言设置为sql
,只可以实现语法高亮。
1 2 3 4 5 6 7 8
| 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关键字,数据库名称,表名称,字段名称的补全提示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| 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提供的补全注册方法是支持异步返回的。