From f4fded1472c8d9d97e21d8fc3a4a307e2d6607e2 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Tue, 28 Apr 2026 13:28:02 +0700 Subject: [PATCH] fix(app): size file preview gutter to fit 3-digit line numbers (#592) The gutter width formula was calibrated for the diff pane's 12px font, so 3-digit numbers wrapped to two lines in the file preview's 14px gutter. Parameterize on font size and add numberOfLines={1} as a guard. --- packages/app/src/components/code-insets.ts | 9 ++++++--- packages/app/src/components/file-pane.tsx | 8 +++++--- packages/app/src/components/git-diff-pane.tsx | 15 +++++++++++---- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/packages/app/src/components/code-insets.ts b/packages/app/src/components/code-insets.ts index bcb34bf59..d8d1c2905 100644 --- a/packages/app/src/components/code-insets.ts +++ b/packages/app/src/components/code-insets.ts @@ -2,11 +2,14 @@ import type { Theme } from "@/styles/theme"; /** * Compute the pixel width for a line-number gutter based on the highest - * line number that will be displayed. Minimum width accommodates 2 digits. + * line number that will be displayed and the gutter font size. Minimum + * width accommodates 2 digits. The 0.62 factor approximates monospace + * digit width as a fraction of font size. */ -export function lineNumberGutterWidth(maxLineNumber: number): number { +export function lineNumberGutterWidth(maxLineNumber: number, fontSize: number): number { const digits = Math.max(2, String(maxLineNumber).length); - return digits * 8 + 12; + const digitWidth = Math.ceil(fontSize * 0.62); + return digits * digitWidth + 12; } export function getCodeInsets(theme: Theme) { diff --git a/packages/app/src/components/file-pane.tsx b/packages/app/src/components/file-pane.tsx index ac5e85ced..e93f0a64c 100644 --- a/packages/app/src/components/file-pane.tsx +++ b/packages/app/src/components/file-pane.tsx @@ -112,7 +112,9 @@ const CodeLine = React.memo(function CodeLine({ return ( - {String(lineNumber)} + + {String(lineNumber)} + {keyedTokens.map(({ key, token }) => ( @@ -193,8 +195,8 @@ function FilePreviewBody({ const gutterWidth = useMemo(() => { if (!highlightedLines) return 0; - return lineNumberGutterWidth(highlightedLines.length); - }, [highlightedLines]); + return lineNumberGutterWidth(highlightedLines.length, theme.fontSize.sm); + }, [highlightedLines, theme.fontSize.sm]); const imageSource = useMemo( () => (imagePreviewUri ? { uri: imagePreviewUri } : null), diff --git a/packages/app/src/components/git-diff-pane.tsx b/packages/app/src/components/git-diff-pane.tsx index 83f733e9d..9c94b80b2 100644 --- a/packages/app/src/components/git-diff-pane.tsx +++ b/packages/app/src/components/git-diff-pane.tsx @@ -235,7 +235,9 @@ function DiffGutterCell({ ); return ( - {formatDiffGutterText(lineNumber)} + + {formatDiffGutterText(lineNumber)} + ); } @@ -350,7 +352,9 @@ function DiffLineView({ return ( - {formatDiffGutterText(lineNumber)} + + {formatDiffGutterText(lineNumber)} + {line.type !== "header" && visibleTokens ? ( @@ -403,7 +407,9 @@ function SplitDiffLine({ return ( - {formatDiffGutterText(line?.lineNumber ?? null)} + + {formatDiffGutterText(line?.lineNumber ?? null)} + {visibleTokens ? ( @@ -624,6 +630,7 @@ function DiffFileBody({ }) { const [scrollViewWidth, setScrollViewWidth] = useState(0); const [bodyWidth, setBodyWidth] = useState(0); + const { theme } = useUnistyles(); const handleLayout = useCallback( (event: LayoutChangeEvent) => { @@ -660,7 +667,7 @@ function DiffFileBody({ hunk.newStart + hunk.newCount, ); } - const gutterWidth = lineNumberGutterWidth(maxLineNo); + const gutterWidth = lineNumberGutterWidth(maxLineNo, theme.fontSize.xs); if (layout === "split") { const rows = buildSplitDiffRows(file);