import path from 'node:path'; import * as vscode from 'vscode'; import { isArchifyFile } from '../sources/detect'; import { log } from '../util/log'; import { Brand, brandValueAt, loadBrandCatalog } from './brands'; const JSON_SOURCES = '**/*.{architecture,workflow,sequence,dataflow,lifecycle}.json'; export const BRAND_COMPLETION_SELECTOR: vscode.DocumentSelector = [ { pattern: '**/*.archify' }, { language: 'json', pattern: JSON_SOURCES }, { language: 'jsonc', pattern: JSON_SOURCES }, ]; /** Suggests Archify's built-in brand IDs for `brand` values. */ export class BrandCompletionProvider implements vscode.CompletionItemProvider { private brands: Brand[] | undefined; constructor(private readonly extensionPath: string) {} private catalog(): Brand[] { if (!this.brands) { try { this.brands = loadBrandCatalog(path.join(this.extensionPath, 'vendor', 'archify', 'brand-marks', 'catalog.json')); } catch (error) { log().error(`Could not read the Archify brand catalog: ${error instanceof Error ? error.message : String(error)}`); this.brands = []; } } return this.brands; } provideCompletionItems(document: vscode.TextDocument, position: vscode.Position): vscode.CompletionItem[] | undefined { const linePrefix = document.lineAt(position.line).text.slice(0, position.character); const value = brandValueAt(linePrefix, isArchifyFile(document.fileName) ? 'yaml' : 'json'); if (!value) return undefined; const range = new vscode.Range(position.translate(0, -value.typed.length), position); return this.catalog().map((brand) => { const item = new vscode.CompletionItem({ label: brand.id, description: brand.title }, vscode.CompletionItemKind.Value); item.detail = `${brand.title} ยท ${brand.category}`; if (brand.aliases.length) item.documentation = `Also matches: ${brand.aliases.join(', ')}`; // Typing an alias or the product name finds the brand too. item.filterText = [brand.id, ...brand.aliases, brand.title].join(' '); item.range = range; return item; }); } }