monaco-editor实现SQL编辑器功能——自定义语法提示

5,912 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情

一、前言

项目中需要用到代码编辑器,公司有用monaco-editor封装一个组件使用。自己利用业余(摸鱼)时间来在react(项目使用的vue)中使用,顺便熟悉一下。

"react": "^17.0.2",
"monaco-editor": "^0.34.1",

二、基本使用

  • 安装
yarn add monaco-editor 
  • 使用
import React, {useEffect, useState} from 'react';
import './App.css'
import * as monaco from 'monaco-editor';


const App = () => {
  const [editor, setEditor] =  useState(null)
  const initEditor = () => {
    const monacoEditor = monaco.editor.create(document.getElementById('container'), {
      value:`select * from dw_wr`,
      language: 'sql',
      theme: 'vs-dark',
    })
    setEditor(monacoEditor)
  }

  useEffect(() => {
    editor?.dispose()
    initEditor()
  }, [])

  return (
    <div className="App">
      <div id="container"></div>
    </div>
  )
}

export default App;

image.png

我测试的效果是像selectfrom会有高亮,但是如果前面没有出现的字段是不会有语法提示的;下面我们看看怎么给出关键词的提示。

三、语法提示(sql为例)

这里我也是通过不断百度才知道怎么处理~ 它内部有提供许多语言,我们可以通过打印monaco.languages.getLanguages() image.png

然后,我们引入sql语法配置文件monaco-editor/esm/vs/basic-languages/sql/sql.js。我们可以在node_modules下看到它内置的一些语法配置文件,你可以将你需要的引入 image.png 下面要做的就是把语法配置的关键词配置到编辑器里面去,让它有语法提示。

  • 自定义语法提示

通过百度(主要靠它)和官方文档(这里不得不吐槽下,这个官方文档真的让人奔溃,首先是英文,其次很不好读,也没有示例可以参考,太难了);这里也顺便说下怎么去看文档。

首先它是和语法相关的,自然能知道是去languages中查找 image.png

然后找到里面registerCompletionItemProvider image.png 它有两个参数,第一个就是你要配置的语言,第二个你可以点上面Defined...去掉它代码定义的地方去看,也可以直接点击参数在文档中查看。

核心代码如下:

import { language as sqlLanguage } from 'monaco-editor/esm/vs/basic-languages/sql/sql.js'


monaco.languages.registerCompletionItemProvider('sql', {
  provideCompletionItems: (
    model,
    position,
    ) => {
      let suggestions = []
      const { lineNumber, column } = position
      const textBeforePointer = model.getValueInRange({
        startLineNumber: lineNumber,
        startColumn: 0,
        endLineNumber: lineNumber,
        endColumn: column,
      })
      const contents = textBeforePointer.trim().split(/\s+/)
      const lastContents = contents[contents?.length - 1] // 获取最后一段非空字符串
      if (lastContents) {
        const sqlConfigKey = ['builtinFunctions', 'keywords', 'operators']
        sqlConfigKey.forEach(key => {
          sqlLanguage[key].forEach(sql => {
            suggestions.push(
              {
                label: sql, // 显示的提示内容;默认情况下,这也是选择完成时插入的文本。
                insertText: sql, // 选择此完成时应插入到文档中的字符串或片段
                // kind: monaco.languages.CompletionItemKind['Function'], // 此完成项的种类。编辑器根据图标的种类选择图标。
              }
            )
          })

        })
      }
      return {
        suggestions,
      }
    }
})

下面我们就实现了基本的语法提示 image.png

四、思考

最后给大家留个思考题;在sql编辑器中我们比较常见的需求就是根据接口返回的数据库、表、字段给出对应的语法提示,大家可以试一试,其实主要也就是组装上面的suggestions