Monaco Editor系列(七)代码信息指示器CodeLens、使用API触发键盘事件、自动完成配置

前言:最近工作太忙了555,都没时间学习。端午节我要抽半天时间学习!(我自己都不信🤣)先总结一下下上一篇文章的知识点,我也忘得差不多了

  • Range类详解 Range类和IRange接口,Range类是基类,上面保存各种 range 相关的方法;IRange接口是开放给开发者的接口,传参的时候传 IRange接口类型的数据即可,这样传参就方便多了,里面只有关键的 range 的位置信息,起始位置和结束位置。两者可以相互转换。
  • 使用 monaco.editor.createModel() 方法,可以通过第三个参数 uri 设置语言。但是如果是自己开发,确定的语言,肯定就直接传了,目前没有发现这样传参很必要的使用场景。
  • monaco.Uri.parse() 将一个 url 地址,转换成 monaco 可用的 uri 标识。在 Monaco 编辑器中,Uri 经常用于表示打开的文件、编辑的文本或资源的位置。通过使用 Uri,可以在编辑器中准确地标识和操作这些资源。
  • monaco.editor.create(容器, 配置项) 通过第二个参数的minimap属性,可以配置 minamap 的配置项

这篇文章继续学习学习学习!我爱学习!

一、代码信息指示器CodeLens

1、简介

在使用 VS Code 编辑器的时候,如果你使用了 Git 版本工具,那么就会看到这样的效果
在这里插入图片描述

这一行文字用来提示修改代码的人员和修改时间,并且不会占据真正的代码行
蓝色的还可以点击进去查看更详细的信息
在这里插入图片描述
这一交互的实现就是通过 monaco 的代码信息提示器 CodeLens 实现的,显示的版本提交的内容是通过插件 Gitlen 实现的。
CodeLens 为代码提供辅助信息,并不真正存在在文件中,复制的时候不会复制到剪切板。前面学过的 markers 跟 CodeLens 有点像,都是帮助开发者理解代码,并且存在于编辑器外,通过人为手动设置的。
CodeLens 通常是一行信息,它是作用于语言模型的,也就是通过 monaco.languages 命名空间设置。

2、使用

使用 CodeLens 需要使用 monaco.editor.registerCodeLensProvider 方法注册一个 Provider
官网也给出了这个方法的示例
registerCodeLensProvider
参数一:LanguageSelector
还是看一下在源码中的定义
node_modules/monaco-editor-core/monaco.d.ts

export type LanguageSelector = string | LanguageFilter | ReadonlyArray<string | LanguageFilter>;

export interface LanguageFilter {
	readonly language?: string;
	readonly scheme?: string;
	readonly pattern?: string | IRelativePattern;
	readonly notebookType?: string;
	/**
	 * This provider is implemented in the UI thread.
	 */
	readonly hasAccessToAllModels?: boolean;
	readonly exclusive?: boolean;
	/**
	 * This provider comes from a builtin extension.
	 */
	readonly isBuiltin?: boolean;
}

这个参数的写法有三种:
1、 字符串 'javascript'
2、LanguageFilter 类型的对象,如果你不想给所有的某种语言的文件都增加,就可以通过对象的方式,来匹配你想设置 CodeLens 的文件

{
    language: 'javascript',
    pattern: '**/*.js'
}

但是这个匹配规则,emm,通过这样的路径匹配的方式,看源码没看出来怎么匹配的,太难了,不如还是用字符串
3、第三种是可以传一个LanguageFilter 类型的对象数组

参数二:CodeLensProvider

export interface CodeLensProvider {
	onDidChange?: IEvent<this>;
	provideCodeLenses(model: editor.ITextModel, token: CancellationToken): ProviderResult<CodeLensList>;
	resolveCodeLens?(model: editor.ITextModel, codeLens: CodeLens, token: CancellationToken): ProviderResult<CodeLens>;
}

一个监听函数 onDidChange 监听 CodeLens 的改变
provideCodeLenses 用来构建 CodeLens 数组
resolveCodeLens 没看出来什么作用
CodeLens 接口定义也挺简单的

export interface CodeLens {
	range: IRange;
	id?: string;
	command?: Command;
}

指定 CodeLens 出现的范围,以及唯一标识id,和绑定的 command 自定义命令。command 需要使用咱们之前学过的 addCommand 生成,可以指定点击 CodeLens 时候执行的回调函数
假设屏幕前的您已经拥有了一个编辑器

var commandId = editor.addCommand(
    0,
    function () {
        alert('CodeLens被点击啦');
    },
    ""
);
monaco.languages.registerCodeLensProvider("javascript", {
    provideCodeLenses: function (model, token) {
        return {
            lenses: [
                {
                    range: {
                        startLineNumber: 1,
                        startColumn: 1,
                        endLineNumber: 2,
                        endColumn: 1,
                    },
                    id: "First Line",
                    command: {
                        id: commandId,
                        title: "我是第一行",
                    },
                },
            ],
        };
    },
});

在这里插入图片描述
点它

在这里插入图片描述
CodeLens 类的 range 是必填的,CodeLens 是一个没有办法占据多行的东东,而且肯定是从一行的起始位置开始的,所以其实只有 startLineNumber 属性能影响它的位置;idcommand 都不是必填的,但是如果要指定点击的回调函数,就必须要填 command 了。

二、使用API触发键盘事件

我们的鼠标右键有很多的命令,以及快捷键也绑定了很多命令,
在这里插入图片描述
除了直接通过点击事件触发,我们还可以通过调API触发这些命令的回调函数,有点类似于使用js触发DOM元素的点击事件 ele.click()
手动触发命令有两种方法,

  • editor.trigger(source, handlerId) 第一个 source 是自己定义的一个字符串
  • 先使用 editor.getAction(actionId) 获取 action 实例,然后再使用 actionrun() 方法执行对应的回调函数。
addAction()
function addAction() {
    editor.addAction({
        // 不能重复
        id: 'bomb',

        // 展示在菜单中的文本
        label: 'Didara Bomb',

        // 快捷键
        keybindings: [
            monaco.KeyMod.CtrlCmd | monaco.KeyCode.F10,
            // 组合按键
            monaco.KeyMod.chord(
                monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyD,
                monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyM
            )
        ],

        // 前提条件 String
        // 暂时只找到这一个例子,判断编辑器语言是不是 javascript
        precondition: "editorLangId == 'javascript'",

        // 绑定快捷键的规则
        keybindingContext: "editorLangId == 'javascript'",

        // 指定操作应显示在上下文菜单的哪个组中 navigation表示默认组
        contextMenuGroupId: 'navigation',

        // 操作在菜单中的显示顺序
        contextMenuOrder: 1.5,

        // 操作执行的方法
        // @param editor ed.getPosition() 获取焦点坐标
        run: function (ed) {
            alert("艺术就是💣💣💣💣💥💥💥💥" + ed.getPosition());
        }
    });
}

setTimeout(() => {
    editor.trigger('bomb', 'bomb')
}, 1000)
setTimeout(() => {
    const action = editor.getAction('bomb')
    action.run()
}, 2000)

我这里是自定义了一个命令,然后通过延时器触发了两次这个命令。对于内置命令也可以这样触发
内置命令有 154 个,根据学习大佬的文章得知这些命令在editor实例的_actions里面保存着
在这里插入图片描述
真的是,深似海,关键是文档太粗糙🤓🤓🤓
而且还不能直接打印 console.log(editor._action),这样子的结果是 undefined,大概因为加横线的属性是私有属性
例如要手动触发字号放大

setTimeout(() => {
    editor.trigger('fontZoomIn', 'editor.action.fontZoomIn')
}, 1000)

或者

setTimeout(() => {
    editor.getAction('editor.action.fontZoomIn').run()
}, 1000)

三、自动完成配置

这一节讲的就是自动补全相关的配置项
monaco 官网提供的有自动补全配置项的相关案例 completion-provider-example
自动补全也在 Languages 命名空间的统治范围内

export function registerCompletionItemProvider(languageSelector: LanguageSelector, provider: CompletionItemProvider): IDisposable;

第一个参数和上面的 CodeLens 设置的时候传的一样,我们用的话,传递字符串就够用了
第二个参数的定义也和CodeLens传的第二个参数很类似

export interface CompletionItemProvider {
	triggerCharacters?: string[];
	provideCompletionItems(model: editor.ITextModel, position: Position, context: CompletionContext, token: CancellationToken): ProviderResult<CompletionList>;
	resolveCompletionItem?(item: CompletionItem, token: CancellationToken): ProviderResult<CompletionItem>;
}

其中配置的关键就是 provideCompletionItems 方法
接收的参数:
model:当前语言模型
position:当前光标的位置
context:自动完成的上下文
返回的 CompletionItem 的定义也和 CodeLens 定义很类似

export interface CompletionList {
	suggestions: CompletionItem[];
	incomplete?: boolean;
	dispose?(): void;
}

所以在这个方法里,我们主要的任务就是构建 CompletionList 数组,然后返回出去
关键的属性就是 suggestions,它是 CompletionItem 组成的数组,这个接口的定义有一丢丢的复杂,属性稍微有一丢丢多

export interface CompletionItem {
	/**
	 * 展示在自动补全列表中的文本
	 */
	label: string | CompletionItemLabel;
	/**
	 * 类型,决定显示的图标 可选项:monaco.languages.CompletionItemKind 枚举值
	 */
	kind: CompletionItemKind;
	/**
	 * 枚举值CompletionItemTag 只有一个选项 如果设置了表示废弃,自动补全元素上会出现划线
	 */
	tags?: ReadonlyArray<CompletionItemTag>;
	/**
	 * 提供信息的字符串,会出现在选项的最右侧,如果没设置,就显示右箭头
	 */
	detail?: string;
	/**
	 * 选型的详细描述,字符串或者markdown 点击右箭头或者 detail显示出来
	 */
	documentation?: string | IMarkdownString;
	/**
	 * 用来调整顺序的字符串 如果设置为 falsy,那么顺序会往后排,默认的顺序是数组定义的顺序
	 */
	sortText?: string;
	/**
	 * 用来筛选当前选项是否可用,如果设置为 falsy,则不会显示
	 */
	filterText?: string;
	/**
	 * 预设 布尔值 如果设置为true,那么就会被默认选中,此时直接回车就直接应用了
	 */
	preselect?: boolean;
	/**
	 * 实际插入的代码
	 */
	insertText: string;
	/**
	 * 插入时额外的规则 枚举值 KeepWhitespace(自动调整插入文本的缩进) InsertAsSnippet(将insertText当做片段插入)
	 */
	insertTextRules?: CompletionItemInsertTextRule;
	/**
	 * 自动补全的位置
	 */
	range: IRange | CompletionItemRanges;
	/**
	 * 是一个数组,里面元素是单个字符,当选中选项的时候,再输入这几个指定的字符,就会插入insertText,并且将制定字符加到后面
	 * 默认的选中按键是enter,这几个区别是还会将字符加到后面
	 */
	commitCharacters?: string[];
	/**
	 * 选中时自动追加多行内容
	 */
	additionalTextEdits?: editor.ISingleEditOperation[];
	/**
	 * 选中后执行的回调
	 */
	command?: Command;
}
  • labeldetail
    在这里插入图片描述

  • kind
    在这里插入图片描述

  • documentation
    在这里插入图片描述

  • tags: [monaco.languages.CompletionItemTag.Deprecated]
    在这里插入图片描述

  • preselect: true,对应的选项会自动被选中
    在这里插入图片描述

  • commitCharacters: ['a', 'b','c']
    先选中对应选项
    在这里插入图片描述
    然后按下按键a
    在这里插入图片描述

  • additionalTextEdits
    如图想在开头插入代码,它会直接插入到指定位置,但是还需要自己换行

在这里插入图片描述

  • command 配置选中选项后的回调 但是不能是自定义的
export interface Command {
	id: string;
	title: string;
	tooltip?: string;
	arguments?: any[];
}

通过 id 指定 monaco提供的命令
例如添加代码后立马注释

command: {
    id: 'editor.action.commentLine',
    title: '注释选中的行',
}

自动补全配置代码:

function createDependencyProposals(range) {
    return [
        {
            label: 'monaco',
            kind: monaco.languages.CompletionItemKind.Reference,  // 控制图标
            documentation: "定义一个不能修改的常量",  // 点击右侧按钮出现在下边,详细说明
            detail: '我是detail属性',  // 出现在选项的最右侧,几个字的内容
            insertText: 'console.log("monaco可真是太好用了")',  // 实际插入的代码
            range: range,  // 范围
            // tags: [monaco.languages.CompletionItemTag.Deprecated],  // 出现划线,表示不建议
            preselect: true, // 预选中
            // filterText: 'falsy',  // 不显示
            insertTextRules: monaco.languages.CompletionItemInsertTextRule.KeepWhitespace, // 插入的规则 InsertAsSnippet:作为代码块插入;KeepWhitespace:插入后自动格式化
            commitCharacters: ['a', 'b','c'], // 选中后输入这几个字符,自动插入代码和字符
            // additionalTextEdits: [
            //     {
            //         range: {
            //             startLineNumber: 1,
            //             startColumn: 1,
            //             endLineMumber: 1,
            //             endColumn:1
            //         },
            //         text: '// 这是一行额外加进来的代码',
            //         forceMoveMarkers: true,
            //     }
            // ],
            command: {
                id: 'editor.action.commentLine',
                title: '注释选中的行',
            }

        },
    ];
}

monaco.languages.registerCompletionItemProvider("javascript", {
    provideCompletionItems: function (model, position) {
        var word = model.getWordUntilPosition(position);
        var range = {
            startLineNumber: position.lineNumber,
            endLineNumber: position.lineNumber,
            startColumn: word.startColumn,
            endColumn: word.endColumn,
        };
        return {
            suggestions: createDependencyProposals(range),
        };
    },
});

本篇文章主要介绍了三个功能
CodeLens 代码信息提示器的配置和自动补全配置很类似,都是隶属于 languages 命名空间,从函数名上看,都是通过注册 Provider 的方式,增加配置,里面传参也很类似,第一个参数都是语言,第二个是配置项
CodeLens 和 Markers 很类似,都是提供代码提示的,帮助开发者更好的理解代码,但是 Markers 是鼠标浮动到代码上才会出现,并且可以显示的内容比较多,CodeLens 直接显示在代码里面,占据独立一行,但是不占用行号,复制时不会被复制到剪切板中。
自动补全配置很厉害,可以自定义菜单中显示的名称和位置、插入的代码、插入后的回调函数等等。
使用API触发键盘事件或者命令比较简单,一个是使用 monaco.editor.trigger(),指定要触发的命令的id;一个是先获取 action,调用action.run() 方法。

  • 17
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
在 umijs 中使用 react-monaco-editor 可以通过以下步骤进行配置: 1. 安装 react-monaco-editor: ``` npm install react-monaco-editor ``` 2. 在需要使用的组件中引入: ```jsx import MonacoEditor from 'react-monaco-editor'; ``` 3. 在组件中使用 MonacoEditor,并配置 options: ```jsx function CodeEditor() { const options = { selectOnLineNumbers: true, automaticLayout: true, colorDecorators: true, readOnly: false, minimap: { enabled: false, }, language: 'javascript', }; function handleEditorDidMount(editor) { // 在这里可以添加一些初始化操作 } function handleEditorChange(value, event) { // 在这里可以添加一些编辑器内容改变时的操作 } return ( <MonacoEditor width="100%" height="500" language="javascript" theme="vs-dark" value="// 在这里输入代码" options={options} onChange={handleEditorChange} editorDidMount={handleEditorDidMount} /> ); } ``` 4. 在 options 中添加 language 对象,指定代码高亮显示的语言。 ```jsx const options = { ... language: 'javascript', }; ``` 如果需要支持其他语言,可以在 options 中指定相应的语言,例如: ```jsx const options = { ... language: 'java', }; ``` 更多语言支持可以参考 [Monaco Editor 的官方文档](https://microsoft.github.io/monaco-editor/)。 5. 在 umijs 中使用主题可以通过在配置文件中添加主题的方式进行配置,例如在 `config/config.js` 中添加以下代码: ```js export default { ... define: { 'process.env.NODE_ENV': 'dev', // 添加主题配置 'process.env.MONACO_THEME': 'vs-dark', }, }; ``` 然后在组件中使用时,可以通过以下方式指定主题: ```jsx <MonacoEditor ... theme={process.env.MONACO_THEME} ... /> ``` 在这里,我们使用了 `process.env.MONACO_THEME` 来获取主题的值,这样可以在不同环境中使用不同的主题,例如在开发环境中使用 `vs` 主题,在生产环境中使用 `vs-dark` 主题。 注意:在使用 umijs 的 `umi build` 命令构建时,需要在执行命令时添加环境变量,例如: ``` MONACO_THEME=vs umi build ``` 这样可以在构建时指定主题的值。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值