import * as vscode from 'vscode'; import * as lc from 'vscode-languageclient'; import { Server } from './server'; export interface Decoration { range: lc.Range; tag: string; } export class Highlighter { private static initDecorations(): Map { const decor = (color: string) => vscode.window.createTextEditorDecorationType({ color }); const decorations: Iterable<[string, vscode.TextEditorDecorationType]> = [ ['background', decor('#3F3F3F')], ['error', vscode.window.createTextEditorDecorationType({ borderColor: 'red', borderStyle: 'none none dashed none', })], ['comment', decor('#7F9F7F')], ['string', decor('#CC9393')], ['keyword', decor('#F0DFAF')], ['function', decor('#93E0E3')], ['parameter', decor('#94BFF3')], ['builtin', decor('#DD6718')], ['text', decor('#DCDCCC')], ['attribute', decor('#BFEBBF')], ['literal', decor('#DFAF8F')], ]; return new Map(decorations); } private decorations: (Map | null) = null; public removeHighlights() { if (this.decorations == null) { return; } // Decorations are removed when the object is disposed for (const decoration of this.decorations.values()) { decoration.dispose(); } this.decorations = null; } public setHighlights( editor: vscode.TextEditor, highlights: Decoration[], ) { // Initialize decorations if necessary // // Note: decoration objects need to be kept around so we can dispose them // if the user disables syntax highlighting if (this.decorations == null) { this.decorations = Highlighter.initDecorations(); } const byTag: Map = new Map(); for (const tag of this.decorations.keys()) { byTag.set(tag, []); } for (const d of highlights) { if (!byTag.get(d.tag)) { continue; } byTag.get(d.tag)!.push( Server.client.protocol2CodeConverter.asRange(d.range), ); } for (const tag of byTag.keys()) { const dec = this.decorations.get(tag) as vscode.TextEditorDecorationType; const ranges = byTag.get(tag)!; editor.setDecorations(dec, ranges); } } }