自定义VS Code扩展DocumentHighlightProvider对特殊字符不触发,如何支持全字符?
自定义VS Code扩展中,registerDocumentHighlightProvider(文档高亮事件)在光标位于[、]、{、}等符号上时不会触发,但在A-Z这类字母上能正常触发。如何让文档高亮对所有字符生效?
测试代码基于VS Code官方《Getting Started》示例,完整TypeScript代码如下:
import * as vscode from 'vscode'; export function activate(context: vscode.ExtensionContext) { let disposable = vscode.commands.registerCommand('helloworld.helloWorld', () => { vscode.window.showInformationMessage('Hello World from HelloWorld!'); }); let docSelector: vscode.DocumentSelector = { scheme: 'file', language: 'json' }; let highlight: Highlighter = new Highlighter(); context.subscriptions.push( vscode.languages.registerDocumentHighlightProvider(docSelector, highlight), disposable ); } export class Highlighter implements vscode.DocumentHighlightProvider { provideDocumentHighlights(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken) { // highlight single character at cursor let range = new vscode.Range(position.line, position.character, position.line, position.character + 1); let highlight = new vscode.DocumentHighlight(range, vscode.DocumentHighlightKind.Write); return [ highlight ]; } } export function deactivate() {}
调试时使用的JSON测试文件:
{ "test": "[`${SOMEFUNC(param1)} etc.`]", }
调试发现,光标在[、]、{、}、)等符号上时,provideDocumentHighlights的断点完全不触发,但在字母上正常触发。
问题根源在于VS Code的**词法范围(Word Range)**定义:不同语言的wordPattern决定了哪些字符会被识别为“词”的一部分,只有当光标位于一个“词”范围内时,才会触发DocumentHighlightProvider。JSON语言的默认wordPattern不包含[、]、{、}这类符号,因此光标在这些字符上时不会触发高亮逻辑。
有两种可行的解决方法:
方法1:自定义语言的wordPattern(仅针对当前扩展生效)
通过扩展贡献点修改JSON语言的wordPattern,将符号类字符纳入词范围:
- 在扩展的
package.json中添加contributes.configuration:
"contributes": { "configuration": { "title": "Custom JSON Highlight", "properties": { "[json]": { "editor.wordPattern": { "type": "string", "default": "(-?\\d*\\.\\d\\w*)|([^\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\<\\.\\>\\/\\?\\s]+)" } } } } }
这个自定义的wordPattern包含了常见符号,会让VS Code把这些符号识别为词的一部分,从而触发DocumentHighlightProvider。
方法2:绕过默认词范围检测,手动监听光标位置实现高亮
放弃依赖DocumentHighlightProvider的自动触发,改用TextEditorDecorationType结合光标位置监听来实现全字符高亮:
import * as vscode from 'vscode'; export function activate(context: vscode.ExtensionContext) { // 创建装饰类型,用于高亮光标所在字符 const highlightDecoration = vscode.window.createTextEditorDecorationType({ backgroundColor: 'rgba(255, 255, 0, 0.3)', border: '1px solid yellow' }); // 监听光标选择变化 const updateHighlight = () => { const editor = vscode.window.activeTextEditor; if (!editor || editor.document.languageId !== 'json') return; const position = editor.selection.active; // 选中光标所在的单个字符 const range = new vscode.Range(position.line, position.character, position.line, position.character + 1); editor.setDecorations(highlightDecoration, [range]); }; // 注册监听事件 context.subscriptions.push( vscode.window.onDidChangeActiveTextEditor(updateHighlight), vscode.window.onDidChangeTextEditorSelection(updateHighlight), highlightDecoration ); // 初始化高亮 updateHighlight(); // 保留原有的命令 let disposable = vscode.commands.registerCommand('helloworld.helloWorld', () => { vscode.window.showInformationMessage('Hello World from HelloWorld!'); }); context.subscriptions.push(disposable); } export function deactivate() {}
这种方法直接监听光标位置变化,手动应用装饰,不受语言wordPattern的限制,能对所有字符生效。
内容的提问来源于stack exchange,提问作者RadicalGratitude

