@@ -494,81 +494,67 @@ Interface.prototype._insertString = function(c) {
494
494
} ;
495
495
496
496
Interface . prototype . _tabComplete = function ( lastKeypressWasTab ) {
497
- const self = this ;
498
-
499
- self . pause ( ) ;
500
- self . completer ( self . line . slice ( 0 , self . cursor ) , function onComplete ( err , rv ) {
501
- self . resume ( ) ;
497
+ this . pause ( ) ;
498
+ this . completer ( this . line . slice ( 0 , this . cursor ) , ( err , value ) => {
499
+ this . resume ( ) ;
502
500
503
501
if ( err ) {
504
- self . _writeToOutput ( `Tab completion error: ${ inspect ( err ) } ` ) ;
502
+ this . _writeToOutput ( `Tab completion error: ${ inspect ( err ) } ` ) ;
505
503
return ;
506
504
}
507
505
508
506
// Result and the text that was completed.
509
- const [ completions , completeOn ] = rv ;
507
+ const [ completions , completeOn ] = value ;
510
508
511
509
if ( ! completions || completions . length === 0 ) {
512
510
return ;
513
511
}
514
512
515
- // Apply/show completions.
516
- if ( lastKeypressWasTab ) {
517
- self . _writeToOutput ( '\r\n' ) ;
518
- const width = completions . reduce ( ( a , b ) => {
519
- return a . length > b . length ? a : b ;
520
- } ) . length + 2 ; // 2 space padding
521
- let maxColumns = MathFloor ( self . columns / width ) ;
522
- if ( ! maxColumns || maxColumns === Infinity ) {
523
- maxColumns = 1 ;
524
- }
525
- let group = [ ] ;
526
- for ( const c of completions ) {
527
- if ( c === '' ) {
528
- handleGroup ( self , group , width , maxColumns ) ;
529
- group = [ ] ;
530
- } else {
531
- group . push ( c ) ;
532
- }
533
- }
534
- handleGroup ( self , group , width , maxColumns ) ;
535
- }
536
-
537
513
// If there is a common prefix to all matches, then apply that portion.
538
- const f = completions . filter ( ( e ) => e ) ;
539
- const prefix = commonPrefix ( f ) ;
514
+ const prefix = commonPrefix ( completions . filter ( ( e ) => e !== '' ) ) ;
540
515
if ( prefix . length > completeOn . length ) {
541
- self . _insertString ( prefix . slice ( completeOn . length ) ) ;
516
+ this . _insertString ( prefix . slice ( completeOn . length ) ) ;
517
+ return ;
542
518
}
543
519
544
- self . _refreshLine ( ) ;
545
- } ) ;
546
- } ;
520
+ if ( ! lastKeypressWasTab ) {
521
+ return ;
522
+ }
547
523
548
- // this = Interface instance
549
- function handleGroup ( self , group , width , maxColumns ) {
550
- if ( group . length === 0 ) {
551
- return ;
552
- }
553
- const minRows = MathCeil ( group . length / maxColumns ) ;
554
- for ( let row = 0 ; row < minRows ; row ++ ) {
555
- for ( let col = 0 ; col < maxColumns ; col ++ ) {
556
- const idx = row * maxColumns + col ;
557
- if ( idx >= group . length ) {
558
- break ;
524
+ // Apply/show completions.
525
+ const completionsWidth = completions . map ( ( e ) => getStringWidth ( e ) ) ;
526
+ const width = MathMax ( ...completionsWidth ) + 2 ; // 2 space padding
527
+ let maxColumns = MathFloor ( this . columns / width ) || 1 ;
528
+ if ( maxColumns === Infinity ) {
529
+ maxColumns = 1 ;
530
+ }
531
+ let output = '\r\n' ;
532
+ let lineIndex = 0 ;
533
+ let whitespace = 0 ;
534
+ for ( let i = 0 ; i < completions . length ; i ++ ) {
535
+ const completion = completions [ i ] ;
536
+ if ( completion === '' || lineIndex === maxColumns ) {
537
+ output += '\r\n' ;
538
+ lineIndex = 0 ;
539
+ whitespace = 0 ;
540
+ } else {
541
+ output += ' ' . repeat ( whitespace ) ;
559
542
}
560
- const item = group [ idx ] ;
561
- self . _writeToOutput ( item ) ;
562
- if ( col < maxColumns - 1 ) {
563
- for ( let s = 0 ; s < width - item . length ; s ++ ) {
564
- self . _writeToOutput ( ' ' ) ;
565
- }
543
+ if ( completion !== '' ) {
544
+ output += completion ;
545
+ whitespace = width - completionsWidth [ i ] ;
546
+ lineIndex ++ ;
547
+ } else {
548
+ output += '\r\n' ;
566
549
}
567
550
}
568
- self . _writeToOutput ( '\r\n' ) ;
569
- }
570
- self . _writeToOutput ( '\r\n' ) ;
571
- }
551
+ if ( lineIndex !== 0 ) {
552
+ output += '\r\n\r\n' ;
553
+ }
554
+ this . _writeToOutput ( output ) ;
555
+ this . _refreshLine ( ) ;
556
+ } ) ;
557
+ } ;
572
558
573
559
Interface . prototype . _wordLeft = function ( ) {
574
560
if ( this . cursor > 0 ) {
@@ -1125,7 +1111,7 @@ Interface.prototype[SymbolAsyncIterator] = function() {
1125
1111
* accepts a readable Stream instance and makes it emit "keypress" events
1126
1112
*/
1127
1113
1128
- function emitKeypressEvents ( stream , iface ) {
1114
+ function emitKeypressEvents ( stream , iface = { } ) {
1129
1115
if ( stream [ KEYPRESS_DECODER ] ) return ;
1130
1116
1131
1117
stream [ KEYPRESS_DECODER ] = new StringDecoder ( 'utf8' ) ;
@@ -1138,26 +1124,25 @@ function emitKeypressEvents(stream, iface) {
1138
1124
1139
1125
function onData ( b ) {
1140
1126
if ( stream . listenerCount ( 'keypress' ) > 0 ) {
1141
- const r = stream [ KEYPRESS_DECODER ] . write ( b ) ;
1142
- if ( r ) {
1127
+ const string = stream [ KEYPRESS_DECODER ] . write ( b ) ;
1128
+ if ( string ) {
1143
1129
clearTimeout ( timeoutId ) ;
1144
1130
1145
- let escapeTimeout = ESCAPE_CODE_TIMEOUT ;
1146
-
1147
- if ( iface ) {
1148
- iface . _sawKeyPress = r . length === 1 ;
1149
- escapeTimeout = iface . escapeCodeTimeout ;
1150
- }
1131
+ // This supports characters of length 2.
1132
+ iface . _sawKeyPress = charLengthAt ( string , 0 ) === string . length ;
1133
+ const escapeTimeout = iface . escapeCodeTimeout || ESCAPE_CODE_TIMEOUT ;
1151
1134
1152
- for ( let i = 0 ; i < r . length ; i ++ ) {
1153
- if ( r [ i ] === '\t' && typeof r [ i + 1 ] === 'string' && iface ) {
1135
+ let length = 0 ;
1136
+ for ( const character of string ) {
1137
+ length += character . length ;
1138
+ if ( character === '\t' && length !== string . length ) {
1154
1139
iface . isCompletionEnabled = false ;
1155
1140
}
1156
1141
1157
1142
try {
1158
- stream [ ESCAPE_DECODER ] . next ( r [ i ] ) ;
1143
+ stream [ ESCAPE_DECODER ] . next ( character ) ;
1159
1144
// Escape letter at the tail position
1160
- if ( r [ i ] === kEscape && i + 1 === r . length ) {
1145
+ if ( character === kEscape && length === string . length ) {
1161
1146
timeoutId = setTimeout ( escapeCodeTimeout , escapeTimeout ) ;
1162
1147
}
1163
1148
} catch ( err ) {
0 commit comments