diff --git a/CHANGELOG.md b/CHANGELOG.md index 04e5bde8..bbc2bb67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ All notable user-visible changes to Hunk are documented in this file. ### Fixed +- Preserved split diff alignment when horizontal scrolling starts inside a wide CJK or emoji character. - Made diff syntax highlighting follow the active theme: keyword, function, number, and variable token colors now resolve to the configured theme's palette (including custom themes) in both light and dark, instead of passing through Pierre's built-in syntax colors. - Expanded the diff window during rapid scrolling bursts so large reviews keep real rows mounted instead of falling back to blank placeholder regions. diff --git a/src/ui/lib/text.ts b/src/ui/lib/text.ts index a46b4504..c929f9c7 100644 --- a/src/ui/lib/text.ts +++ b/src/ui/lib/text.ts @@ -53,6 +53,11 @@ export function sliceTextByWidth(text: string, offset: number, width: number) { continue; } if (clusterStart < startOffset) { + const hiddenCellWidth = Math.min(clusterEnd, startOffset + maxWidth) - startOffset; + if (hiddenCellWidth > 0) { + visibleText += " ".repeat(hiddenCellWidth); + usedWidth += hiddenCellWidth; + } continue; } if (usedWidth + clusterWidth > maxWidth) { diff --git a/src/ui/lib/ui-lib.test.ts b/src/ui/lib/ui-lib.test.ts index ed872994..5bea1f3b 100644 --- a/src/ui/lib/ui-lib.test.ts +++ b/src/ui/lib/ui-lib.test.ts @@ -314,7 +314,9 @@ describe("ui helpers", () => { test("text helpers measure and slice wide characters by terminal cells", () => { expect(measureTextWidth("日本語")).toBe(6); expect(sliceTextByWidth("a日本b", 1, 4)).toEqual({ text: "日本", width: 4 }); - expect(sliceTextByWidth("a日本b", 2, 4)).toEqual({ text: "本b", width: 3 }); + expect(sliceTextByWidth("a日本b", 2, 4)).toEqual({ text: " 本b", width: 4 }); + expect(sliceTextByWidth("日本b", 3, 3)).toEqual({ text: " b", width: 2 }); + expect(sliceTextByWidth("日", 1, 1)).toEqual({ text: " ", width: 1 }); expect(fitText("日本語", 5)).toBe("日本."); expect(measureTextWidth(padText("日本", 6))).toBe(6); });