Skip to content

Commit 9147f69

Browse files
authored
fix: example command hanging in REPL when executing multi-line code
PR-URL: #2706 Resolves: #2273 --------- Signed-off-by: Snehil Shah <snehilshah.989@gmail.com> Reviewed-by: Athan Reines <kgryte@gmail.com> Reviewed-by: Philipp Burckhardt <pburckhardt@outlook.com>
1 parent 48ba6d6 commit 9147f69

File tree

2 files changed

+68
-52
lines changed

2 files changed

+68
-52
lines changed

lib/node_modules/@stdlib/repl/lib/commands/example.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ function command( repl, cmds ) {
5757
function onCommand( alias ) {
5858
var aliases;
5959
var entry;
60+
var lines;
6061
var out;
6162
var len;
6263
var N;
@@ -133,6 +134,7 @@ function command( repl, cmds ) {
133134
}
134135
}
135136
if ( out ) {
137+
lines = [];
136138
out = out.split( RE_EOL );
137139
len = out.length;
138140
i = -1;
@@ -149,13 +151,27 @@ function command( repl, cmds ) {
149151
* @private
150152
* @param {string} cmd - command
151153
* @param {boolean} success - boolean indicating whether the command successfully executed
154+
* @returns {void}
152155
*/
153156
function next() {
157+
var j;
154158
i += 1;
155159
if ( i < len ) {
156160
// Forward the next line to the REPL readline interface in order to mimic user input...
157161
if ( out[ i ] ) {
158-
repl._rli.write( out[ i ]+'\n' );
162+
lines.push( out[ i ] );
163+
164+
// If line is part of a multi-line input, wait for the next line...
165+
if ( repl._multilineHandler.isMultilineInput( lines.join( '\n' ) ) ) {
166+
return next();
167+
}
168+
for ( j = 0; j < lines.length; j++ ) {
169+
repl._rli.write( lines[ j ] );
170+
repl._rli.write( '\n', {
171+
'name': 'return'
172+
});
173+
}
174+
lines = [];
159175
repl.once( 'drain', next );
160176
} else {
161177
nextTick( next );

lib/node_modules/@stdlib/repl/lib/multiline_handler.js

Lines changed: 51 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -394,56 +394,6 @@ setNonEnumerableReadOnly( MultilineHandler.prototype, '_triggerMultiline', funct
394394
this._rli.line = this._rli.line.substring( 0, this._rli.cursor );
395395
});
396396

397-
/**
398-
* Checks if the command is incomplete and a multi-line input.
399-
*
400-
* @private
401-
* @name _isMultilineInput
402-
* @memberof MultilineHandler.prototype
403-
* @type {Function}
404-
* @param {string} cmd - command
405-
* @returns {boolean} boolean indicating whether the command is a multi-line input
406-
*/
407-
setNonEnumerableReadOnly( MultilineHandler.prototype, '_isMultilineInput', function isMultilineInput( cmd ) {
408-
var node;
409-
var tmp;
410-
var ast;
411-
412-
debug( 'Attempting to detect multi-line input...' );
413-
if ( RE_WHITESPACE.test( cmd ) ) {
414-
debug( 'Multi-line input not detected.' );
415-
return false;
416-
}
417-
if ( RE_SINGLE_LINE_COMMENT.test( cmd ) || RE_MULTI_LINE_COMMENT.test( cmd ) ) { // eslint-disable-line max-len
418-
debug( 'Multi-line input not detected.' );
419-
return false;
420-
}
421-
// Check if the command has valid syntax...
422-
tmp = processCommand( cmd );
423-
if ( !( tmp instanceof Error ) ) {
424-
debug( 'Multi-line input not detected.' );
425-
return false;
426-
}
427-
if ( hasMultilineError( cmd, AOPTS ) ) {
428-
debug( 'Detected multi-line input. Triggering multi-line mode...' );
429-
return true;
430-
}
431-
// Still possible that a user is attempting to enter an object literal across multiple lines...
432-
ast = parseLoose( cmd, AOPTS );
433-
434-
// Check for a trailing node which is being interpreted as a block statement, as this could be an object literal...
435-
node = ast.body[ ast.body.length-1 ];
436-
if ( node.type === 'BlockStatement' && node.end === ast.end ) {
437-
tmp = cmd.slice( node.start, node.end );
438-
if ( hasMultilineError( tmp, AOPTS ) ) {
439-
debug( 'Detected multi-line input. Triggering multi-line mode...' );
440-
return true;
441-
}
442-
}
443-
debug( 'Multi-line input not detected.' );
444-
return false;
445-
});
446-
447397
/**
448398
* Resets input buffers.
449399
*
@@ -581,6 +531,55 @@ setNonEnumerableReadOnly( MultilineHandler.prototype, 'isPasting', function isPa
581531
return this._multiline.pasteMode;
582532
});
583533

534+
/**
535+
* Checks if the command is incomplete and a multi-line input.
536+
*
537+
* @name isMultilineInput
538+
* @memberof MultilineHandler.prototype
539+
* @type {Function}
540+
* @param {string} cmd - command
541+
* @returns {boolean} boolean indicating whether the command is a multi-line input
542+
*/
543+
setNonEnumerableReadOnly( MultilineHandler.prototype, 'isMultilineInput', function isMultilineInput( cmd ) {
544+
var node;
545+
var tmp;
546+
var ast;
547+
548+
debug( 'Attempting to detect multi-line input...' );
549+
if ( RE_WHITESPACE.test( cmd ) ) {
550+
debug( 'Multi-line input not detected.' );
551+
return false;
552+
}
553+
if ( RE_SINGLE_LINE_COMMENT.test( cmd ) || RE_MULTI_LINE_COMMENT.test( cmd ) ) { // eslint-disable-line max-len
554+
debug( 'Multi-line input not detected.' );
555+
return false;
556+
}
557+
// Check if the command has valid syntax...
558+
tmp = processCommand( cmd );
559+
if ( !( tmp instanceof Error ) ) {
560+
debug( 'Multi-line input not detected.' );
561+
return false;
562+
}
563+
if ( hasMultilineError( cmd, AOPTS ) ) {
564+
debug( 'Detected multi-line input. Triggering multi-line mode...' );
565+
return true;
566+
}
567+
// Still possible that a user is attempting to enter an object literal across multiple lines...
568+
ast = parseLoose( cmd, AOPTS );
569+
570+
// Check for a trailing node which is being interpreted as a block statement, as this could be an object literal...
571+
node = ast.body[ ast.body.length-1 ];
572+
if ( node.type === 'BlockStatement' && node.end === ast.end ) {
573+
tmp = cmd.slice( node.start, node.end );
574+
if ( hasMultilineError( tmp, AOPTS ) ) {
575+
debug( 'Detected multi-line input. Triggering multi-line mode...' );
576+
return true;
577+
}
578+
}
579+
debug( 'Multi-line input not detected.' );
580+
return false;
581+
});
582+
584583
/**
585584
* Processes input line data.
586585
*
@@ -737,9 +736,10 @@ setNonEnumerableReadOnly( MultilineHandler.prototype, 'beforeKeypress', function
737736
case 'return':
738737
cmd = copy( this._cmd );
739738
cmd[ this._lineIndex ] = this._rli.line;
739+
this._lines[ this._lineIndex ] = this._rli.line;
740740

741741
// If we are in paste mode or the command is incomplete, trigger multi-line mode...
742-
if ( !this._multiline.pasteMode && !this._isMultilineInput( cmd.join( '\n' ) ) ) {
742+
if ( !this._multiline.pasteMode && !this.isMultilineInput( cmd.join( '\n' ) ) ) {
743743
this._ttyWrite.call( this._rli, data, key );
744744
return;
745745
}

0 commit comments

Comments
 (0)