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:
@@ -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";
|
||||
|
||||
Reference in New Issue
Block a user