import type { GitFileStatus } from "./git-types"; export interface GitPorcelainEntry { path: string; originalPath?: string; indexStatus: string; worktreeStatus: string; } function usesRenamePath(indexStatus: string, worktreeStatus: string): boolean { return indexStatus === "R" || indexStatus === "C" || worktreeStatus === "R" || worktreeStatus === "C"; } export function parseGitPorcelainV1(output: string): GitPorcelainEntry[] { const records = output.split("\0"); const entries: GitPorcelainEntry[] = []; for (let i = 0; i < records.length; i++) { const record = records[i]; if (!record || record.length < 4 || record[2] !== " ") continue; const indexStatus = record[0]; const worktreeStatus = record[1]; const entry: GitPorcelainEntry = { path: record.slice(3), indexStatus, worktreeStatus, }; if (usesRenamePath(indexStatus, worktreeStatus)) { entry.originalPath = records[++i] || undefined; } entries.push(entry); } return entries; } const CONFLICT_STATUSES = new Set(["DD", "AU", "UD", "UA", "DU", "AA", "UU"]); export function classifyGitStatus(entry: GitPorcelainEntry): Pick { const pair = `${entry.indexStatus}${entry.worktreeStatus}`; if (pair === "??") return { status: "untracked", code: "U" }; if (CONFLICT_STATUSES.has(pair) || pair.includes("U")) return { status: "conflict", code: "C" }; if (pair.includes("D")) return { status: "deleted", code: "D" }; if (pair.includes("R") || pair.includes("C")) return { status: "renamed", code: "R" }; if (pair.includes("A")) return { status: "added", code: "A" }; return { status: "modified", code: "M" }; }