@@ -142,8 +142,14 @@ export class CliInput extends EventEmitter {
142142 // Backspace
143143 if ( chunk === "\x7f" || chunk === "\b" ) {
144144 if ( this . buffer . length > 0 ) {
145+ const removed = this . buffer . slice ( - 1 ) ;
145146 this . buffer = this . buffer . slice ( 0 , - 1 ) ;
146- process . stdout . write ( "\b \b" ) ;
147+ // CJK and other wide characters take 2 terminal columns
148+ if ( this . isWideChar ( removed ) ) {
149+ process . stdout . write ( "\b \b\b \b" ) ;
150+ } else {
151+ process . stdout . write ( "\b \b" ) ;
152+ }
147153 }
148154 return ;
149155 }
@@ -259,4 +265,24 @@ export class CliInput extends EventEmitter {
259265 showInputPrompt ( ) : void {
260266 this . showPrompt ( ) ;
261267 }
268+
269+ /** Check if a character is full-width (CJK, emoji, etc.) */
270+ private isWideChar ( ch : string ) : boolean {
271+ const code = ch . codePointAt ( 0 ) ?? 0 ;
272+ return (
273+ ( code >= 0x1100 && code <= 0x115f ) || // Hangul Jamo
274+ ( code >= 0x2e80 && code <= 0x303e ) || // CJK Radicals
275+ ( code >= 0x3040 && code <= 0x33bf ) || // Japanese
276+ ( code >= 0x3400 && code <= 0x4dbf ) || // CJK Unified Extension A
277+ ( code >= 0x4e00 && code <= 0x9fff ) || // CJK Unified
278+ ( code >= 0xa960 && code <= 0xa97c ) || // Hangul Jamo Extended-A
279+ ( code >= 0xac00 && code <= 0xd7a3 ) || // Hangul Syllables
280+ ( code >= 0xf900 && code <= 0xfaff ) || // CJK Compatibility
281+ ( code >= 0xfe30 && code <= 0xfe6b ) || // CJK Compatibility Forms
282+ ( code >= 0xff01 && code <= 0xff60 ) || // Fullwidth Forms
283+ ( code >= 0xffe0 && code <= 0xffe6 ) || // Fullwidth Signs
284+ ( code >= 0x1f000 && code <= 0x1fbff ) || // Emoji & Symbols
285+ ( code >= 0x20000 && code <= 0x2ffff ) // CJK Extension B+
286+ ) ;
287+ }
262288}
0 commit comments