UNPKG

coc-ccls

Version:

C/C++/ObjC language server supporting cross references, hierarchies, completion and semantic highlighting

209 lines (188 loc) 6.66 kB
import { workspace, } from "coc.nvim"; import { Disposable, Range, } from "vscode-languageserver-protocol"; import { SymbolKind } from "vscode-languageserver-types"; import { disposeAll, normalizeUri, unwrap } from "./utils"; const window = workspace; enum CclsSymbolKind { // ls.SymbolKind ccls extensions TypeAlias = 252, Parameter = 253, StaticMethod = 254, Macro = 255 } enum StorageClass { Invalid, None, Extern, Static, PrivateExtern, Auto, Register } interface SemanticSymbol { readonly id: number; readonly parentKind: SymbolKind; readonly kind: SymbolKind; readonly isTypeMember: boolean; readonly storage: StorageClass; readonly lsRanges: Range[]; } export interface PublishSemanticHighlightArgs { readonly uri: string; readonly symbols: SemanticSymbol[]; } // function makeSemanticDecorationType( // color: string|undefined, underline: boolean, italic: boolean, // bold: boolean): TextEditorDecorationType { // const opts: DecorationRenderOptions = {}; // opts.rangeBehavior = DecorationRangeBehavior.ClosedClosed; // opts.color = color; // if (underline === true) // opts.textDecoration = 'underline'; // if (italic === true) // opts.fontStyle = 'italic'; // if (bold === true) // opts.fontWeight = 'bold'; // return window.createTextEditorDecorationType( // opts as DecorationRenderOptions); // } export const semanticTypes: {[name: string]: Array<SymbolKind|CclsSymbolKind>} = { enumConstants: [SymbolKind.EnumMember], enums: [SymbolKind.Enum], freeStandingFunctions: [SymbolKind.Function], freeStandingVariables: [], globalVariables: [], macros: [CclsSymbolKind.Macro], memberFunctions: [SymbolKind.Method, SymbolKind.Constructor], memberVariables: [SymbolKind.Field], namespaces: [SymbolKind.Namespace], parameters: [CclsSymbolKind.Parameter], staticMemberFunctions: [CclsSymbolKind.StaticMethod], staticMemberVariables: [], templateParameters: [SymbolKind.TypeParameter], typeAliases: [CclsSymbolKind.TypeAlias], types: [SymbolKind.Class, SymbolKind.Struct], }; // function makeDecorations(type: string) { // const config = workspace.getConfiguration('ccls'); // let colors = config.get(`highlighting.colors.${type}`, [undefined]); // if (colors.length === 0) // colors = [undefined]; // const u = config.get(`highlighting.underline.${type}`, false); // const i = config.get(`highlighting.italic.${type}`, false); // const b = config.get(`highlighting.bold.${type}`, false); // return colors.map((c) => makeSemanticDecorationType(c, u, i, b)); // } // TODO: enable bold/italic decorators, might need change in vscode export class SemanticContext implements Disposable { // private semanticDecorations = new Map<string, TextEditorDecorationType[]>(); private semanticEnabled = new Map<string, boolean>(); // private cachedDecorations = new Map<string, Map<TextEditorDecorationType, Array<Range>>>(); private _dispose: Disposable[] = []; public constructor() { for (const type of Object.keys(semanticTypes)) { // this.semanticDecorations.set(type, makeDecorations(type)); this.semanticEnabled.set(type, false); } this.updateConfigValues(); // workspace.onDidChangeActiveTextEditor( // (editor?: TextEditor) => { // if (editor) { // this.updateDecoration(editor); // } // }, // undefined, // this._dispose // ); } public dispose() { disposeAll(this._dispose); } public publishSemanticHighlight(args: PublishSemanticHighlightArgs) { this.updateConfigValues(); const normUri = normalizeUri(args.uri); // for (const visibleEditor of window.visibleTextEditors) { // if (normUri !== visibleEditor.document.uri.toString(true)) // continue; // // const decorations = new Map<TextEditorDecorationType, Array<Range>>(); // // for (const symbol of args.symbols) { // const type = this.tryFindDecoration(symbol); // if (!type) // continue; // const existing = decorations.get(type); // if (existing) { // for (const range of symbol.lsRanges) { // existing.push(range); // } // } else { // decorations.set(type, symbol.lsRanges); // } // } // TODO limit cache size // this.cachedDecorations.set(normUri, decorations); // this.updateDecoration(visibleEditor); // } } private updateConfigValues() { // Fetch new config instance, since vscode will cache the previous one. const config = workspace.getConfiguration('ccls'); for (const [name, _value] of this.semanticEnabled) { this.semanticEnabled.set(name, config.get(`highlighting.enabled.${name}`, false)); } } // private tryFindDecoration( // symbol: SemanticSymbol // ): TextEditorDecorationType|undefined { // const get = (name: string) => { // if (!this.semanticEnabled.get(name)) // return undefined; // const decorations = unwrap(this.semanticDecorations.get(name), "semantic"); // return decorations[symbol.id % decorations.length]; // }; // // if (symbol.kind === SymbolKind.Variable) { // if (symbol.parentKind === SymbolKind.Function || // symbol.parentKind === SymbolKind.Method || // symbol.parentKind === SymbolKind.Constructor) { // return get('freeStandingVariables'); // } // return get('globalVariables'); // } else if (symbol.kind === SymbolKind.Field) { // if (symbol.storage === StorageClass.Static) { // return get('staticMemberVariables'); // } // return get('memberVariables'); // } else { // for (const name of Object.keys(semanticTypes)) { // const kinds = semanticTypes[name]; // if (kinds.some((e) => e === symbol.kind)) { // return get(name); // } // } // } // } // private updateDecoration(editor: TextEditor) { // const uri = editor.document.uri.toString(true); // const cachedDecoration = this.cachedDecorations.get(uri); // if (cachedDecoration) { // // Clear decorations and set new ones. We might not use all of the // // decorations so clear before setting. // for (const [_, decorations] of this.semanticDecorations) { // decorations.forEach((type) => { // editor.setDecorations(type, []); // }); // } // // Set new decorations. // cachedDecoration.forEach((ranges, type) => { // editor.setDecorations(type, ranges); // }); // } // } }