OXYGENHUB
◆ main oxygen-vscode / src / contentProvider.ts
2.0 KiB · last changed Milestone 0.1: source control view, diffs over the oxy: scheme, quick diff, decorations, status bar, commit, quick-pick log; process wrapper with a Node test; packaging 1 month ago source blame history raw
1
// The `oxy:` URI scheme serves file content at a state through `oxy cat`
2
// (spec §3): oxy:/<repository-relative path>?root=<repository root>&change=<change>
3
// where `change` is `@base` (the working copy's base) or anything
4
// `oxy cat -r` accepts.
5
6
import * as vscode from "vscode";
7
import { Oxy } from "./oxy";
8
9
export const SCHEME = "oxy";
10
11
export function oxyUri(root: string, path: string, change: string): vscode.Uri {
12
  const query = new URLSearchParams({ root, change }).toString();
13
  return vscode.Uri.from({ scheme: SCHEME, path: "/" + path, query });
14
}
15
16
export function baseUri(root: string, path: string): vscode.Uri {
17
  return oxyUri(root, path, "@base");
18
}
19
20
export function parseOxyUri(uri: vscode.Uri): { root: string; path: string; change: string } | undefined {
21
  if (uri.scheme !== SCHEME) {
22
    return undefined;
23
  }
24
  const q = new URLSearchParams(uri.query);
25
  const root = q.get("root");
26
  const change = q.get("change") ?? "@base";
27
  if (!root) {
28
    return undefined;
29
  }
30
  return { root, path: uri.path.replace(/^\//, ""), change };
31
}
32
33
export class OxyContentProvider implements vscode.TextDocumentContentProvider {
34
  private readonly emitter = new vscode.EventEmitter<vscode.Uri>();
35
  readonly onDidChange = this.emitter.event;
36
37
  constructor(private readonly oxy: Oxy) {}
38
39
  /** Tell open `oxy:` documents under `root` to reload (after an operation). */
40
  invalidate(root: string): void {
41
    for (const doc of vscode.workspace.textDocuments) {
42
      const parsed = parseOxyUri(doc.uri);
43
      if (parsed && parsed.root === root && parsed.change === "@base") {
44
        this.emitter.fire(doc.uri);
45
      }
46
    }
47
  }
48
49
  async provideTextDocumentContent(uri: vscode.Uri): Promise<string> {
50
    const parsed = parseOxyUri(uri);
51
    if (!parsed) {
52
      return "";
53
    }
54
    try {
55
      const bytes = await this.oxy.cat(parsed.root, parsed.path, parsed.change === "@base" ? undefined : parsed.change);
56
      return bytes.toString("utf8");
57
    } catch {
58
      // A path absent from that state (an added file's base) is empty.
59
      return "";
60
    }
61
  }
62
}