Skip to content

feat: add bracketed-paste mode in the REPL #2502

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Jul 5, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions lib/node_modules/@stdlib/repl/lib/auto_close_pairs.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,19 @@ function isQuote( ch ) {
* @param {Object} rli - readline instance
* @param {boolean} autoClose - boolean indicating whether auto-closing should be initially enabled
* @param {boolean} autoDelete - boolean indicating whether auto-deleting should be initially enabled
* @param {MultilineHandler} multiline - multiline handler instance
* @returns {AutoCloser} auto-closer instance
*/
function AutoCloser( rli, autoClose, autoDelete ) {
function AutoCloser( rli, autoClose, autoDelete, multiline ) {
if ( !(this instanceof AutoCloser) ) {
return new AutoCloser( rli, autoClose, autoDelete );
return new AutoCloser( rli, autoClose, autoDelete, multiline );
}
debug( 'Creating an auto-closer...' );
this._rli = rli;
this._ignoreBackspace = false;
this._autoClose = autoClose;
this._autoDelete = autoDelete;
this._multiline = multiline;
return this;
}

Expand Down Expand Up @@ -316,6 +318,9 @@ setNonEnumerableReadOnly( AutoCloser.prototype, 'beforeKeypress', function befor
if ( !this._autoDelete ) {
return false;
}
if ( this._multiline.isPasting() ) {
return false;
}
if ( !key || key.name !== 'backspace' ) {
return false;
}
Expand Down Expand Up @@ -360,6 +365,9 @@ setNonEnumerableReadOnly( AutoCloser.prototype, 'onKeypress', function onKeypres
if ( !this._autoClose ) {
return false;
}
if ( this._multiline.isPasting() ) {
return false;
}
cursor = this._rli.cursor;
line = this._rli.line;

Expand Down
8 changes: 4 additions & 4 deletions lib/node_modules/@stdlib/repl/lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@
}
opts.isTTY = ( opts.isTTY === void 0 ) ? opts.output.isTTY : opts.isTTY;
opts.settings.autoPage = ( opts.settings.autoPage === void 0 ) ? opts.isTTY : opts.settings.autoPage; // eslint-disable-line max-len
opts.settings.bracketedPaste = ( opts.settings.bracketedPaste === void 0 ) ? opts.isTTY : opts.settings.bracketedPaste; // eslint-disable-line max-len
opts.settings.bracketedPaste = ( opts.settings.bracketedPaste === void 0 && opts.isTTY ) ? true : opts.settings.bracketedPaste; // eslint-disable-line max-len
opts.settings.completionPreviews = ( opts.settings.completionPreviews === void 0 ) ? opts.isTTY : opts.settings.completionPreviews; // eslint-disable-line max-len
opts.settings.autoDisableBracketedPasteOnExit = ( opts.settings.autoDisableBracketedPasteOnExit === void 0 ) ? opts.isTTY : opts.settings.autoDisableBracketedPasteOnExit; // eslint-disable-line max-len
opts.settings.syntaxHighlighting = ( opts.settings.syntaxHighlighting === void 0 ) ? opts.isTTY : opts.settings.syntaxHighlighting; // eslint-disable-line max-len
Expand Down Expand Up @@ -279,7 +279,7 @@
setNonEnumerableReadOnly( this, '_completerEngine', new CompleterEngine( this, this._completer, this._wstream, this._rli._ttyWrite ) );

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

// Initialize a preview completer:
setNonEnumerableReadOnly( this, '_previewCompleter', new PreviewCompleter( this._rli, this._completer, this._ostream, this._settings.completionPreviews ) );
Expand All @@ -291,7 +291,7 @@
setNonEnumerableReadOnly( this, '_ttyWrite', this._rli._ttyWrite );

// Overwrite the private `ttyWrite` method to allow processing input before a "keypress" event is triggered:
this._rli._ttyWrite = beforeKeypress; // WARNING: overwriting a private property

Check warning on line 294 in lib/node_modules/@stdlib/repl/lib/main.js

View workflow job for this annotation

GitHub Actions / Lint Changed Files

Unexpected 'warning' comment: 'WARNING: overwriting a private property'

// Add event listeners:
this._rli.on( 'close', onClose );
Expand All @@ -311,9 +311,9 @@
// Write a welcome message:
this._wstream.write( opts.welcome );

// TODO: check whether to synchronously initialize a REPL history file

Check warning on line 314 in lib/node_modules/@stdlib/repl/lib/main.js

View workflow job for this annotation

GitHub Actions / Lint Changed Files

Unexpected 'todo' comment: 'TODO: check whether to synchronously...'

// TODO: check whether to synchronously initialize a REPL log file

Check warning on line 316 in lib/node_modules/@stdlib/repl/lib/main.js

View workflow job for this annotation

GitHub Actions / Lint Changed Files

Unexpected 'todo' comment: 'TODO: check whether to synchronously...'

// Add any provided user-defined themes...
if ( opts.themes ) {
Expand All @@ -326,7 +326,7 @@
this.settings( 'theme', opts.settings.theme );

// Initialize specified bracketed-paste setting in TTY environments:
if ( this._isTTY ) {
if ( opts.settings.bracketedPaste !== void 0 ) {
this.settings( 'bracketedPaste', opts.settings.bracketedPaste );
}
// Check whether to load and execute a JavaScript file (e.g., prior REPL history) upon startup...
Expand Down Expand Up @@ -412,7 +412,7 @@
* @private
*/
function onClose() {
if ( self._settings.autoDisableBracketedPasteOnExit ) {
if ( self._settings.bracketedPaste && self._settings.autoDisableBracketedPasteOnExit ) { // eslint-disable-line max-len
self._multilineHandler.disableBracketedPaste();
}
ostream.end();
Expand Down Expand Up @@ -499,9 +499,9 @@
// Update the internal command history buffer: [..., <id>, <cmd>, <success>, ...]
self._history.push( self._count, cmd, success );

// TODO: if successful and if necessary, (asynchronously?) write the command to a history file (question: do we only want to write successful commands to the history file? maybe we need to option for limiting to successful commands?)

Check warning on line 502 in lib/node_modules/@stdlib/repl/lib/main.js

View workflow job for this annotation

GitHub Actions / Lint Changed Files

Unexpected 'todo' comment: 'TODO: if successful and if necessary,...'

// TODO: if necessary, (asynchronously?) write the command and result to a log file (JSON serialization?)

Check warning on line 504 in lib/node_modules/@stdlib/repl/lib/main.js

View workflow job for this annotation

GitHub Actions / Lint Changed Files

Unexpected 'todo' comment: 'TODO: if necessary, (asynchronously?)...'
}
}

Expand Down Expand Up @@ -740,7 +740,7 @@

// Before creating a new execution context in a non-sandboxed environment, remove current workspace variables in order to allow garbage collection and avoid memory leaks (e.g., variables/functions declared during a REPL session which might remain bound to the environment `global` after clearing a REPL):
if ( this._sandbox === false ) {
// WARNING: in a non-sandboxed environment, if a global variable is externally introduced during a REPL session (i.e., introduced via a mechanism outside of the REPL environment), we will delete that global variable, which means the following logic may introduce unintended side-effects for this particular edge case (e.g., application code may expect the presence of the subsequently deleted global variable). While not ideal, (a) user applications should not be introducing globals to begin with and (b) the probability of a user running a REPL session, a user clearing that REPL session, AND a global variable being introduced between starting a REPL and clearing the REPL should be negligible.

Check warning on line 743 in lib/node_modules/@stdlib/repl/lib/main.js

View workflow job for this annotation

GitHub Actions / Lint Changed Files

Unexpected 'warning' comment: 'WARNING: in a non-sandboxed environment,...'
tmp = this._context.vars();
for ( i = 0; i < tmp.length; i++ ) {
if ( isConfigurableProperty( this._context, tmp[ i ] ) ) {
Expand Down Expand Up @@ -1344,9 +1344,9 @@
// Clear the command queue:
this._queue.clear();

// TODO: ensure REPL history is saved (flushed) to file before closing the REPL (see https://github.com/nodejs/node/blob/b21e7c7bcf23a2715951e4cd96180e4dbf1dcd4d/lib/repl.js#L805)

Check warning on line 1347 in lib/node_modules/@stdlib/repl/lib/main.js

View workflow job for this annotation

GitHub Actions / Lint Changed Files

Unexpected 'todo' comment: 'TODO: ensure REPL history is saved...'

// TODO: ensure REPL log is saved (flushed) to file before closing the REPL

Check warning on line 1349 in lib/node_modules/@stdlib/repl/lib/main.js

View workflow job for this annotation

GitHub Actions / Lint Changed Files

Unexpected 'todo' comment: 'TODO: ensure REPL log is saved (flushed)...'

nextTick( onTick );

Expand All @@ -1369,7 +1369,7 @@

// If this is a non-sandboxed REPL, remove global variables/properties which were introduced during context creation and by a user during a REPL session...
if ( self._sandbox === false ) {
// WARNING: in a non-sandboxed environment, if a global variable is externally introduced during a REPL session (i.e., introduced via a mechanism outside of the REPL environment), we will delete that global variable, which means the following logic may introduce unintended side-effects for this particular edge case (e.g., application code may expect the presence of the subsequently deleted global variable). While not ideal, (a) user applications should not be introducing globals to begin with and (b) the probability of a user running a REPL session, a user closing that REPL session, AND a global variable being introduced between starting a REPL and closing the REPL should be negligible.

Check warning on line 1372 in lib/node_modules/@stdlib/repl/lib/main.js

View workflow job for this annotation

GitHub Actions / Lint Changed Files

Unexpected 'warning' comment: 'WARNING: in a non-sandboxed environment,...'
tmp = self._context.vars(); // current workspace variables
for ( i = 0; i < tmp.length; i++ ) {
if ( isConfigurableProperty( self._context, tmp[ i ] ) ) {
Expand Down Expand Up @@ -1449,7 +1449,7 @@
throw new Error( format( 'invalid argument. First argument must be a recognized setting. Value: `%s`.', name ) );
}
if ( nargs === 1 ) {
return this._settings[ name ]; // TODO: we should consider returning a deep copy if settings are allowed to be objects, not just primitives, in order to avoid unintentional mutation

Check warning on line 1452 in lib/node_modules/@stdlib/repl/lib/main.js

View workflow job for this annotation

GitHub Actions / Lint Changed Files

Unexpected 'todo' comment: 'TODO: we should consider returning a...'
}
value = arguments[ 1 ];
f = SETTINGS_VALIDATORS[ SETTINGS[ name ].type ];
Expand Down
7 changes: 2 additions & 5 deletions lib/node_modules/@stdlib/repl/lib/multiline_handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -401,9 +401,8 @@ setNonEnumerableReadOnly( MultilineHandler.prototype, 'resetInput', function res
});

/**
* Enables bracketed paste mode.
* Enables bracketed-paste mode.
*
* @private
* @name enableBracketedPaste
* @memberof MultilineHandler.prototype
* @type {Function}
Expand All @@ -414,9 +413,8 @@ setNonEnumerableReadOnly( MultilineHandler.prototype, 'enableBracketedPaste', fu
});

/**
* Disables bracketed paste mode.
* Disables bracketed-paste mode.
*
* @private
* @name disableBracketedPaste
* @memberof MultilineHandler.prototype
* @type {Function}
Expand All @@ -429,7 +427,6 @@ setNonEnumerableReadOnly( MultilineHandler.prototype, 'disableBracketedPaste', f
/**
* Checks whether the REPL is currently receiving pasted input.
*
* @private
* @name isPasting
* @memberof MultilineHandler.prototype
* @type {Function}
Expand Down
Loading