VS Code扩展如何为decoration的before/after添加hoverMessage
VS Code扩展实现before装饰元素单独绑定hover效果方案
VS Code原生DecorationOptions的hoverMessage属性默认绑定到装饰覆盖的整个文本范围,不支持直接给before/after伪元素单独配置悬停提示,GitLens的同款效果是通过拆分装饰+零宽范围+自定义Hover提供者的组合方案实现的,具体实现步骤如下:
步骤1:拆分两组独立装饰
不要把图标和hover触发逻辑放在同一个装饰里,拆成两个完全独立的装饰配置:
- 第一组为图标展示装饰:保留原有before图标配置,覆盖你需要标记的代码文本范围,不配置任何hoverMessage,负责在代码前渲染图标,鼠标悬停在代码上时不会触发任何提示。
- 第二组为hover触发装饰:不配置任何渲染样式,将range设置为原装饰起始位置的零宽范围(即起止位置都是原range的startPos,不覆盖任何实际代码字符),用于定位before图标的悬停触发区域,存储需要展示的hover内容。
对应实现代码:
import * as vscode from 'vscode'; // 提前注册两个全局装饰类型,扩展停用时记得调用dispose()销毁 const codeIconDecorationType = vscode.window.createTextEditorDecorationType({ before: { margin: '0 4px 0 0', height: vscode.workspace.getConfiguration('editor').get('fontSize') } }); const hoverTriggerDecorationType = vscode.window.createTextEditorDecorationType({ // 无任何渲染配置,完全透明不影响界面显示 }); // 模块级变量存储当前生效的触发装饰,兼容低版本VS Code let activeHoverTriggers: vscode.DecorationOptions[] = []; // 渲染装饰的逻辑 function renderDecorations(editor: vscode.TextEditor) { const iconDecorations: vscode.DecorationOptions[] = []; const triggerDecorations: vscode.DecorationOptions[] = []; // 遍历你所有需要加装饰的位置数据 decorationList.forEach(item => { const { startPos, endPos, iconBase64, hoverContent } = item; // 图标装饰:覆盖代码范围,不带hover iconDecorations.push({ range: new vscode.Range(startPos, endPos), renderOptions: { before: { contentIconPath: vscode.Uri.parse(iconBase64) } } }); // 触发装饰:零宽范围,绑定hover内容 triggerDecorations.push({ range: new vscode.Range(startPos, startPos), hoverMessage: hoverContent }); }); // 给编辑器挂载两组装饰 editor.setDecorations(codeIconDecorationType, iconDecorations); editor.setDecorations(hoverTriggerDecorationType, triggerDecorations); // 更新缓存的触发装饰列表 activeHoverTriggers = triggerDecorations; }
步骤2:注册Hover Provider响应触发
注册全局Hover提供者,判断当前鼠标悬停位置是否命中零宽触发装饰的位置,命中时返回对应hover内容即可:
vscode.languages.registerHoverProvider('*', { provideHover(document, position) { const activeEditor = vscode.window.activeTextEditor; if (!activeEditor || activeEditor.document !== document) return null; // 遍历缓存的触发装饰,判断是否命中 for (const trigger of activeHoverTriggers) { // 零宽装饰的起止位置一致,匹配即命中图标悬停区域 if (trigger.range.start.isEqual(position)) { return new vscode.Hover(trigger.hoverMessage); } } return null; } });
效果说明
- 鼠标悬停在before图标上时,刚好命中零宽范围的起始位置,会弹出配置的hover提示
- 鼠标悬停在range覆盖的代码文本上时,不会命中零宽触发点,不会弹出任何提示,和GitLens的图标悬停效果完全一致
- 若需要调整hover触发的热区大小,可适当调整零宽range的范围,比如设置为从startPos到startPos偏移1个字符的位置即可扩大触发区域
内容的提问来源于stack exchange,提问作者1245582339qqcom
相关产品推荐
相关产品推荐

