为 Monaco Editor 实现 ctrl+点击的函数或引用的文件转跳

958 阅读2分钟

什么是 Monaco Editor

vscode 是我们经常在用的编辑器,它的前身是微软的一个叫 Monaco Workbench 的项目,而 Monaco Editor 就是从这个项目中成长出来的一个 web 编辑器,他们很大一部分的代码都是共用的,所以 Monaco Editor 和 VSCode 在编辑代码,交互及 UI 上几乎是一摸一样的。不同的是,两者的平台不一样, Monaco Editor 基于浏览器,而 VSCode 基于 electron ,所以功能上 VSCode 更加健全,性能比较强大。

安装

npm install monaco-editor --save

使用

<div id="monaco" class="monaco-editor"></div>

import * as monaco from 'monaco-editor';
this.fileEditor = this.monaco.editor.create(document.getElementById('monaco'), {
 value: null,
 language: 'sql' // 这里以sql为例
})

this.fileEditor.dispose(); // 使用完后销毁

这里引入 monaco 要注意,在 react 中以下面方式引入:

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

实现 ctrl+点击的函数或引用的文件转跳

monaco 的函数转跳功能需要手动把所有 编辑的代码加载到model上,才能搜索到转跳引索信息;

```// 创建model方法
monaco.editor.createModel(fileContent, lang, monaco.Uri.file("file://我的文件1.js"))
monaco.editor.createModel(fileContent, lang, monaco.Uri.file("file://我的文件2.js"))

然后需要重写鼠标点击后转跳的方法,我的实现方法是直接修改monaco的源码:

在源码找到 StandaloneCodeEditorServiceImpl 这个类
重新下面这个函数:

class StandaloneCodeEditorServiceImpl extends codeEditorServiceImpl_1.CodeEditorServiceImpl {
        getActiveCodeEditor() {
            return null; // not supported in the standalone case
        }
        openCodeEditor(input, source, sideBySide) {
            if (!source) {
                return Promise.resolve(null);
            }
            return Promise.resolve(this.doOpenEditor(source, input));
        }
        doOpenEditor(editor, input) {
            const model = this.findModel(editor, input.resource);
            const selection = (input.options ? input.options.selection : null);
            if (!model) {
                if (input.resource) {
                    const schema = input.resource.scheme;
                    if (schema === network_1.Schemas.http || schema === network_1.Schemas.https) {
                        // This is a fully qualified http or https URL
                        dom_1.windowOpenNoOpener(input.resource.toString());
                        return editor;
                    }
                }
                // 在此添加自定义打开文件、转跳函数 
                myFunc({uri:input.resource,selection});
                return null;
            }
            if (selection) {
                if (typeof selection.endLineNumber === 'number' && typeof selection.endColumn === 'number') {
                    editor.setSelection(selection);
                    editor.revealRangeInCenter(selection, 1 /* Immediate */);
                }
                else {
                    const pos = {
                        lineNumber: selection.startLineNumber,
                        column: selection.startColumn
                    };
                    editor.setPosition(pos);
                    editor.revealPositionInCenter(pos, 1 /* Immediate */);
                }
            }
            
                // 在此添加自定义打开文件、转跳函数
                myFunc({uri:input.resource,selection});
            return editor;
        }

听网友反馈后的修改方法

// 不修改源码,直接覆盖原方法,这样写也可以
editor._codeEditorService.doOpenEditor = function() {
	console.log('触发鼠标+ctrl点击')
}