119 lines · 4.9 KB
import * as vscode from "vscode";
import type { ChangeStatus, RoomControl } from "../lib/editor-protocol";
import type { EditorSessionInfo, ForgeApi } from "./forge";
import type { GitforFileSystem } from "./fs";

const LABELS: Record<ChangeStatus, string> = { A: "Added", M: "Modified", D: "Deleted" };

type CommitResult = { sha: string; branch: string; pullUrl: string | null; pullError: string | null; files: number };

/**
 * Source Control view over the room's pending changes (shared by everyone in the session). Commit
 * snapshots the room to the branch through the forge, which enforces protection and opens a PR when needed.
 */
export class GitforScm implements vscode.Disposable {
  private readonly scm: vscode.SourceControl;
  private readonly changes: vscode.SourceControlResourceGroup;
  private readonly conflicts: vscode.SourceControlResourceGroup;
  private readonly disposables: vscode.Disposable[] = [];

  constructor(
    private readonly api: ForgeApi,
    private readonly fs: GitforFileSystem,
    private session: EditorSessionInfo,
  ) {
    this.scm = vscode.scm.createSourceControl("gitfor", `gitfor: ${session.ref}`, fs.uri("").with({ path: fs.root }));
    this.scm.inputBox.placeholder = session.protected
      ? `Message (commits to a new branch and opens a pull request into ${session.ref})`
      : `Message (commit to ${session.ref})`;
    this.scm.acceptInputCommand = { command: "gitfor.commit", title: "Commit" };
    this.conflicts = this.scm.createResourceGroup("conflicts", "Conflicts with upstream");
    this.conflicts.hideWhenEmpty = true;
    this.changes = this.scm.createResourceGroup("changes", "Changes (shared)");
    this.disposables.push(
      this.scm,
      vscode.workspace.registerTextDocumentContentProvider("gitfor-base", {
        provideTextDocumentContent: async (uri) => (await this.api.blob(uri.path.replace(/^\//, ""))).content ?? "",
      }),
      vscode.commands.registerCommand("gitfor.commit", () => this.commit()),
      vscode.commands.registerCommand("gitfor.commitToBranch", () => this.commit(true)),
      vscode.commands.registerCommand("gitfor.openChange", (path: string) => this.openChange(path)),