diff --git a/packages/review-editor/App.tsx b/packages/review-editor/App.tsx index fa0869e8..1228a0e2 100644 --- a/packages/review-editor/App.tsx +++ b/packages/review-editor/App.tsx @@ -157,6 +157,7 @@ const ReviewApp: React.FC = () => { const diffShowLineNumbers = useConfigValue('diffShowLineNumbers'); const diffShowBackground = useConfigValue('diffShowBackground'); const diffHideWhitespace = useConfigValue('diffHideWhitespace'); + const diffExpandUnchanged = useConfigValue('diffExpandUnchanged'); const diffFontFamily = useConfigValue('diffFontFamily'); const diffFontSize = useConfigValue('diffFontSize'); const diffTabSize = useConfigValue('diffTabSize'); @@ -1400,6 +1401,7 @@ const ReviewApp: React.FC = () => { lineDiffType: diffLineDiffType, disableLineNumbers: !diffShowLineNumbers, disableBackground: !diffShowBackground, + expandUnchanged: diffExpandUnchanged, fontFamily: diffFontFamily || undefined, fontSize: diffFontSize || undefined, // Only propagate base for modes where it affects old/new content. Avoids @@ -1465,7 +1467,7 @@ const ReviewApp: React.FC = () => { }), [ files, activeFileIndex, diffStyle, diffOverflow, diffIndicators, diffLineDiffType, diffShowLineNumbers, diffShowBackground, - diffFontFamily, diffFontSize, activeDiffBase, committedBase, feedbackDiffContext, prReviewScopeLabel, prDiffScope, + diffExpandUnchanged, diffFontFamily, diffFontSize, activeDiffBase, committedBase, feedbackDiffContext, prReviewScopeLabel, prDiffScope, allAnnotations, externalAnnotations, selectedAnnotationId, pendingSelection, handleLineSelection, handleAddAnnotation, handleAddFileComment, handleAddFileCommentForFile, handleEditAnnotation, diff --git a/packages/review-editor/components/AllFilesDiffView.tsx b/packages/review-editor/components/AllFilesDiffView.tsx index a255531d..5f6ea917 100644 --- a/packages/review-editor/components/AllFilesDiffView.tsx +++ b/packages/review-editor/components/AllFilesDiffView.tsx @@ -33,6 +33,7 @@ interface AllFilesDiffViewProps { lineDiffType?: 'word-alt' | 'word' | 'char' | 'none'; disableLineNumbers?: boolean; disableBackground?: boolean; + expandUnchanged?: boolean; fontFamily?: string; fontSize?: string; viewedFiles: Set; @@ -73,6 +74,7 @@ export const AllFilesDiffView: React.FC = ({ lineDiffType, disableLineNumbers, disableBackground, + expandUnchanged, fontFamily, fontSize, viewedFiles, @@ -460,6 +462,7 @@ export const AllFilesDiffView: React.FC = ({ lineDiffType, disableLineNumbers, disableBackground, + expandUnchanged, hunkSeparators: 'line-info', enableLineSelection: true, enableGutterUtility: true, diff --git a/packages/review-editor/components/DiffOptionsPopover.tsx b/packages/review-editor/components/DiffOptionsPopover.tsx index e2ae2701..b871dadf 100644 --- a/packages/review-editor/components/DiffOptionsPopover.tsx +++ b/packages/review-editor/components/DiffOptionsPopover.tsx @@ -95,6 +95,7 @@ export const DiffOptionsPopover: React.FC = () => { const diffShowLineNumbers = useConfigValue('diffShowLineNumbers'); const diffShowBackground = useConfigValue('diffShowBackground'); const diffHideWhitespace = useConfigValue('diffHideWhitespace'); + const diffExpandUnchanged = useConfigValue('diffExpandUnchanged'); const diffTabSize = useConfigValue('diffTabSize'); const diffLineBgIntensity = useConfigValue('diffLineBgIntensity'); @@ -151,6 +152,7 @@ export const DiffOptionsPopover: React.FC = () => { configStore.set('diffLineBgIntensity', v)} /> )} + configStore.set('diffExpandUnchanged', v)} label="Full file context" /> configStore.set('diffHideWhitespace', v)} label="Hide whitespace" /> []; pendingSelection: SelectedLineRange | null; onLineSelectionEnd: (range: SelectedLineRange | null) => void; @@ -55,6 +56,7 @@ const PierreDiffContent = React.memo(({ lineDiffType, disableLineNumbers, disableBackground, + expandUnchanged, mergedAnnotations, pendingSelection, onLineSelectionEnd, @@ -78,6 +80,7 @@ const PierreDiffContent = React.memo(({ lineDiffType, disableLineNumbers, disableBackground, + expandUnchanged, hunkSeparators: 'line-info', enableLineSelection: true, enableGutterUtility: true, @@ -105,6 +108,7 @@ const PierreDiffContent = React.memo(({ prev.lineDiffType === next.lineDiffType && prev.disableLineNumbers === next.disableLineNumbers && prev.disableBackground === next.disableBackground && + prev.expandUnchanged === next.expandUnchanged && prev.mergedAnnotations === next.mergedAnnotations && prev.pendingSelection === next.pendingSelection && prev.onLineSelectionEnd === next.onLineSelectionEnd && @@ -131,6 +135,7 @@ interface DiffViewerProps { lineDiffType?: 'word-alt' | 'word' | 'char' | 'none'; disableLineNumbers?: boolean; disableBackground?: boolean; + expandUnchanged?: boolean; fontFamily?: string; fontSize?: string; annotations: CodeAnnotation[]; @@ -180,6 +185,7 @@ export const DiffViewer: React.FC = ({ lineDiffType, disableLineNumbers, disableBackground, + expandUnchanged, fontFamily, fontSize, annotations, @@ -408,7 +414,7 @@ export const DiffViewer: React.FC = ({ roots.forEach(root => applySearchHighlights(root, query, matches, activeSearchMatchId) ); - }, [searchQuery, searchMatches, filePath, diffStyle, diffOverflow, diffIndicators, lineDiffType, disableLineNumbers, disableBackground, augmentedDiff, viewport]); + }, [searchQuery, searchMatches, filePath, diffStyle, diffOverflow, diffIndicators, lineDiffType, disableLineNumbers, disableBackground, expandUnchanged, augmentedDiff, viewport]); // Swap active search highlight instantly when stepping between matches. // This avoids a full rebuild just to change two elements' background color. @@ -421,7 +427,7 @@ export const DiffViewer: React.FC = ({ useEffect(() => { if (!activeSearchMatch || !containerRef.current) return; return retryScrollToSearchMatch(containerRef.current, activeSearchMatch); - }, [activeSearchMatch, filePath, diffStyle, diffOverflow, diffIndicators, lineDiffType, disableLineNumbers, disableBackground, viewport]); + }, [activeSearchMatch, filePath, diffStyle, diffOverflow, diffIndicators, lineDiffType, disableLineNumbers, disableBackground, expandUnchanged, viewport]); // Map annotations to @pierre/diffs format const lineAnnotations = useMemo(() => { @@ -606,6 +612,7 @@ export const DiffViewer: React.FC = ({ lineDiffType={lineDiffType} disableLineNumbers={disableLineNumbers} disableBackground={disableBackground} + expandUnchanged={expandUnchanged} mergedAnnotations={mergedAnnotations} pendingSelection={pendingSelection} onLineSelectionEnd={handlePierreLineSelectionEnd} diff --git a/packages/review-editor/dock/ReviewStateContext.tsx b/packages/review-editor/dock/ReviewStateContext.tsx index f9cf02a1..146c3ae3 100644 --- a/packages/review-editor/dock/ReviewStateContext.tsx +++ b/packages/review-editor/dock/ReviewStateContext.tsx @@ -26,6 +26,7 @@ export interface ReviewState { lineDiffType?: 'word-alt' | 'word' | 'char' | 'none'; disableLineNumbers?: boolean; disableBackground?: boolean; + expandUnchanged?: boolean; fontFamily?: string; fontSize?: string; /** User-selected base branch; feeds the `base` query param on file-content fetches. */ diff --git a/packages/review-editor/dock/panels/ReviewAllFilesDiffPanel.tsx b/packages/review-editor/dock/panels/ReviewAllFilesDiffPanel.tsx index 3ccc8895..b781ca2a 100644 --- a/packages/review-editor/dock/panels/ReviewAllFilesDiffPanel.tsx +++ b/packages/review-editor/dock/panels/ReviewAllFilesDiffPanel.tsx @@ -24,6 +24,7 @@ export const ReviewAllFilesDiffPanel: React.FC = () => { lineDiffType={state.lineDiffType} disableLineNumbers={state.disableLineNumbers} disableBackground={state.disableBackground} + expandUnchanged={state.expandUnchanged} fontFamily={state.fontFamily} fontSize={state.fontSize} viewedFiles={state.viewedFiles} diff --git a/packages/review-editor/dock/panels/ReviewDiffPanel.tsx b/packages/review-editor/dock/panels/ReviewDiffPanel.tsx index 8498fcc6..60787ce5 100644 --- a/packages/review-editor/dock/panels/ReviewDiffPanel.tsx +++ b/packages/review-editor/dock/panels/ReviewDiffPanel.tsx @@ -80,6 +80,7 @@ export const ReviewDiffPanel: React.FC = (props) => { lineDiffType={state.lineDiffType} disableLineNumbers={state.disableLineNumbers} disableBackground={state.disableBackground} + expandUnchanged={state.expandUnchanged} fontFamily={state.fontFamily} fontSize={state.fontSize} annotations={fileAnnotations} diff --git a/packages/shared/config.ts b/packages/shared/config.ts index 10b0908b..e8722842 100644 --- a/packages/shared/config.ts +++ b/packages/shared/config.ts @@ -24,6 +24,7 @@ export interface DiffOptions { fontSize?: string; tabSize?: number; hideWhitespace?: boolean; + expandUnchanged?: boolean; defaultDiffType?: DefaultDiffType; lineBgIntensity?: DiffLineBgIntensity; } diff --git a/packages/ui/components/Settings.tsx b/packages/ui/components/Settings.tsx index 79b8e675..6c6a207f 100644 --- a/packages/ui/components/Settings.tsx +++ b/packages/ui/components/Settings.tsx @@ -237,6 +237,7 @@ const ReviewDisplayTab: React.FC = () => { const diffShowBackground = useConfigValue('diffShowBackground'); const diffLineBgIntensity = useConfigValue('diffLineBgIntensity'); const diffHideWhitespace = useConfigValue('diffHideWhitespace'); + const diffExpandUnchanged = useConfigValue('diffExpandUnchanged'); const diffFontFamily = useConfigValue('diffFontFamily'); const diffFontSize = useConfigValue('diffFontSize'); @@ -383,6 +384,16 @@ const ReviewDisplayTab: React.FC = () => {
+ {/* Expand Unchanged Regions */} + configStore.set('diffExpandUnchanged', v)} + label="Expand Unchanged Regions" + description="Show full file content around changes by default" + /> + +
+ {/* Hide Whitespace */} ({ diffOptions: { hideWhitespace: v } }), }, + diffExpandUnchanged: { + defaultValue: false as boolean, + fromCookie: () => { + const v = storage.getItem('plannotator-diff-expand-unchanged'); + return v === 'true' ? true : v === 'false' ? false : undefined; + }, + toCookie: (v: boolean) => storage.setItem('plannotator-diff-expand-unchanged', String(v)), + serverKey: 'diffOptions', + fromServer: (sc: Record) => { + const v = (sc.diffOptions as Record | undefined)?.expandUnchanged; + return typeof v === 'boolean' ? v : undefined; + }, + toServer: (v: boolean) => ({ diffOptions: { expandUnchanged: v } }), + }, + diffFontSize: { defaultValue: '' as string, // empty = theme default fromCookie: () => storage.getItem('plannotator-diff-font-size') || undefined,