From 415c47ba1c5bf9d54cdb211eb1500d64b46eaca6 Mon Sep 17 00:00:00 2001 From: 0PrashantYadav0 Date: Wed, 26 Aug 2026 16:24:47 +0530 Subject: [PATCH 1/3] bug: REPL rendering goes awry when entering a command exceeding the terminal width --- lib/node_modules/@stdlib/repl/lib/defaults.js | 5 +- lib/node_modules/@stdlib/repl/lib/main.js | 3 +- .../@stdlib/repl/lib/welcome_text.js | 84 +++++++++++++++++-- 3 files changed, 79 insertions(+), 13 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/defaults.js b/lib/node_modules/@stdlib/repl/lib/defaults.js index 10a683a3f74a..10a1d7053b4b 100644 --- a/lib/node_modules/@stdlib/repl/lib/defaults.js +++ b/lib/node_modules/@stdlib/repl/lib/defaults.js @@ -23,7 +23,6 @@ var stdin = require( '@stdlib/streams/node/stdin' ); var stdout = require( '@stdlib/streams/node/stdout' ); var DEFAULT_KEYBINDINGS = require( './default_keybindings.js' ); -var WELCOME = require( './welcome_text.js' ); // MAIN // @@ -64,8 +63,8 @@ function defaults() { // Flag indicating whether to run a REPL in a sandboxed context: 'sandbox': true, - // Welcome message: - 'welcome': WELCOME, + // Welcome message (null means generate dynamically based on terminal width): + 'welcome': null, // File path specifying where to save REPL command history: 'save': '', diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index 8bb1b56fec8b..35244f877d0d 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -74,6 +74,7 @@ var EagerEvaluator = require( './eager_evaluator.js' ); var ALIAS_OVERRIDES = require( './alias_overrides.js' ); var SETTINGS = require( './settings.js' ); var SETTINGS_VALIDATORS = require( './settings_validators.js' ); +var welcomeText = require( './welcome_text.js' ); // VARIABLES // @@ -329,7 +330,7 @@ function REPL( options ) { this._istream.on( 'keypress', onKeypress ); // Write a welcome message: - this._wstream.write( opts.welcome ); + this._wstream.write( opts.welcome || welcomeText( this._wstream.columns || 80 ) ); // TODO: check whether to synchronously initialize a REPL history file diff --git a/lib/node_modules/@stdlib/repl/lib/welcome_text.js b/lib/node_modules/@stdlib/repl/lib/welcome_text.js index 08e9aeda7e8b..f46c81fbfcc1 100644 --- a/lib/node_modules/@stdlib/repl/lib/welcome_text.js +++ b/lib/node_modules/@stdlib/repl/lib/welcome_text.js @@ -18,17 +18,26 @@ 'use strict'; -// MAIN // +// VARIABLES // + +var SIDE_BY_SIDE_MIN_WIDTH = 70; -var MSG = [ +var LOGO = [ ' _ _ _ _ _', - ' ___| |_ __| | (_) |__ | A better REPL for JavaScript and Node.js.', - '/ __| __/ _` | | | \'_ \\ |', - '\\__ \\ || (_| | | | |_) | | For more info, see the source repository:', - '|___/\\__\\__,_|_|_|_.__/ | https://github.com/stdlib-js/stdlib', + ' ___| |_ __| | (_) |__', + '/ __| __/ _` | | | \'_ \\', + '\\__ \\ || (_| | | | |_) |', + '|___/\\__\\__,_|_|_|_.__/' +]; + +var INFO_LINES = [ + 'A better REPL for JavaScript and Node.js.', '', + 'For more info, see the source repository:', + 'https://github.com/stdlib-js/stdlib' +]; - // TODO: include platform, copyright, version (see Julia, R, and Python for inspiration) +var HELP = [ '', ' help() Print help text.', ' help(alias) Print help text for a specified alias.', @@ -44,9 +53,66 @@ var MSG = [ ' copyright() Print copyright information.', '', '' -].join( '\n' ); +]; + + +// MAIN // + +/** +* Returns the welcome message formatted for the given terminal width. +* +* @private +* @param {PositiveInteger} columns - terminal width in columns +* @returns {string} formatted welcome message +*/ +function welcomeText( columns ) { + var lines; + var sep; + var pad; + var max; + var i; + + if ( columns >= SIDE_BY_SIDE_MIN_WIDTH ) { + // Side-by-side layout (original): + lines = [ + ' _ _ _ _ _', + ' ___| |_ __| | (_) |__ | A better REPL for JavaScript and Node.js.', + '/ __| __/ _` | | | \'_ \\ |', + '\\__ \\ || (_| | | | |_) | | For more info, see the source repository:', + '|___/\\__\\__,_|_|_|_.__/ | https://github.com/stdlib-js/stdlib' + ]; + } else { + // Stacked layout for narrow terminals: + lines = LOGO.slice(); + + // Find widest logo line for centering the separator: + max = 0; + for ( i = 0; i < LOGO.length; i++ ) { + if ( LOGO[ i ].length > max ) { + max = LOGO[ i ].length; + } + } + // Add a blank line and the info lines below the logo: + lines.push( '' ); + + // Add separator: + sep = ''; + for ( i = 0; i < max; i++ ) { + sep += '-'; + } + lines.push( sep ); + lines.push( '' ); + + // Add info with indentation: + pad = ' '; + for ( i = 0; i < INFO_LINES.length; i++ ) { + lines.push( pad + INFO_LINES[ i ] ); + } + } + return lines.concat( HELP ).join( '\n' ); +} // EXPORTS // -module.exports = MSG; +module.exports = welcomeText; From 59b7ce70855b37301f42d4d1f1dbec53e737ddfd Mon Sep 17 00:00:00 2001 From: 0PrashantYadav0 Date: Mon, 31 Aug 2026 18:45:07 +0530 Subject: [PATCH 2/3] fix: stack help commands in the REPL welcome message on narrow terminals --- type: pre_commit_static_analysis_report description: Results of running static analysis checks when committing changes. report: - task: lint_filenames status: passed - task: lint_editorconfig status: passed - task: lint_markdown_pkg_readmes status: na - task: lint_markdown_docs status: na - task: lint_markdown status: na - task: lint_package_json status: na - task: lint_repl_help status: na - task: lint_javascript_src status: passed - task: lint_javascript_cli status: na - task: lint_javascript_examples status: na - task: lint_javascript_tests status: na - task: lint_javascript_benchmarks status: na - task: lint_python status: na - task: lint_r status: na - task: lint_c_src status: na - task: lint_c_examples status: na - task: lint_c_benchmarks status: na - task: lint_c_tests_fixtures status: na - task: lint_shell status: na - task: lint_typescript_declarations status: passed - task: lint_typescript_tests status: na - task: lint_license_headers status: passed --- --- .../@stdlib/repl/lib/welcome_text.js | 226 ++++++++++++++---- 1 file changed, 177 insertions(+), 49 deletions(-) diff --git a/lib/node_modules/@stdlib/repl/lib/welcome_text.js b/lib/node_modules/@stdlib/repl/lib/welcome_text.js index f46c81fbfcc1..cd445ce6d80a 100644 --- a/lib/node_modules/@stdlib/repl/lib/welcome_text.js +++ b/lib/node_modules/@stdlib/repl/lib/welcome_text.js @@ -20,8 +20,27 @@ // VARIABLES // +// Minimum terminal width (in columns) for rendering the logo and info text side-by-side. Below this threshold, the welcome message switches to a stacked layout. NOTE: this value corresponds to the width of the widest side-by-side line; if the logo, info text, or command descriptions are modified, re-verify that this threshold still exceeds the widest rendered line. var SIDE_BY_SIDE_MIN_WIDTH = 70; +// Minimum number of spaces separating the command column from the description column in the side-by-side help layout: +var HELP_GAP = 4; + +// Indentation preceding each command in the help section: +var HELP_INDENT = ' '; + +// Indentation preceding each description in the stacked (narrow) help layout: +var HELP_DESC_INDENT = ' '; + +// Indentation preceding each line of info text in the stacked (narrow) layout: +var INFO_INDENT = ' '; + +// Gutter placed on each side of the vertical bar separating the logo from the info text in the side-by-side layout: +var LOGO_GUTTER = ' '; + +// Vertical bar separating the logo from the info text in the side-by-side layout: +var LOGO_BAR = '|'; + var LOGO = [ ' _ _ _ _ _', ' ___| |_ __| | (_) |__', @@ -30,6 +49,7 @@ var LOGO = [ '|___/\\__\\__,_|_|_|_.__/' ]; +// Info text rendered beside the logo. In the side-by-side layout, the first logo line has no counterpart, so these lines align to the logo lines beginning with the second (hence `LOGO.length` must equal `INFO_LINES.length+1`): var INFO_LINES = [ 'A better REPL for JavaScript and Node.js.', '', @@ -37,25 +57,107 @@ var INFO_LINES = [ 'https://github.com/stdlib-js/stdlib' ]; -var HELP = [ - '', - ' help() Print help text.', - ' help(alias) Print help text for a specified alias.', - ' help(alias.) Print help text for a specified property.', - '', - ' example(alias) Run examples for a specified alias.', - ' example(alias.) Run examples for a specified property.', - '', - ' reset() Reset the REPL.', - ' quit() Exit the REPL.', - '', - ' license() Print license information.', - ' copyright() Print copyright information.', - '', - '' +var COMMANDS = [ + { + 'cmd': 'help()', + 'desc': 'Print help text.' + }, + { + 'cmd': 'help(alias)', + 'desc': 'Print help text for a specified alias.' + }, + { + 'cmd': 'help(alias.)', + 'desc': 'Print help text for a specified property.' + }, + { + 'cmd': '', + 'desc': '' + }, + { + 'cmd': 'example(alias)', + 'desc': 'Run examples for a specified alias.' + }, + { + 'cmd': 'example(alias.)', + 'desc': 'Run examples for a specified property.' + }, + { + 'cmd': '', + 'desc': '' + }, + { + 'cmd': 'reset()', + 'desc': 'Reset the REPL.' + }, + { + 'cmd': 'quit()', + 'desc': 'Exit the REPL.' + }, + { + 'cmd': '', + 'desc': '' + }, + { + 'cmd': 'license()', + 'desc': 'Print license information.' + }, + { + 'cmd': 'copyright()', + 'desc': 'Print copyright information.' + } ]; +// FUNCTIONS // + +/** +* Returns a string consisting of a character repeated a specified number of times. +* +* @private +* @param {string} ch - character to repeat +* @param {NonNegativeInteger} n - number of repetitions +* @returns {string} repeated string +* +* @example +* var str = repeat( '-', 3 ); +* // returns '---' +*/ +function repeat( ch, n ) { + var out; + var i; + + out = ''; + for ( i = 0; i < n; i++ ) { + out += ch; + } + return out; +} + +/** +* Right-pads a string with spaces up to a minimum length. +* +* ## Notes +* +* - If the input string is already at least the desired length, the string is returned unchanged. +* +* @private +* @param {string} str - input string +* @param {NonNegativeInteger} len - minimum output length +* @returns {string} padded string +* +* @example +* var str = rightPad( 'abc', 5 ); +* // returns 'abc ' +*/ +function rightPad( str, len ) { + if ( str.length >= len ) { + return str; + } + return str + repeat( ' ', len-str.length ); +} + + // MAIN // /** @@ -66,50 +168,76 @@ var HELP = [ * @returns {string} formatted welcome message */ function welcomeText( columns ) { + var cmdWidth; + var isWide; + var logoW; var lines; - var sep; - var pad; - var max; + var line; + var text; var i; - if ( columns >= SIDE_BY_SIDE_MIN_WIDTH ) { - // Side-by-side layout (original): - lines = [ - ' _ _ _ _ _', - ' ___| |_ __| | (_) |__ | A better REPL for JavaScript and Node.js.', - '/ __| __/ _` | | | \'_ \\ |', - '\\__ \\ || (_| | | | |_) | | For more info, see the source repository:', - '|___/\\__\\__,_|_|_|_.__/ | https://github.com/stdlib-js/stdlib' - ]; - } else { - // Stacked layout for narrow terminals: - lines = LOGO.slice(); + isWide = ( columns >= SIDE_BY_SIDE_MIN_WIDTH ); - // Find widest logo line for centering the separator: - max = 0; - for ( i = 0; i < LOGO.length; i++ ) { - if ( LOGO[ i ].length > max ) { - max = LOGO[ i ].length; + // Resolve the width of the widest logo line (used to align the separator in both layouts): + logoW = 0; + for ( i = 0; i < LOGO.length; i++ ) { + if ( LOGO[ i ].length > logoW ) { + logoW = LOGO[ i ].length; + } + } + lines = []; + if ( isWide ) { + // Side-by-side layout: render the first logo line on its own, then pair each subsequent logo line with a line of info text separated by a vertical bar... + lines.push( LOGO[ 0 ] ); + for ( i = 1; i < LOGO.length; i++ ) { + line = rightPad( LOGO[ i ], logoW ) + LOGO_GUTTER + LOGO_BAR; + text = INFO_LINES[ i-1 ]; + if ( text ) { + line += LOGO_GUTTER + text; } + lines.push( line ); } - // Add a blank line and the info lines below the logo: - lines.push( '' ); - - // Add separator: - sep = ''; - for ( i = 0; i < max; i++ ) { - sep += '-'; + } else { + // Stacked layout for narrow terminals: render the logo, a separator, and then the info text on successive lines... + for ( i = 0; i < LOGO.length; i++ ) { + lines.push( LOGO[ i ] ); } - lines.push( sep ); lines.push( '' ); - - // Add info with indentation: - pad = ' '; + lines.push( repeat( '-', logoW ) ); + lines.push( '' ); for ( i = 0; i < INFO_LINES.length; i++ ) { - lines.push( pad + INFO_LINES[ i ] ); + lines.push( INFO_INDENT + INFO_LINES[ i ] ); } } - return lines.concat( HELP ).join( '\n' ); + + // Append the help text section: + lines.push( '' ); + + // In the side-by-side layout, resolve the command column width from the longest command so that descriptions remain aligned and separated by at least `HELP_GAP` spaces: + cmdWidth = 0; + if ( isWide ) { + for ( i = 0; i < COMMANDS.length; i++ ) { + if ( COMMANDS[ i ].cmd.length > cmdWidth ) { + cmdWidth = COMMANDS[ i ].cmd.length; + } + } + cmdWidth += HELP_GAP; + } + for ( i = 0; i < COMMANDS.length; i++ ) { + if ( COMMANDS[ i ].cmd === '' ) { + lines.push( '' ); + } else if ( isWide ) { + lines.push( HELP_INDENT + rightPad( COMMANDS[ i ].cmd, cmdWidth ) + COMMANDS[ i ].desc ); + } else { + // Stack the command and its description on separate lines: + lines.push( HELP_INDENT + COMMANDS[ i ].cmd ); + lines.push( HELP_DESC_INDENT + COMMANDS[ i ].desc ); + } + } + lines.push( '' ); + lines.push( '' ); + + return lines.join( '\n' ); } From b359d3368e6031a217d111dfa18176d7f66ec224 Mon Sep 17 00:00:00 2001 From: 0PrashantYadav0 Date: Mon, 31 Aug 2026 19:06:28 +0530 Subject: [PATCH 3/3] fix: handling null condition in welcome message --- type: pre_commit_static_analysis_report description: Results of running static analysis checks when committing changes. report: - task: lint_filenames status: passed - task: lint_editorconfig status: passed - task: lint_markdown_pkg_readmes status: na - task: lint_markdown_docs status: na - task: lint_markdown status: na - task: lint_package_json status: na - task: lint_repl_help status: na - task: lint_javascript_src status: passed - task: lint_javascript_cli status: na - task: lint_javascript_examples status: na - task: lint_javascript_tests status: na - task: lint_javascript_benchmarks status: na - task: lint_python status: na - task: lint_r status: na - task: lint_c_src status: na - task: lint_c_examples status: na - task: lint_c_benchmarks status: na - task: lint_c_tests_fixtures status: na - task: lint_shell status: na - task: lint_typescript_declarations status: passed - task: lint_typescript_tests status: na - task: lint_license_headers status: passed --- --- lib/node_modules/@stdlib/repl/lib/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node_modules/@stdlib/repl/lib/main.js b/lib/node_modules/@stdlib/repl/lib/main.js index 35244f877d0d..9739d1b941ff 100644 --- a/lib/node_modules/@stdlib/repl/lib/main.js +++ b/lib/node_modules/@stdlib/repl/lib/main.js @@ -330,7 +330,7 @@ function REPL( options ) { this._istream.on( 'keypress', onKeypress ); // Write a welcome message: - this._wstream.write( opts.welcome || welcomeText( this._wstream.columns || 80 ) ); + this._wstream.write( ( opts.welcome === null ) ? welcomeText( this._wstream.columns || 80 ) : opts.welcome ); // TODO: check whether to synchronously initialize a REPL history file