From 8350fbd2d11782c0517abd42d060f04c38eeba39 Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Thu, 29 May 2025 22:36:36 -0700 Subject: [PATCH] Include both staged and unstaged changes in git diff statistics --- .../void/electron-main/voidSCMMainService.ts | 93 ++++++++++++++++--- 1 file changed, 78 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/contrib/void/electron-main/voidSCMMainService.ts b/src/vs/workbench/contrib/void/electron-main/voidSCMMainService.ts index 5294bc23..56f0a26e 100644 --- a/src/vs/workbench/contrib/void/electron-main/voidSCMMainService.ts +++ b/src/vs/workbench/contrib/void/electron-main/voidSCMMainService.ts @@ -20,29 +20,92 @@ const git = async (command: string, path: string): Promise => { } const getNumStat = async (path: string): Promise => { - const output = await git('git diff --numstat', path) - return output - .split('\n') - .map((line) => { - const [added, removed, file] = line.split('\t') - return { - file, - added: parseInt(added, 10) || 0, - removed: parseInt(removed, 10) || 0, - } - }) + // Get both staged and unstaged changes + const [stagedOutput, unstagedOutput] = await Promise.all([ + git('git diff --cached --numstat', path).catch(() => ''), // staged changes + git('git diff --numstat', path).catch(() => '') // unstaged changes + ]) + + const parseOutput = (output: string) => { + if (!output.trim()) return [] + return output + .split('\n') + .filter(line => line.trim()) + .map((line) => { + const [added, removed, file] = line.split('\t') + return { + file, + added: parseInt(added, 10) || 0, + removed: parseInt(removed, 10) || 0, + } + }) + } + + const stagedStats = parseOutput(stagedOutput) + const unstagedStats = parseOutput(unstagedOutput) + + // Combine and deduplicate by file, summing the changes + const fileMap = new Map() + + for (const stat of [...stagedStats, ...unstagedStats]) { + const existing = fileMap.get(stat.file) + if (existing) { + existing.added += stat.added + existing.removed += stat.removed + } else { + fileMap.set(stat.file, { ...stat }) + } + } + + return Array.from(fileMap.values()) } const getSampledDiff = async (file: string, path: string): Promise => { - const diff = await git(`git diff --unified=0 --no-color -- "${file}"`, path) - return diff.slice(0, 2000) + // Get both staged and unstaged diffs + const [stagedDiff, unstagedDiff] = await Promise.all([ + git(`git diff --cached --unified=0 --no-color -- "${file}"`, path).catch(() => ''), // staged changes + git(`git diff --unified=0 --no-color -- "${file}"`, path).catch(() => '') // unstaged changes + ]) + + let combinedDiff = '' + if (stagedDiff.trim()) { + combinedDiff += `=== STAGED CHANGES ===\n${stagedDiff}\n\n` + } + if (unstagedDiff.trim()) { + combinedDiff += `=== UNSTAGED CHANGES ===\n${unstagedDiff}\n\n` + } + + return combinedDiff.slice(0, 2000) } export class VoidSCMService implements IVoidSCMService { readonly _serviceBrand: undefined - gitStat(path: string): Promise { - return git('git diff --stat', path) + async gitStat(path: string): Promise { + // Get both staged and unstaged stats + const [stagedStat, unstagedStat] = await Promise.all([ + git('git diff --cached --stat', path).catch(() => ''), // staged changes + git('git diff --stat', path).catch(() => '') // unstaged changes + ]) + + let combinedStat = '' + if (stagedStat.trim()) { + combinedStat += `Staged changes:\n${stagedStat}\n\n` + } + if (unstagedStat.trim()) { + combinedStat += `Unstaged changes:\n${unstagedStat}\n\n` + } + + // If neither staged nor unstaged changes, check if there are any changes at all + if (!combinedStat.trim()) { + // This will show changes between HEAD and working directory (includes staged changes) + const allChanges = await git('git diff HEAD --stat', path).catch(() => '') + if (allChanges.trim()) { + combinedStat = `All changes:\n${allChanges}` + } + } + + return combinedStat.trim() } async gitSampledDiffs(path: string): Promise {