Add git status utility for TUI.
Provides GitStatus interface and refreshGitStatus function for displaying repository branch, dirty state, untracked files, and commit counts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e501ffeefd
commit
7e03021b25
1 changed files with 70 additions and 0 deletions
70
src/resources/extensions/sf-tui/git.ts
Normal file
70
src/resources/extensions/sf-tui/git.ts
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
import { execFileSync } from "node:child_process";
|
||||
|
||||
export interface GitStatus {
|
||||
branch: string | null;
|
||||
dirty: boolean;
|
||||
untracked: boolean;
|
||||
ahead: number;
|
||||
behind: number;
|
||||
}
|
||||
|
||||
let cache: GitStatus | null = null;
|
||||
let lastFetch = 0;
|
||||
|
||||
export function refreshGitStatus(cwd: string): GitStatus {
|
||||
const now = Date.now();
|
||||
if (now - lastFetch < 400 && cache) return cache;
|
||||
lastFetch = now;
|
||||
|
||||
let branch: string | null = null;
|
||||
try {
|
||||
branch = execFileSync("git", ["branch", "--show-current"], {
|
||||
cwd,
|
||||
encoding: "utf-8",
|
||||
stdio: ["pipe", "pipe", "ignore"],
|
||||
timeout: 1500,
|
||||
}).trim() || null;
|
||||
} catch {
|
||||
cache = { branch: null, dirty: false, untracked: false, ahead: 0, behind: 0 };
|
||||
return cache;
|
||||
}
|
||||
|
||||
try {
|
||||
const status = execFileSync("git", ["status", "--porcelain"], {
|
||||
cwd,
|
||||
encoding: "utf-8",
|
||||
stdio: ["pipe", "pipe", "ignore"],
|
||||
timeout: 1500,
|
||||
});
|
||||
const lines = status.split("\n").filter((l) => l.length > 2);
|
||||
const dirty = lines.some((l) => {
|
||||
const x = l[0] ?? " ";
|
||||
const y = l[1] ?? " ";
|
||||
return x !== "?" && x !== " " && x !== "!" || y !== " " && y !== "?";
|
||||
});
|
||||
const untracked = lines.some((l) => l.startsWith("??"));
|
||||
|
||||
let ahead = 0;
|
||||
let behind = 0;
|
||||
try {
|
||||
const ab = execFileSync("git", ["rev-list", "--left-right", "--count", "HEAD...@{u}"], {
|
||||
cwd,
|
||||
encoding: "utf-8",
|
||||
stdio: ["pipe", "pipe", "ignore"],
|
||||
timeout: 1500,
|
||||
}).trim();
|
||||
const [a, b] = ab.split("\t").map((n) => parseInt(n, 10));
|
||||
ahead = Number.isNaN(a) ? 0 : a;
|
||||
behind = Number.isNaN(b) ? 0 : b;
|
||||
} catch { /* no upstream */ }
|
||||
|
||||
cache = { branch, dirty, untracked, ahead, behind };
|
||||
} catch {
|
||||
cache = { branch, dirty: false, untracked: false, ahead: 0, behind: 0 };
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
export function invalidateGitStatus(): void {
|
||||
lastFetch = 0;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue