fix(tui): preserve line number alignment

This commit is contained in:
James Long
2026-07-30 16:38:17 +00:00
parent 0d4ab8e6be
commit 71a86995c6
2 changed files with 23 additions and 5 deletions
+20 -5
View File
@@ -3,6 +3,7 @@ import { DiffRenderable, LineNumberRenderable, type ColorInput } from "@opentui/
import type { JSX } from "@opentui/solid"
import { createMemo, For, Show, splitProps } from "solid-js"
import { splitPatchHunks } from "../util/diff"
import { stringWidth } from "../util/string-width"
type Props = Omit<JSX.IntrinsicElements["diff"], "diff" | "lineNumberBg"> & {
diff: string
@@ -19,12 +20,26 @@ export function PatchDiff(props: Props) {
const sides = [...nodes]
.filter((item) => !item.isDestroyed)
.flatMap((item) => item.getChildren().filter((side) => side instanceof LineNumberRenderable))
const max = Math.max(...sides.flatMap((side) => [...side.getLineNumbers().values()]))
if (!max && attempt < 2) return syncGutters(attempt + 1)
if (!max) return
const lineNumbers = sides.map((side) => new Map([...side.getLineNumbers()].filter(([line]) => line >= 0)))
const digits = lineNumbers.map((numbers) => Math.max(0, ...numbers.values()).toString().length)
const after = sides.map((side) =>
Math.max(
0,
...[...side.getLineSigns()]
.filter(([line]) => line >= 0)
.map(([, sign]) => stringWidth(sign.after ?? "")),
),
)
const maxDigits = Math.max(...digits)
const maxAfter = Math.max(...after)
if (!maxDigits && attempt < 2) return syncGutters(attempt + 1)
if (!maxDigits) return
sides.forEach((side) => {
side.setLineNumbers(new Map([...side.getLineNumbers(), [-1, max]]))
side.setLineSigns(new Map([...side.getLineSigns(), [-1, { after: " " }]]))
const index = sides.indexOf(side)
const signs = new Map([...side.getLineSigns()].filter(([line]) => line >= 0))
signs.set(-1, { after: " ".repeat(maxAfter + maxDigits - digits[index]) })
side.setLineNumbers(lineNumbers[index])
side.setLineSigns(signs)
})
})
}
@@ -46,6 +46,8 @@ test("renders separate diff nodes with a full-width hunk row", async () => {
const frame = app.captureCharFrame()
const headerRow = frame.split("\n").findIndex((line) => line.includes("@@ -20,3 +20,3 @@"))
const header = frame.split("\n")[headerRow]
const firstLine = frame.split("\n").find((line) => line.includes("const first")) ?? ""
const secondLine = frame.split("\n").find((line) => line.includes("const second")) ?? ""
const background = parseColor("#222222")
expect(header?.startsWith("@@ -20,3 +20,3 @@")).toBe(true)
@@ -66,6 +68,7 @@ test("renders separate diff nodes with a full-width hunk row", async () => {
expect(diffs).toHaveLength(2)
expect(gutters[0].width).toBeGreaterThan(0)
expect(new Set(gutters.map((gutter) => gutter.width)).size).toBe(1)
expect(firstLine.search(/\d/)).toBe(secondLine.search(/\d/))
})
function findDiffs(root: Renderable): DiffRenderable[] {