Monaco Editor 使用入門


以前項目是用ace編輯器的,但是總有些不敬人意的地方。前端事件看見的VS Code編輯器Monaco Editor准備更換下,下面介紹一些使用中遇到的一點問題。代碼提示

 1.項目引用

import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';

    項目中引用了editor.api.js,但是這個文件不包含一些默認的語言和插件,所以在使用的時候,還需要我們自己import

import 'monaco-editor/esm/vs/basic-languages/mysql/mysql.contribution';
import 'monaco-editor/esm/vs/editor/contrib/suggest/suggestController.js';
import 'monaco-editor/esm/vs/editor/contrib/bracketMatching/bracketMatching.js';
import 'monaco-editor/esm/vs/editor/contrib/hover/hover.js';

     如果嫌麻煩我們也可以使用editor.all.js

   2.react組件封裝

    可以使用github項目,https://github.com/superRaytin/react-monaco-editor,也可以拿來項目里面改下,比較簡單

    其實在componentDidUpdate的方法中,使用這個方法this.editor.setValue,undo不能撤回上次的value,

    如果項目中有別的需求可以使用

var model = this.editor.getModel();
model.pushEditOperations(
    [],
    [
        {
            range: model.getFullModelRange(),
            text: prevProps.value
        }
    ]
);

    onDidChangeModelContent,方法產生的監聽需要在組件銷毀的時候dispose下

   3.編輯器參數配置

     查看以下代碼文件 monaco-editor/esm/vs/editor/common/config/commonEditorConfig.js

     minimap,scrollBeyondLastLine,Suggestion,snippet相關的

   4.在光標處插入文本

  跟ace使用差別比較大

var position = editor.getPosition();
editor.executeEdits('', [
    {
        range: {
            startLineNumber: position.lineNumber,
            startColumn: position.column,
            endLineNumber: position.lineNumber,
            endColumn: position.column
        },
        text: 'test'
    }
]);

   5.代碼自動完成

下面代碼是引用了monaco-editor自帶的mysql的語法高亮里面的定義,設置的代碼提示

import { language as mysqlLanguage } from 'monaco-editor/esm/vs/basic-languages/mysql/mysql.js';
monaco.languages.registerCompletionItemProvider('mysql', {
    provideCompletionItems: function(model, position) {
        // get editor content before the pointer
        var textUntilPosition = model.getValueInRange({
            startLineNumber: position.lineNumber,
            startColumn: 1,
            endLineNumber: position.lineNumber,
            endColumn: position.column
        });
        var match = textUntilPosition.match(/(\S+)$/);
        if (!match) return [];
        match = match[0].toUpperCase();
        var suggestions = [];
        mysqlLanguage.keywords.forEach(item => {
            if (item.indexOf(match) !== -1) {
                suggestions.push({
                    label: item,
                    kind: monaco.languages.CompletionItemKind.Keyword,
                    insertText: item
                });
            }
        });
        mysqlLanguage.operators.forEach(item => {
            if (item.indexOf(match) !== -1) {
                suggestions.push({
                    label: item,
                    kind: monaco.languages.CompletionItemKind.Operator,
                    insertText: item
                });
            }
        });
        mysqlLanguage.builtinFunctions.forEach(item => {
            if (item.indexOf(match) !== -1) {
                suggestions.push({
                    label: item,
                    kind: monaco.languages.CompletionItemKind.Function,
                    insertText: item
                });
            }
        });
        return {
            suggestions
        };
    }
});

如果你想增加代碼片段,也可以直接添加下面的信息

            {
                label: 'ifelse',
                kind: monaco.languages.CompletionItemKind.Snippet,
                insertText: ['if (${1:condition}) {', '\t$0', '} else {', '\t', '}'].join('\n'),
                insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
                documentation: 'If-Else Statement'
            }

使用中發現,編輯器自帶的默認的變量提示,在提供了自定義的registerCompletionItemProvider后會失效,暫時沒找到什么好方法

默認的變量提示 monaco-editor/esm/vs/editor/common/services/editorWorkerServiceImpl.js

_this._register(modes.CompletionProviderRegistry.register('*', new WordBasedCompletionItemProvider(_this._workerManager, configurationService, _this._modelService)));

monaco-editor/esm/vs/editor/contrib/suggest/suggest.js

會根據注冊的Provider的分組,語言默認的優先級不高,沒有分到一組,找到了結果就不再會執行下面的組

    6.語法高亮

      官網的文檔蠻詳細的,和ace的差別不是很大,雖然我也沒怎么看懂

  https://microsoft.github.io/monaco-editor/monarch.html

      可以在項目中找個相似的語言抄抄改改,結合着看官方文檔

      monaco-editor/esm/vs/basic-languages

      高亮的樣式需要在定義主題來對應,不是完全通過css處理的

monaco.editor.defineTheme('ace', {
  base: 'vs',
  inherit: true,
  rules: [
    { token: '', foreground: '5c6773' },
    { token: 'invalid', foreground: 'ff3333' },
    { token: 'emphasis', fontStyle: 'italic' },
    { token: 'strong', fontStyle: 'bold' },
    { token: 'variable', foreground: '5c6773' },
    { token: 'variable.predefined', foreground: '5c6773' },
    { token: 'constant', foreground: 'f08c36' },
  ]
});

  7.語法檢測

        語法檢測,就需要編寫對應的語法編譯邏輯,這個不同語言不同的寫法,一些也有現成的。這邊主要介紹下怎么和編輯器交互,顯示錯誤信息

        錯誤信息hover顯示需要插件 import 'monaco-editor/esm/vs/editor/contrib/hover/hover.js';

//清楚mark
monaco.editor.setModelMarkers(model, 'eslint', []);
//添加mark
monaco.editor.setModelMarkers(model, 'eslint', [
    {
        startLineNumber: 2,
        endLineNumber: 2,
        startColumn: 2,
        endColumn: 4,
        message: 'Syntax error',
        severity: 3,
        source: 'ESLint',
        code: 'asdasdas'
    }
]);

       對於上面的一些配置信息會對提示框有什么影響可以看下面的源碼

       monaco-editor/esm/vs/editor/common/services/modelServiceImpl.js  ModelMarkerHandler._createDecorationOption

    ModelMarkerHandler._createDecorationOption = function (marker) {
        var className;
        var color = undefined;
        var zIndex;
        var inlineClassName = undefined;
        switch (marker.severity) {
            case MarkerSeverity.Hint:
                if (marker.tags && marker.tags.indexOf(1 /* Unnecessary */) >= 0) {
                    className = "squiggly-unnecessary" /* EditorUnnecessaryDecoration */;
                }
                else {
                    className = "squiggly-hint" /* EditorHintDecoration */;
                }
                zIndex = 0;
                break;
            case MarkerSeverity.Warning:
                className = "squiggly-warning" /* EditorWarningDecoration */;
                color = themeColorFromId(overviewRulerWarning);
                zIndex = 20;
                break;
            case MarkerSeverity.Info:
                className = "squiggly-info" /* EditorInfoDecoration */;
                color = themeColorFromId(overviewRulerInfo);
                zIndex = 10;
                break;
            case MarkerSeverity.Error:
            default:
                className = "squiggly-error" /* EditorErrorDecoration */;
                color = themeColorFromId(overviewRulerError);
                zIndex = 30;
                break;
        }
        if (marker.tags) {
            if (marker.tags.indexOf(1 /* Unnecessary */) !== -1) {
                inlineClassName = "squiggly-inline-unnecessary" /* EditorUnnecessaryInlineDecoration */;
            }
        }
        var hoverMessage = null;
        var message = marker.message, source = marker.source, relatedInformation = marker.relatedInformation, code = marker.code;
        if (typeof message === 'string') {
            message = message.trim();
            if (source) {
                if (/\n/g.test(message)) {
                    if (code) {
                        message = nls.localize('diagAndSourceAndCodeMultiline', "[{0}]\n{1} [{2}]", source, message, code);
                    }
                    else {
                        message = nls.localize('diagAndSourceMultiline', "[{0}]\n{1}", source, message);
                    }
                }
                else {
                    if (code) {
                        message = nls.localize('diagAndSourceAndCode', "[{0}] {1} [{2}]", source, message, code);
                    }
                    else {
                        message = nls.localize('diagAndSource', "[{0}] {1}", source, message);
                    }
                }
            }
            hoverMessage = new MarkdownString().appendCodeblock('_', message);
            if (!isFalsyOrEmpty(relatedInformation)) {
                hoverMessage.appendMarkdown('\n');
                for (var _i = 0, _a = relatedInformation; _i < _a.length; _i++) {
                    var _b = _a[_i], message_1 = _b.message, resource = _b.resource, startLineNumber = _b.startLineNumber, startColumn = _b.startColumn;
                    hoverMessage.appendMarkdown("* [" + basename(resource.path) + "(" + startLineNumber + ", " + startColumn + ")](" + resource.toString(false) + "#" + startLineNumber + "," + startColumn + "): ");
                    hoverMessage.appendText("" + message_1);
                    hoverMessage.appendMarkdown('\n');
                }
                hoverMessage.appendMarkdown('\n');
            }
        }
View Code

 

 

      


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM