Monaco Editor 自定义语言的实现

废话不多说

The Monaco Editor is the code editor that powers VS Code.

It is licensed under the MIT License and supports IE 9/10/11, Edge, Chrome, Firefox, Safari and Opera.


安装

npm install monaco-editor复制代码

引用

本人写Vue + Webpack 较多,以此为例:

第一种写法: 使用  monaco-editor-webpack-plugin

// .vue 对应的 script脚本中
import * as monaco from 'monaco-editor';

monaco.editor.create(document.getElementById('container'), {
  value: [
    'function x() {',
    '\tconsole.log("Hello world!");',
    '}'
  ].join('\n'),
  language: 'javascript'
});复制代码
// 在 webpack.base.conf.js 中
// 需要安装 monaco-editor-webpack-plugin

const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
const path = require('path');
module.exports = {
  ...
  plugins: [
    new MonacoWebpackPlugin()
  ]
};
复制代码


第二种写法:

// .vue 对应的 script脚本中

import * as monaco from 'monaco-editor';

// Since packaging is done by you, you need
// to instruct the editor how you named the
// bundles that contain the web workers.
self.MonacoEnvironment = {
  getWorkerUrl: function (moduleId, label) {
    if (label === 'json') {
      return './json.worker.bundle.js';
    }
    if (label === 'css') {
      return './css.worker.bundle.js';
    }
    if (label === 'html') {
      return './html.worker.bundle.js';
    }
    if (label === 'typescript' || label === 'javascript') {
      return './ts.worker.bundle.js';
    }
    return './editor.worker.bundle.js';
  }
}

monaco.editor.create(document.getElementById('container'), {
  value: [
    'function x() {',
    '\tconsole.log("Hello world!");',
    '}'
  ].join('\n'),
  language: 'javascript'
});复制代码
// 在 webpack.base.conf.js 中
// 不需要安装任何脚本const path = require('path');

module.exports = {
  entry: {
    "app": './index.js',
    // Package each language's worker and give these filenames in `getWorkerUrl`
    "editor.worker": 'monaco-editor/esm/vs/editor/editor.worker.js',
    "json.worker": 'monaco-editor/esm/vs/language/json/json.worker',
    "css.worker": 'monaco-editor/esm/vs/language/css/css.worker',
    "html.worker": 'monaco-editor/esm/vs/language/html/html.worker',
    "ts.worker": 'monaco-editor/esm/vs/language/typescript/ts.worker',
  },
  ...
};复制代码

 自定义语言

本人使用的是第二种方式,引用Editor。由于需要自定义语言 ,所以值引用了一个editor.worker包。

webpack.base.conf.js中的配置

module.exports = {
  entry: {
    app: ['babel-polyfill', './src/main.js'], // './src/main.js'
    "editor.worker": 'monaco-editor/esm/vs/editor/editor.worker.js',  }
 ......
}复制代码

.vue 文件对应的script代码段,引用monaco-editor,

引入custom-language 和 custom-completion

import * as monaco from 'monaco-editor'
import vLang from './custom-language'
import vCompletion from './custon-completion'

initEditor () {
      // 在methods中定义的编辑器初始化方法
      this.MonacoEnvironment = {
        getWorkerUrl: function (moduleId, label) {
          return './editor.worker.bundle.js'
        }
      }
      // 注册自定义语言
      monaco.languages.register({ id: 'mySpecialLanguage' })
      // 为该自定义语言基本的Token
      monaco.languages.setMonarchTokensProvider('mySpecialLanguage', vLang)
      // 为该语言注册一个语言提示器--联想
      monaco.languages.registerCompletionItemProvider('mySpecialLanguage', {        provideCompletionItems: () => {          return { suggestions: vCompletion }        }      })
      // 创建编辑器
      this.vEditor.editor = monaco.editor.create(document.getElementById('editor'), {
        value: this.vEditor.value,
        theme: this.vEditor.theme,
        language: 'mySpecialLanguage',
      })
    },复制代码

// custom-language.js
  /* eslint-disable no-useless-escape */
export default {
  // Set defaultToken to invalid to see what you do not tokenize yet
  // defaultToken: 'invalid',
  keywords: [    'IF', 'THEN', 'END', 'WHILE', 'DO', 'ELSE'  ],
  typeKeywords: [],
  operators: ['=', '>', '<', '==', '<=', '>=', '!=', '<>', '+', '-', '*', '/'],
  digits: /\d+(_+\d+)*/,
  octaldigits: /[0-7]+(_+[0-7]+)*/,  binarydigits: /[0-1]+(_+[0-1]+)*/,
  hexdigits: /[[0-9a-fA-F]+(_+[0-9a-fA-F]+)*/,
  // The main tokenizer for our languages
  tokenizer: {
    root: [
      // identifiers and keywords
      [/[a-z_$][\w$]*/, {
        cases: {
          '@typeKeywords': 'keyword',
          '@keywords': 'keyword',
          '@default': 'identifier'
        }
      }],
      [/[A-Z][\w\$]*/, 'type.identifier'],  // to show class names nicely
      // whitespace
      { include: '@whitespace' },
      // delimiters and operators
      [/[{}()\[\]]/, '@brackets'],
      // @ annotations.
      // As an example, we emit a debugging log message on these tokens.
      // Note: message are supressed during the first load -- change some lines to see them.
      // eslint-disable-next-line no-useless-escape
      [/@\s*[a-zA-Z_\$][\w\$]*/, { token: 'annotation', log: 'annotation token: $0' }],
      // numbers
      [/\d*\.\d+([eE][\-+]?\d+)?/, 'number.float'],
      [/0[xX][0-9a-fA-F]+/, 'number.hex'],
      [/\d+/, 'number'],
      // delimiter: after number because of .\d floats
      [/[;,.]/, 'delimiter'],
      // strings
      [/"([^"\\]|\\.)*$/, 'string.invalid'],
      // non-teminated string
      [/"/, { token: 'string.quote', bracket: '@open', next: '@string' }],
      // characters
      [/'[^\\']'/, 'string'],
      [/'/, 'string.invalid']    ],
    comment: [
      [/[^\/*]+/, 'comment'],
      [/\/\*/, 'comment', '@push'],
    // nested comment
      ['\\*/', 'comment', '@pop'],
      [/[\/*]/, 'comment']
    ],
    string: [
      [/[^\\"]+/, 'string'],
      [/\\./, 'string.escape.invalid'],
      [/"/, { token: 'string.quote', bracket: '@close', next: '@pop' }]
    ],
    whitespace: [
      [/[ \t\r\n]+/, 'white'],
      [/\/\*/, 'comment', '@comment'],
      [/\/\/.*$/, 'comment'],
    ],
  },}
复制代码

// custom-completion.js
/* eslint-disable no-template-curly-in-string */
export default [  
 /**   * 内置函数   */  
 {    
    label: 'getValue',
    kind: monaco.languages.CompletionItemKind.Function,
    insertText: 'getValue(${1:pattern})',
    insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
    documentation: '根据pattern描述的正则表达式,从数据项中获取匹配的字符串'
  },  {    
    label: 'getIniString',
    kind: monaco.languages.CompletionItemKind.Function,
    insertText: 'getIniString(${1:sec}, ${2: key})',
    insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
    documentation: '从ini类型的数据中,根据section和key,获取key对应的值,作为字符串返回'
  },  {
    label: 'getIniInt',
    kind: monaco.languages.CompletionItemKind.Function,
    insertText: 'getIniInt(${1:sec}, ${2: key})',
    insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
    documentation: '从ini类型的数据中,根据section和key,获取key对应的值,,作为整数返回'
  },  {
    label: 'getIniDouble',
    kind: monaco.languages.CompletionItemKind.Function,
    insertText: 'getIniDouble(${1:sec}, ${2: key})',
    insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
    documentation: '从ini类型的数据中,根据section和key,获取key对应的值,作为浮点数返回'
  },  {
    label: 'isEmpty',
    kind: monaco.languages.CompletionItemKind.Function,
    insertText: 'isEmpty(${1:str})',
    insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
    documentation: '判断str是否为空'
  },  {
    label: 'isEqual',
    kind: monaco.languages.CompletionItemKind.Function,
    insertText: 'isEqual(${1:str1}, ${2: str2})',
    insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
    documentation: '判断str是否为空'
  },  {
    label: 'isContain',
    kind: monaco.languages.CompletionItemKind.Function,
    insertText: 'isContain(${1:str})',
    insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
    documentation: '判断数据项中是否包含str'
  }, {
    label: 'getJsonInt',
    kind: monaco.languages.CompletionItemKind.Function,
    insertText: 'getJsonInt(${1:path})',
    insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
    documentation: '根据path获取JSON数据中作为整数返回的值'
  },  {
    label: 'getJsonDouble',
    kind: monaco.languages.CompletionItemKind.Function,
    insertText: 'getJsonDouble(${1:path})',
    insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
    documentation: '根据path获取JSON数据中作为整数返回的值'
  },  {
    label: 'getJsonSize',
    kind: monaco.languages.CompletionItemKind.Function,
    insertText: 'getJsonSize(${1:path})',
    insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
    documentation: '根据path获取JSON数据中作为数组类型的数据的长度'
  },
  /**   * 语句   */  
  {
    label: 'IF-ELSE',
    kind: monaco.languages.CompletionItemKind.Snippet,
    insertText: [      
      'IF ${1:condition} THEN',
      '\t$0',
      'ELSE',
      '\t$0',
      'END'
    ].join('\n'),
    insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
    documentation: 'If-Else Statement'
  },  {
    label: 'WHILE-DO',
    kind: monaco.languages.CompletionItemKind.Snippet,
    insertText: [
      'WHILE ${1:condition} DO',
      '\t$0',
      'END'
    ].join('\n'),
    insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
    documentation: 'WHILE-DO Statement'
  }]

复制代码

截图:


想要更多信息,还是看看官网和stackoverflow

官网说明:

官网地址:microsoft.github.io/monaco-edit…

自定义语言的DEMO:microsoft.github.io/monaco-edit…

在webpack类的项目中如何引用:github.com/Microsoft/m…



你可能感兴趣的:(Monaco Editor 自定义语言的实现)