如何在Monaco Editor中同时实现悬停提示与自动补全功能?
解决Monaco Editor自定义类提示与补全的方案
核心思路:结合类型定义与自定义补全增强
你提到的第三种方式(用类代码创建模型)其实可以通过补充规范JSDoc标注+轻量自定义补全增强实现需求,无需重复编写文档,同时兼顾悬停提示和带默认值的补全。
步骤1:完善JSDoc注释,让Monaco识别JS类型
纯JS下Monaco对类型的识别依赖标准JSDoc,调整你的类注释格式:
/** * MyClass * @class * @description This is my custom class. * @param {number} initialValue - 初始值 */ class MyClass { /** * @type {number} */ myProperty; /** * @type {string} */ value; constructor(initialValue) { this.myProperty = initialValue; } /** * myMethod * @description This is a sample method. * @param {string} val - The value to store. */ myMethod(val) { this.value = val; } }
关键调整点:
- 给类添加
@class标签,给属性添加@type类型标注 - 参数注释使用标准
@param标签(而非@args,Monaco遵循标准JSDoc规范) - 在类顶层显式声明属性并标注类型,即使属性在构造函数中赋值
调整后Monaco就能识别c的类型为MyClass,自动提供属性/方法的悬停提示和基础补全。
步骤2:自定义补全提供器增强默认值插入
基于原生类型识别能力,写一个轻量补全提供器,仅针对需要默认值的方法做增强,无需重复维护类成员文档:
monaco.languages.registerCompletionItemProvider('javascript', { triggerCharacters: ['.'], provideCompletionItems(model, position) { const word = model.getWordUntilPosition(position); const range = new monaco.Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn); // 判断当前是否为对象成员访问场景 const lineContent = model.getLineContent(position.lineNumber); const prefix = lineContent.substring(0, position.column - 1); if (!prefix.endsWith('.')) return { suggestions: [] }; // 复用Monaco原生类型补全结果,仅增强目标方法 return monaco.editor.getModelLanguageService(model).doComplete(model, position).then(result => { const enhancedSuggestions = result.suggestions.map(suggestion => { if (suggestion.kind === monaco.languages.CompletionItemKind.Method && suggestion.label === 'myMethod') { return { ...suggestion, insertText: 'myMethod(${1:val})', insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet }; } return suggestion; }); return { suggestions: enhancedSuggestions }; }); } });
这个提供器会复用原生类型补全的所有信息,仅给myMethod添加带占位符的默认值片段,避免重复劳动。
关于三种方式的兼容性
Monaco允许同时注册多种服务,原生类型服务(第三种方式)和自定义补全/悬停提供器可以共存,自定义提供器优先级更高,你可以用它增强原生功能,而非完全替代。
额外提示
- 如果不想暴露类源码给编辑器,可以把类型定义抽成
.d.ts文件,通过monaco.languages.typescript.javascriptDefaults.addExtraLib()注入到Monaco类型系统中,效果与直接引入类代码一致。 - 属性的默认值补全也可以用相同逻辑,在提供器中判断属性类型后添加对应的默认值片段。
内容的提问来源于stack exchange,提问作者nucleon
相关产品推荐
相关产品推荐

