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.
This commit is contained in:
Mohamed Boudra
2026-04-28 13:28:02 +07:00
parent b23e60a8f4
commit f4fded1472
3 changed files with 22 additions and 10 deletions
+6 -3
View File
@@ -2,11 +2,14 @@ import type { Theme } from "@/styles/theme";
/** /**
* Compute the pixel width for a line-number gutter based on the highest * 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); 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) { export function getCodeInsets(theme: Theme) {
+5 -3
View File
@@ -112,7 +112,9 @@ const CodeLine = React.memo(function CodeLine({
return ( return (
<View style={codeLineStyles.line}> <View style={codeLineStyles.line}>
<View style={gutterStyle}> <View style={gutterStyle}>
<Text style={gutterTextStyle}>{String(lineNumber)}</Text> <Text numberOfLines={1} style={gutterTextStyle}>
{String(lineNumber)}
</Text>
</View> </View>
<Text selectable style={codeLineStyles.lineText}> <Text selectable style={codeLineStyles.lineText}>
{keyedTokens.map(({ key, token }) => ( {keyedTokens.map(({ key, token }) => (
@@ -193,8 +195,8 @@ function FilePreviewBody({
const gutterWidth = useMemo(() => { const gutterWidth = useMemo(() => {
if (!highlightedLines) return 0; if (!highlightedLines) return 0;
return lineNumberGutterWidth(highlightedLines.length); return lineNumberGutterWidth(highlightedLines.length, theme.fontSize.sm);
}, [highlightedLines]); }, [highlightedLines, theme.fontSize.sm]);
const imageSource = useMemo( const imageSource = useMemo(
() => (imagePreviewUri ? { uri: imagePreviewUri } : null), () => (imagePreviewUri ? { uri: imagePreviewUri } : null),
+11 -4
View File
@@ -235,7 +235,9 @@ function DiffGutterCell({
); );
return ( return (
<View style={containerStyle}> <View style={containerStyle}>
<Text style={textStyle}>{formatDiffGutterText(lineNumber)}</Text> <Text numberOfLines={1} style={textStyle}>
{formatDiffGutterText(lineNumber)}
</Text>
</View> </View>
); );
} }
@@ -350,7 +352,9 @@ function DiffLineView({
return ( return (
<View style={containerStyle}> <View style={containerStyle}>
<View style={gutterStyle}> <View style={gutterStyle}>
<Text style={gutterTextStyle}>{formatDiffGutterText(lineNumber)}</Text> <Text numberOfLines={1} style={gutterTextStyle}>
{formatDiffGutterText(lineNumber)}
</Text>
</View> </View>
{line.type !== "header" && visibleTokens ? ( {line.type !== "header" && visibleTokens ? (
<HighlightedText tokens={visibleTokens} wrapLines={wrapLines} /> <HighlightedText tokens={visibleTokens} wrapLines={wrapLines} />
@@ -403,7 +407,9 @@ function SplitDiffLine({
return ( return (
<View style={containerStyle}> <View style={containerStyle}>
<View style={gutterStyle}> <View style={gutterStyle}>
<Text style={gutterTextStyle}>{formatDiffGutterText(line?.lineNumber ?? null)}</Text> <Text numberOfLines={1} style={gutterTextStyle}>
{formatDiffGutterText(line?.lineNumber ?? null)}
</Text>
</View> </View>
{visibleTokens ? ( {visibleTokens ? (
<HighlightedText tokens={visibleTokens} wrapLines={wrapLines} /> <HighlightedText tokens={visibleTokens} wrapLines={wrapLines} />
@@ -624,6 +630,7 @@ function DiffFileBody({
}) { }) {
const [scrollViewWidth, setScrollViewWidth] = useState(0); const [scrollViewWidth, setScrollViewWidth] = useState(0);
const [bodyWidth, setBodyWidth] = useState(0); const [bodyWidth, setBodyWidth] = useState(0);
const { theme } = useUnistyles();
const handleLayout = useCallback( const handleLayout = useCallback(
(event: LayoutChangeEvent) => { (event: LayoutChangeEvent) => {
@@ -660,7 +667,7 @@ function DiffFileBody({
hunk.newStart + hunk.newCount, hunk.newStart + hunk.newCount,
); );
} }
const gutterWidth = lineNumberGutterWidth(maxLineNo); const gutterWidth = lineNumberGutterWidth(maxLineNo, theme.fontSize.xs);
if (layout === "split") { if (layout === "split") {
const rows = buildSplitDiffRows(file); const rows = buildSplitDiffRows(file);