Skip to content

Commit 32b9ebf

Browse files
Snehil-Shahkgryte
andauthored
feat: add multiline editing in the REPL
PR-URL: #2347 Closes: #2060 Co-authored-by: Athan Reines <kgryte@gmail.com> Reviewed-by: Athan Reines <kgryte@gmail.com> Signed-off-by: Snehil Shah <snehilshah.989@gmail.com>
1 parent 377403b commit 32b9ebf

File tree

5 files changed

+642
-161
lines changed

5 files changed

+642
-161
lines changed

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -246,34 +246,37 @@ setNonEnumerableReadOnly( PreviewCompleter.prototype, 'onKeypress', function onK
246246
* @type {Function}
247247
* @param {string} data - input data
248248
* @param {(Object|void)} key - key object
249-
* @returns {void}
249+
* @returns {boolean} boolean indicating whether the preview was auto-completed
250250
*/
251251
setNonEnumerableReadOnly( PreviewCompleter.prototype, 'beforeKeypress', function beforeKeypress( data, key ) {
252252
if ( !this._enabled ) {
253-
return;
253+
return false;
254254
}
255255
if ( !key || this._preview === '' ) {
256-
return;
256+
return false;
257257
}
258258
// Avoid clashing with existing TAB completion behavior...
259259
if ( key.name === 'tab' ) {
260-
return this.clear();
260+
this.clear();
261+
return false;
261262
}
262263
// Handle the case where the user is not at the end of the line...
263264
if ( this._rli.cursor !== this._rli.line.length ) {
264265
// If a user is in the middle of a line and presses ENTER, clear the preview string, as the preview was not accepted prior to executing the expression...
265266
if ( key.name === 'return' || key.name === 'enter' ) {
266267
debug( 'Received an ENTER keypress event while in the middle of the line.' );
267-
return this.clear();
268+
this.clear();
268269
}
269-
return;
270+
return false;
270271
}
271272
// When the user is at the end of the line, auto-complete the line with the completion preview when a user presses RETURN or the RIGHT arrow key (note: pressing ENTER will result in both completion AND execution)...
272273
if ( key.name === 'return' || key.name === 'enter' || key.name === 'right' ) {
273274
debug( 'Completion preview accepted. Performing auto-completion...' );
274275
this._rli.write( this._preview );
275276
this._preview = '';
277+
return true;
276278
}
279+
return false;
277280
});
278281

279282

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

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ var commands = require( './commands.js' );
6161
var displayPrompt = require( './display_prompt.js' );
6262
var inputPrompt = require( './input_prompt.js' );
6363
var OutputStream = require( './output_stream.js' );
64-
var processLine = require( './process_line.js' );
6564
var completerFactory = require( './completer.js' );
65+
var MultilineHandler = require( './multiline_handler.js' );
6666
var PreviewCompleter = require( './completer_preview.js' );
6767
var AutoCloser = require( './auto_close_pairs.js' );
6868
var SyntaxHighlighter = require( './syntax_highlighter.js' );
@@ -237,11 +237,6 @@ function REPL( options ) {
237237
// Define the current workspace:
238238
setNonEnumerable( this, '_currentWorkspace', 'base' );
239239

240-
// Initialize an internal status object for multi-line mode:
241-
setNonEnumerable( this, '_multiline', {} );
242-
setNonEnumerable( this._multiline, 'active', false );
243-
setNonEnumerable( this._multiline, 'mode', 'incomplete_expression' );
244-
245240
// Initialize an internal flag indicating whether the REPL has been closed:
246241
setNonEnumerable( this, '_closed', false );
247242

@@ -273,6 +268,9 @@ function REPL( options ) {
273268
'completer': this._completer
274269
}));
275270

271+
// Initialize a multi-line handler:
272+
setNonEnumerableReadOnly( this, '_multilineHandler', new MultilineHandler( this, this._rli._ttyWrite ) );
273+
276274
// Create a new auto-closer:
277275
setNonEnumerableReadOnly( this, '_autoCloser', new AutoCloser( this._rli, this._settings.autoClosePairs, this._settings.autoDeletePairs ) );
278276

@@ -337,12 +335,20 @@ function REPL( options ) {
337335
* @param {(Object|void)} key - key object
338336
*/
339337
function beforeKeypress( data, key ) {
338+
var completed;
339+
340340
if ( self._ostream.isPaging ) {
341341
self._ostream.beforeKeypress( data, key );
342342
return;
343343
}
344344
self._autoCloser.beforeKeypress( data, key );
345-
self._previewCompleter.beforeKeypress( data, key );
345+
completed = self._previewCompleter.beforeKeypress( data, key );
346+
347+
// If completion was auto-completed, don't trigger multi-line keybindings to avoid double operations...
348+
if ( !completed ) {
349+
self._multilineHandler.beforeKeypress( data, key );
350+
return;
351+
}
346352
self._ttyWrite.call( self._rli, data, key );
347353
}
348354

@@ -366,6 +372,7 @@ function REPL( options ) {
366372
if ( autoClosed ) {
367373
self._previewCompleter.clear();
368374
}
375+
self._multilineHandler.onKeypress( data, key );
369376
self._syntaxHighlighter.onKeypress();
370377
self._previewCompleter.onKeypress( data, key );
371378
}
@@ -379,7 +386,7 @@ function REPL( options ) {
379386
function onLine( line ) {
380387
self._SIGINT = false; // reset flag
381388
if ( self._closed === false ) {
382-
processLine( self, line );
389+
self._multilineHandler.processLine( line );
383390
}
384391
}
385392

@@ -1261,7 +1268,7 @@ setNonEnumerableReadOnly( REPL.prototype, 'clearCommand', function onClearComman
12611268
throw new Error( 'invalid operation. Cannot clear the command buffer of a REPL which has already closed.' );
12621269
}
12631270
// Clear any command which has been buffered but not yet executed:
1264-
this._cmd.length = 0;
1271+
this._multilineHandler.resetInput();
12651272

12661273
return this;
12671274
});

0 commit comments

Comments
 (0)