Skip to content

Commit 9739f1a

Browse files
committed
refactor: extract status badges to separate module with CSS-based approach
- Create GitStatusBadgeManager class in src/statusBadges.ts - Use data-git-status attribute + ::after pseudo-element for badge rendering - Simplify main.ts from 908 to 472 lines - Add MutationObserver with requestAnimationFrame throttling - Support incremental updates via noteCreate/noteModify/noteDelete/noteRename - Remove unused getFileStatusesForPaths from git.ts
1 parent 09a10b6 commit 9739f1a

File tree

5 files changed

+368
-348
lines changed

5 files changed

+368
-348
lines changed

main.js

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/git.ts

Lines changed: 47 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -243,52 +243,65 @@ export async function revertFile(cwd: string, gitPath: string, filePath: string)
243243

244244
export type FileStatus = "M" | "A" | "R" | "U" | "";
245245

246-
export async function getFileStatuses(cwd: string, gitPath: string): Promise<Map<string, FileStatus>> {
246+
function parsePorcelainV1Z(stdout: string): Map<string, FileStatus> {
247247
const statusMap = new Map<string, FileStatus>();
248+
if (!stdout) return statusMap;
248249

249-
try {
250-
const stdout = await runGit({ cwd, gitPath, args: ["status", "--porcelain=v1", "-z"] });
251-
if (!stdout) return statusMap;
252-
253-
const parts = stdout.split("\0").filter(Boolean);
250+
const parts = stdout.split("\0").filter(Boolean);
254251

255-
for (let i = 0; i < parts.length; i++) {
256-
const entry = parts[i];
257-
const xy = entry.slice(0, 2);
258-
let filePath = entry.slice(3);
252+
for (let i = 0; i < parts.length; i++) {
253+
const entry = parts[i];
254+
const xy = entry.slice(0, 2);
255+
let filePath = entry.slice(3);
259256

260-
// Rename/copy entries include an extra NUL-separated "new path"
261-
if (xy.startsWith("R") || xy.startsWith("C")) {
262-
const newPath = parts[++i];
263-
if (newPath) filePath = newPath;
264-
}
257+
if (xy.includes("R") || xy.includes("C")) {
258+
const newPath = parts[++i];
259+
if (newPath) filePath = newPath;
260+
}
265261

266-
// Determine status: X is staged, Y is unstaged
267-
let status: FileStatus = "";
268-
269-
if (xy.includes("U")) {
270-
status = "U"; // Unmerged / conflict (highest priority)
271-
} else if (xy === "??") {
272-
status = "A"; // Untracked = new file
273-
} else if (xy.includes("A")) {
274-
status = "A"; // Added
275-
} else if (xy.includes("M")) {
276-
status = "M"; // Modified
277-
} else if (xy.includes("R") || xy.includes("C")) {
278-
status = "R"; // Renamed / copied
279-
}
262+
let status: FileStatus = "";
263+
if (xy.includes("U")) {
264+
status = "U";
265+
} else if (xy === "??") {
266+
status = "A";
267+
} else if (xy.includes("A")) {
268+
status = "A";
269+
} else if (xy.includes("M")) {
270+
status = "M";
271+
} else if (xy.includes("R") || xy.includes("C")) {
272+
status = "R";
273+
}
280274

281-
if (filePath && status) {
282-
statusMap.set(filePath, status);
283-
}
275+
if (filePath && status) {
276+
statusMap.set(filePath, status);
284277
}
285-
} catch {
286-
// Not a git repo or git error
287278
}
288279

289280
return statusMap;
290281
}
291282

283+
export async function getFileStatuses(cwd: string, gitPath: string): Promise<Map<string, FileStatus>> {
284+
try {
285+
const stdout = await runGit({ cwd, gitPath, args: ["status", "--porcelain=v1", "-z"] });
286+
return parsePorcelainV1Z(stdout);
287+
} catch {
288+
return new Map<string, FileStatus>();
289+
}
290+
}
291+
292+
export async function getTrackedFiles(cwd: string, gitPath: string): Promise<Set<string>> {
293+
const tracked = new Set<string>();
294+
try {
295+
const stdout = await runGit({ cwd, gitPath, args: ["ls-files", "-z"] });
296+
if (stdout) {
297+
stdout.split("\0").filter(Boolean).forEach((p) => tracked.add(p));
298+
}
299+
} catch {
300+
// Ignore
301+
}
302+
return tracked;
303+
}
304+
292305
// Get remote default branch (main/master)
293306
export async function getRemoteDefaultBranch(cwd: string, gitPath: string): Promise<string | null> {
294307
try {

0 commit comments

Comments
 (0)