fix(tui): normalized Thai/Lao AM output for terminal rendering

- Added normalizeTerminalOutput to convert precomposed Thai and Lao AM vowels into compatibility decompositions for terminal rendering.
- Converted ASCII classification tables to Uint8Array and updated whitespace and punctuation checks to use bounded code-point lookups.
This commit is contained in:
can1357
2026-05-12 10:11:18 +02:00
parent 6d41cdb68c
commit 8e1bccf97e
+21 -7
View File
@@ -112,12 +112,26 @@ export function visibleWidth(str: string): number {
return visibleWidthRaw(str);
}
const makeBoolArray = (chars: string): ReadonlyArray<boolean> => {
const table = Array.from({ length: 128 }, () => false);
const THAI_LAO_AM_REGEX = /[\u0e33\u0eb3]/;
const THAI_LAO_AM_GLOBAL_REGEX = /[\u0e33\u0eb3]/g;
/**
* Normalize text for terminal output without changing logical editor content.
* Some terminals render precomposed Thai/Lao AM vowels inconsistently during
* differential repaint. Their compatibility decompositions have the same cell
* width but avoid stale-cell artifacts in terminal renderers.
*/
export function normalizeTerminalOutput(str: string): string {
if (!THAI_LAO_AM_REGEX.test(str)) return str;
return str.replace(THAI_LAO_AM_GLOBAL_REGEX, (char) => (char === "\u0e33" ? "\u0e4d\u0e32" : "\u0ecd\u0eb2"));
}
const makeBoolArray = (chars: string): Uint8Array => {
const table = new Uint8Array(128);
for (let i = 0; i < chars.length; i++) {
const code = chars.charCodeAt(i);
if (code < table.length) {
table[code] = true;
table[code] = 1;
}
}
return table;
@@ -129,8 +143,8 @@ const ASCII_WHITESPACE = makeBoolArray("\x09\x0a\x0b\x0c\x0d\x20");
* Check if a character is whitespace.
*/
export function isWhitespaceChar(char: string): boolean {
const code = char.codePointAt(0) || 0;
return ASCII_WHITESPACE[code] ?? false;
const code = char.codePointAt(0) ?? 0;
return code < 128 && ASCII_WHITESPACE[code] === 1;
}
const ASCII_PUNCTUATION = makeBoolArray("(){}[]<>.,;:'\"!?+-=*/\\|&%^$#@~`");
@@ -139,8 +153,8 @@ const ASCII_PUNCTUATION = makeBoolArray("(){}[]<>.,;:'\"!?+-=*/\\|&%^$#@~`");
* Check if a character is punctuation.
*/
export function isPunctuationChar(char: string): boolean {
const code = char.codePointAt(0) || 0;
return ASCII_PUNCTUATION[code] ?? false;
const code = char.codePointAt(0) ?? 0;
return code < 128 && ASCII_PUNCTUATION[code] === 1;
}
export type WordNavKind = "whitespace" | "delimiter" | "cjk" | "word" | "other";