OXYGENHUB
◆ main oxygen-vscode / src / decorations.ts
2.5 KiB · last changed Oxygen colours, a Get started walkthrough, Create Identity (0.14.0) 1 month ago source blame history raw
1
// Explorer and tab decorations from each repository's latest status (spec §5.1).
2
3
import * as vscode from "vscode";
4
import { Repository } from "./repository";
5
6
export class OxyDecorationProvider implements vscode.FileDecorationProvider, vscode.Disposable {
7
  private readonly emitter = new vscode.EventEmitter<vscode.Uri | vscode.Uri[] | undefined>();
8
  readonly onDidChangeFileDecorations = this.emitter.event;
9
  private readonly disposables: vscode.Disposable[] = [];
10
11
  constructor(private readonly repositories: () => Repository[]) {
12
    this.disposables.push(vscode.window.registerFileDecorationProvider(this), this.emitter);
13
  }
14
15
  /** Call when a repository's status changed; every decoration is recomputed. */
16
  refresh(): void {
17
    this.emitter.fire(undefined);
18
  }
19
20
  provideFileDecoration(uri: vscode.Uri): vscode.FileDecoration | undefined {
21
    if (!vscode.workspace.getConfiguration("oxygen").get<boolean>("decorations.enabled", true)) {
22
      return undefined;
23
    }
24
    for (const repo of this.repositories()) {
25
      const rel = repo.relativePath(uri);
26
      if (rel === undefined || !repo.status) {
27
        continue;
28
      }
29
      const entry = repo.status.paths.find((p) => p.path === rel);
30
      const conflict = repo.status.conflicts.find((c) => c.path === rel);
31
      if (conflict && !entry) {
32
        return new vscode.FileDecoration("‼", "conflict", new vscode.ThemeColor("oxygen.conflict"));
33
      }
34
      if (!entry) {
35
        // A directory containing changes gets a dot, like Git.
36
        if (repo.status.paths.some((p) => p.path.startsWith(rel + "/"))) {
37
          return new vscode.FileDecoration("•", "contains changes", new vscode.ThemeColor("oxygen.modified"));
38
        }
39
        continue;
40
      }
41
      const letters: Record<string, [string, string, string]> = {
42
        Added: ["A", "added", "oxygen.added"],
43
        Modified: ["M", "modified", "oxygen.modified"],
44
        Removed: ["D", "removed", "oxygen.removed"],
45
        Renamed: ["R", "renamed", "oxygen.renamed"],
46
        ModeChanged: ["X", "mode changed", "oxygen.modified"],
47
        ConflictEdited: ["‼", "conflict markers remain", "oxygen.conflict"],
48
        Resolved: ["✔", "conflict resolved", "oxygen.resolved"],
49
      };
50
      const [badge, tooltip, color] = letters[entry.status] ?? ["?", entry.status, "oxygen.modified"];
51
      const d = new vscode.FileDecoration(badge, tooltip, new vscode.ThemeColor(color));
52
      d.propagate = false;
53
      return d;
54
    }
55
    return undefined;
56
  }
57
58
  dispose(): void {
59
    for (const d of this.disposables) {
60
      d.dispose();
61
    }
62
  }
63
}