Skip to content

Commit

Permalink
feat: add multiline editing in the REPL
Browse files Browse the repository at this point in the history
PR-URL: #2347
Closes: #2060
Co-authored-by: Athan Reines <[email protected]>
Reviewed-by: Athan Reines <[email protected]> 
Signed-off-by: Snehil Shah <[email protected]>
  • Loading branch information
Snehil-Shah and kgryte authored Jun 21, 2024
1 parent 377403b commit 32b9ebf
Show file tree
Hide file tree
Showing 5 changed files with 642 additions and 161 deletions.
15 changes: 9 additions & 6 deletions lib/node_modules/@stdlib/repl/lib/completer_preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -246,34 +246,37 @@ setNonEnumerableReadOnly( PreviewCompleter.prototype, 'onKeypress', function onK
* @type {Function}
* @param {string} data - input data
* @param {(Object|void)} key - key object
* @returns {void}
* @returns {boolean} boolean indicating whether the preview was auto-completed
*/
setNonEnumerableReadOnly( PreviewCompleter.prototype, 'beforeKeypress', function beforeKeypress( data, key ) {
if ( !this._enabled ) {
return;
return false;
}
if ( !key || this._preview === '' ) {
return;
return false;
}
// Avoid clashing with existing TAB completion behavior...
if ( key.name === 'tab' ) {
return this.clear();
this.clear();
return false;
}
// Handle the case where the user is not at the end of the line...
if ( this._rli.cursor !== this._rli.line.length ) {
// 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...
if ( key.name === 'return' || key.name === 'enter' ) {
debug( 'Received an ENTER keypress event while in the middle of the line.' );
return this.clear();
this.clear();
}
return;
return false;
}
// 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)...
if ( key.name === 'return' || key.name === 'enter' || key.name === 'right' ) {
debug( 'Completion preview accepted. Performing auto-completion...' );
this._rli.write( this._preview );
this._preview = '';
return true;
}
return false;
});


Expand Down
25 changes: 16 additions & 9 deletions lib/node_modules/@stdlib/repl/lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ var commands = require( './commands.js' );
var displayPrompt = require( './display_prompt.js' );
var inputPrompt = require( './input_prompt.js' );
var OutputStream = require( './output_stream.js' );
var processLine = require( './process_line.js' );
var completerFactory = require( './completer.js' );
var MultilineHandler = require( './multiline_handler.js' );
var PreviewCompleter = require( './completer_preview.js' );
var AutoCloser = require( './auto_close_pairs.js' );
var SyntaxHighlighter = require( './syntax_highlighter.js' );
Expand Down Expand Up @@ -237,11 +237,6 @@ function REPL( options ) {
// Define the current workspace:
setNonEnumerable( this, '_currentWorkspace', 'base' );

// Initialize an internal status object for multi-line mode:
setNonEnumerable( this, '_multiline', {} );
setNonEnumerable( this._multiline, 'active', false );
setNonEnumerable( this._multiline, 'mode', 'incomplete_expression' );

// Initialize an internal flag indicating whether the REPL has been closed:
setNonEnumerable( this, '_closed', false );

Expand Down Expand Up @@ -273,6 +268,9 @@ function REPL( options ) {
'completer': this._completer
}));

// Initialize a multi-line handler:
setNonEnumerableReadOnly( this, '_multilineHandler', new MultilineHandler( this, this._rli._ttyWrite ) );

// Create a new auto-closer:
setNonEnumerableReadOnly( this, '_autoCloser', new AutoCloser( this._rli, this._settings.autoClosePairs, this._settings.autoDeletePairs ) );

Expand Down Expand Up @@ -337,12 +335,20 @@ function REPL( options ) {
* @param {(Object|void)} key - key object
*/
function beforeKeypress( data, key ) {
var completed;

if ( self._ostream.isPaging ) {
self._ostream.beforeKeypress( data, key );
return;
}
self._autoCloser.beforeKeypress( data, key );
self._previewCompleter.beforeKeypress( data, key );
completed = self._previewCompleter.beforeKeypress( data, key );

// If completion was auto-completed, don't trigger multi-line keybindings to avoid double operations...
if ( !completed ) {
self._multilineHandler.beforeKeypress( data, key );
return;
}
self._ttyWrite.call( self._rli, data, key );
}

Expand All @@ -366,6 +372,7 @@ function REPL( options ) {
if ( autoClosed ) {
self._previewCompleter.clear();
}
self._multilineHandler.onKeypress( data, key );
self._syntaxHighlighter.onKeypress();
self._previewCompleter.onKeypress( data, key );
}
Expand All @@ -379,7 +386,7 @@ function REPL( options ) {
function onLine( line ) {
self._SIGINT = false; // reset flag
if ( self._closed === false ) {
processLine( self, line );
self._multilineHandler.processLine( line );
}
}

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

return this;
});
Expand Down
Loading

1 comment on commit 32b9ebf

@stdlib-bot
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage Report

Package Statements Branches Functions Lines
repl $\color{red}9469/11925$
$\color{green}+79.40\%$
$\color{red}543/745$
$\color{green}+72.89\%$
$\color{red}119/200$
$\color{green}+59.50\%$
$\color{red}9469/11925$
$\color{green}+79.40\%$

The above coverage report was generated for the changes in this push.

Please sign in to comment.