Skip to content

Commit ccd406b

Browse files
authored
fix(tui): prevent truncateMiddle overflow at small widths (#60287)
1 parent 6b9f214 commit ccd406b

4 files changed

Lines changed: 27 additions & 0 deletions

File tree

‎packages/tui/src/util/locale.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,13 @@ export function truncateLeft(str: string, len: number): string {
6767
}
6868

6969
export function truncateMiddle(str: string, maxLength: number = 35): string {
70+
if (maxLength <= 0) return ""
7071
if (str.length <= maxLength) return str
7172

7273
const ellipsis = "…"
7374
const keepStart = Math.ceil((maxLength - ellipsis.length) / 2)
7475
const keepEnd = Math.floor((maxLength - ellipsis.length) / 2)
76+
if (keepEnd <= 0) return str.slice(0, keepStart) + ellipsis
7577

7678
return str.slice(0, keepStart) + ellipsis + str.slice(-keepEnd)
7779
}

‎packages/tui/test/util/locale.test.ts‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,15 @@ test("rolls the compact form over at the rounding boundary", () => {
1818
expect(Locale.number(999950)).toBe("1.0M")
1919
expect(Locale.number(1000000)).toBe("1.0M")
2020
})
21+
22+
test("truncates text in the middle without overflowing small widths", () => {
23+
expect(Locale.truncateMiddle("abcdefghij", 0)).toBe("")
24+
expect(Locale.truncateMiddle("abcdefghij", 1)).toBe("…")
25+
expect(Locale.truncateMiddle("abcdefghij", 2)).toBe("a…")
26+
expect(Locale.truncateMiddle("abcdefghij", 3)).toBe("a…j")
27+
expect(Locale.truncateMiddle("abcdefghij", 4)).toBe("ab…j")
28+
expect(Locale.truncateMiddle("abcdefghij", 9)).toBe("abcd…ghij")
29+
expect(Locale.truncateMiddle("abcd", 4)).toBe("abcd")
30+
expect(Locale.truncateMiddle("abcd", 10)).toBe("abcd")
31+
expect(Locale.truncateMiddle("a", 1)).toBe("a")
32+
})

‎packages/util/src/path.test.ts‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,17 @@ describe("client paths", () => {
3737
expect(getFilenameTruncated("/repo/long-component-name.tsx", 16)).toBe("long-compon….tsx")
3838
expect(truncateMiddle("abcdefghijklmnop", 9)).toBe("abcd…mnop")
3939
})
40+
41+
test("truncates in the middle without overflowing small widths", () => {
42+
expect(truncateMiddle("abcdefghij", 0)).toBe("")
43+
expect(truncateMiddle("abcdefghij", 1)).toBe("…")
44+
expect(truncateMiddle("abcdefghij", 2)).toBe("a…")
45+
expect(truncateMiddle("abcdefghij", 3)).toBe("a…j")
46+
expect(truncateMiddle("abcdefghij", 4)).toBe("ab…j")
47+
expect(truncateMiddle("abcd", 4)).toBe("abcd")
48+
expect(truncateMiddle("abcd", 10)).toBe("abcd")
49+
expect(truncateMiddle("a", 1)).toBe("a")
50+
})
4051
})
4152

4253
describe("encodeFilePath", () => {

‎packages/util/src/path.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ export function getFilenameTruncated(path: string | undefined, maxLength = 20) {
2323
}
2424

2525
export function truncateMiddle(text: string, maxLength = 20) {
26+
if (maxLength <= 0) return ""
2627
if (text.length <= maxLength) return text
2728
const available = maxLength - 1
2829
const start = Math.ceil(available / 2)
2930
const end = Math.floor(available / 2)
31+
if (end <= 0) return text.slice(0, start) + "…"
3032
return text.slice(0, start) + "…" + text.slice(-end)
3133
}
3234

0 commit comments

Comments
 (0)