• 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}) {', '	$0', '} else {', '	', '}'].join('
    '),
                    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 (/
    /g.test(message)) {
                        if (code) {
                            message = nls.localize('diagAndSourceAndCodeMultiline', "[{0}]
    {1} [{2}]", source, message, code);
                        }
                        else {
                            message = nls.localize('diagAndSourceMultiline', "[{0}]
    {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('
    ');
                    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('
    ');
                    }
                    hoverMessage.appendMarkdown('
    ');
                }
            }
    View Code

          

  • 相关阅读:
    多态的作用-游戏编程展示------新标准c++程序设计
    类与类之间的两种关系------新标准c++程序设计
    复制构造函数被调用的三种情况------新标准c++程序设计
    Dynamics CRM2011 隐藏sub-grid 新建项和添加现有项按钮
    Dynamics CRM Odata QueryUrl中的SetName问题
    Dynamics CRM 修改自定义实体名字及属性前缀(架构名称)
    Dynamics CRM 请求服务时报access is denied错误
    Dynamics CRM2011中通过JS脚本方式显示和隐藏ribbon中的自定义按钮
    (转载)表服务器无法打开与报表服务器数据库的连接。所有请求和处理都要求与数据库建立连接。
    如何将sqlserver的windows验证模式改为SQL Server 和 Windows 混合身份验证模式
  • 原文地址:https://www.cnblogs.com/legu/p/10350090.html
Copyright © 2020-2023  润新知