// Explorer and tab decorations from each repository's latest status (spec §5.1). import * as vscode from "vscode"; import { Repository } from "./repository"; export class OxyDecorationProvider implements vscode.FileDecorationProvider, vscode.Disposable { private readonly emitter = new vscode.EventEmitter(); readonly onDidChangeFileDecorations = this.emitter.event; private readonly disposables: vscode.Disposable[] = []; constructor(private readonly repositories: () => Repository[]) { this.disposables.push(vscode.window.registerFileDecorationProvider(this), this.emitter); } /** Call when a repository's status changed; every decoration is recomputed. */ refresh(): void { this.emitter.fire(undefined); } provideFileDecoration(uri: vscode.Uri): vscode.FileDecoration | undefined { if (!vscode.workspace.getConfiguration("oxygen").get("decorations.enabled", true)) { return undefined; } for (const repo of this.repositories()) { const rel = repo.relativePath(uri); if (rel === undefined || !repo.status) { continue; } const entry = repo.status.paths.find((p) => p.path === rel); const conflict = repo.status.conflicts.find((c) => c.path === rel); if (conflict && !entry) { return new vscode.FileDecoration("‼", "conflict", new vscode.ThemeColor("oxygen.conflict")); } if (!entry) { // A directory containing changes gets a dot, like Git. if (repo.status.paths.some((p) => p.path.startsWith(rel + "/"))) { return new vscode.FileDecoration("•", "contains changes", new vscode.ThemeColor("oxygen.modified")); } continue; } const letters: Record = { Added: ["A", "added", "oxygen.added"], Modified: ["M", "modified", "oxygen.modified"], Removed: ["D", "removed", "oxygen.removed"], Renamed: ["R", "renamed", "oxygen.renamed"], ModeChanged: ["X", "mode changed", "oxygen.modified"], ConflictEdited: ["‼", "conflict markers remain", "oxygen.conflict"], Resolved: ["✔", "conflict resolved", "oxygen.resolved"], }; const [badge, tooltip, color] = letters[entry.status] ?? ["?", entry.status, "oxygen.modified"]; const d = new vscode.FileDecoration(badge, tooltip, new vscode.ThemeColor(color)); d.propagate = false; return d; } return undefined; } dispose(): void { for (const d of this.disposables) { d.dispose(); } } }