diff --git a/src/renderer/src/components/editor/combined-diff/CombinedDiffViewer.tsx b/src/renderer/src/components/editor/combined-diff/CombinedDiffViewer.tsx index c8fbdf44ba1..3df04729bea 100644 --- a/src/renderer/src/components/editor/combined-diff/CombinedDiffViewer.tsx +++ b/src/renderer/src/components/editor/combined-diff/CombinedDiffViewer.tsx @@ -203,6 +203,7 @@ export default function CombinedDiffViewer({ isAllMode: entrySet.isAllMode, isBranchMode: entrySet.isBranchMode, isCommitMode: entrySet.isCommitMode, + requestSectionReloadRef: registry.requestSectionReloadRef, sectionsRef: registry.sectionsRef, setSectionHeights, setSections diff --git a/src/renderer/src/components/editor/combined-diff/review-controls/use-combined-diff-section-actions.ts b/src/renderer/src/components/editor/combined-diff/review-controls/use-combined-diff-section-actions.ts index 13e8da388df..da4c99bfbd2 100644 --- a/src/renderer/src/components/editor/combined-diff/review-controls/use-combined-diff-section-actions.ts +++ b/src/renderer/src/components/editor/combined-diff/review-controls/use-combined-diff-section-actions.ts @@ -26,6 +26,7 @@ export function useCombinedDiffSectionActions({ isAllMode, isBranchMode, isCommitMode, + requestSectionReloadRef, sectionsRef, setSectionHeights, setSections @@ -38,6 +39,7 @@ export function useCombinedDiffSectionActions({ isAllMode: boolean isBranchMode: boolean isCommitMode: boolean + requestSectionReloadRef: React.RefObject<(index: number) => void> sectionsRef: React.RefObject setSectionHeights: React.Dispatch>> setSections: React.Dispatch> @@ -144,6 +146,7 @@ export function useCombinedDiffSectionActions({ const handleSectionSaveRef = useCombinedDiffSectionSave({ file, + requestSectionReloadRef, sectionsRef, setSectionHeights, setSections diff --git a/src/renderer/src/components/editor/combined-diff/review-controls/use-combined-diff-section-save.test.tsx b/src/renderer/src/components/editor/combined-diff/review-controls/use-combined-diff-section-save.test.tsx index 8a05ee573ac..8184b62b62c 100644 --- a/src/renderer/src/components/editor/combined-diff/review-controls/use-combined-diff-section-save.test.tsx +++ b/src/renderer/src/components/editor/combined-diff/review-controls/use-combined-diff-section-save.test.tsx @@ -44,11 +44,18 @@ function section(key = 'file.ts'): DiffSection { } } } +const reloadSpy = vi.fn() function setup(initial = [section()]) { return renderHook(() => { const { sections, setSections, sectionsRef } = useCombinedDiffSectionsState(initial) const [heights, setSectionHeights] = useState>({ 0: 100, 1: 200 }) - const save = useCombinedDiffSectionSave({ file, sectionsRef, setSections, setSectionHeights }) + const save = useCombinedDiffSectionSave({ + file, + requestSectionReloadRef: { current: reloadSpy }, + sectionsRef, + setSections, + setSectionHeights + }) return { sections, setSections, heights, save } }) } @@ -216,3 +223,13 @@ describe('combined diff section saves', () => { expect(writeFile).not.toHaveBeenCalled() }) }) + +it('re-drives a reload after saving, so a revalidation rejected while dirty is not stranded', async () => { + const { result } = setup() + await act(async () => { + await result.current.save.current(0) + }) + // The git-status signature does not change for an edit inside an already-modified line, so the + // save is the only event that can recover a stale original side. + expect(reloadSpy).toHaveBeenCalledWith(0) +}) diff --git a/src/renderer/src/components/editor/combined-diff/review-controls/use-combined-diff-section-save.ts b/src/renderer/src/components/editor/combined-diff/review-controls/use-combined-diff-section-save.ts index 5740c6c74c2..afad698a15f 100644 --- a/src/renderer/src/components/editor/combined-diff/review-controls/use-combined-diff-section-save.ts +++ b/src/renderer/src/components/editor/combined-diff/review-controls/use-combined-diff-section-save.ts @@ -43,11 +43,13 @@ function acknowledgeSectionSave(section: DiffSection, content: string): DiffSect export function useCombinedDiffSectionSave({ file, + requestSectionReloadRef, sectionsRef, setSectionHeights, setSections }: { file: OpenFile + requestSectionReloadRef: React.RefObject<(index: number) => void> sectionsRef: React.RefObject setSectionHeights: React.Dispatch>> setSections: React.Dispatch> @@ -95,6 +97,10 @@ export function useCombinedDiffSectionSave({ : entry ) ) + // Why: a revalidation rejected while this row was dirty left the original side stale, + // and the git-status signature does not change for an edit inside an already-modified + // line, so nothing else re-drives it. The row is clean now, so the reload can proceed. + requestSectionReloadRef.current(savedIndex) }) .catch((error: unknown) => { console.error('Save failed:', error) @@ -107,7 +113,7 @@ export function useCombinedDiffSectionSave({ saves.set(key, tracked) return tracked }, - [file, sectionsRef, setSectionHeights, setSections] + [file, requestSectionReloadRef, sectionsRef, setSectionHeights, setSections] ) const saveRef = useRef(saveSection) useLayoutEffect(() => {