diff --git a/lib/internal/repl/utils.js b/lib/internal/repl/utils.js index 515e99f925c118..b38d751f0aa9f0 100644 --- a/lib/internal/repl/utils.js +++ b/lib/internal/repl/utils.js @@ -207,11 +207,6 @@ function setupPreview(repl, contextSymbol, bufferSymbol, active) { if (escaped === null && key.meta) { escaped = repl.line; } - } else if ((key.name === 'return' || key.name === 'enter') && - !key.meta && - escaped !== repl.line && - isCursorAtInputEnd()) { - repl._insertString(completionPreview); } } completionPreview = null; @@ -467,7 +462,7 @@ function setupPreview(repl, contextSymbol, bufferSymbol, active) { previewLine += completionPreview; } - getInputPreview(previewLine, inputPreviewCallback); + getInputPreview(repl.line, inputPreviewCallback); if (wrapped) { getInputPreview(previewLine, inputPreviewCallback); } diff --git a/test/parallel/test-repl-history-navigation.js b/test/parallel/test-repl-history-navigation.js index 77be0b0fc05e59..a4f5e8c7f3896e 100644 --- a/test/parallel/test-repl-history-navigation.js +++ b/test/parallel/test-repl-history-navigation.js @@ -1,7 +1,6 @@ 'use strict'; // Flags: --expose-internals - const common = require('../common'); const stream = require('stream'); const REPL = require('internal/repl'); @@ -244,16 +243,14 @@ const tests = [ // 230 + 2 + 4 + 14 '\x1B[1G', '\x1B[0J', `${prompt}${' '.repeat(230)} aut`, '\x1B[237G', - ' // ocompleteMe', '\x1B[237G', - '\n// 123', '\x1B[237G', - '\x1B[1A', '\x1B[1B', '\x1B[2K', '\x1B[1A', + ' // ocompleteMe', '\x1B[237G', ' // ocompleteMe', + '\x1B[237G', '\x1B[0K', // 2. UP '\x1B[1G', '\x1B[0J', `${prompt}${' '.repeat(229)} aut`, '\x1B[236G', - ' // ocompleteMe', '\x1B[236G', - '\n// 123', '\x1B[236G', - '\x1B[1A', '\x1B[1B', '\x1B[2K', '\x1B[1A', + ' // ocompleteMe', '\x1B[236G', ' // ocompleteMe', + '\x1B[236G', // Preview cleanup '\x1B[0K', // 3. UP @@ -337,13 +334,12 @@ const tests = [ BACKSPACE, LEFT, LEFT, - 'A', - BACKSPACE, GO_TO_END, BACKSPACE, WORD_LEFT, WORD_RIGHT, ESCAPE, + RIGHT, ENTER, UP, LEFT, @@ -362,15 +358,11 @@ const tests = [ '\x1B[1G', '\x1B[0J', prompt, '\x1B[3G', 'a', // 'u' 'u', ' // tocompleteMe', '\x1B[5G', - '\n// 123', '\x1B[5G', - '\x1B[1A', '\x1B[1B', '\x1B[2K', '\x1B[1A', - // 't' - Cleanup '\x1B[0K', + // 't' - Cleanup 't', ' // ocompleteMe', '\x1B[6G', - '\n// 123', '\x1B[6G', - '\x1B[1A', '\x1B[1B', '\x1B[2K', '\x1B[1A', - // 1. Right. Cleanup '\x1B[0K', + // 1. Right. Cleanup 'ocompleteMe', '\n// 123', '\x1B[17G', '\x1B[1A', '\x1B[1B', '\x1B[2K', '\x1B[1A', @@ -378,8 +370,7 @@ const tests = [ '\x1B[1G', '\x1B[0J', `${prompt}autocompleteM`, '\x1B[16G', // Autocomplete and refresh? ' // e', '\x1B[16G', - '\n// 123', '\x1B[16G', - '\x1B[1A', '\x1B[1B', '\x1B[2K', '\x1B[1A', + ' // e', '\x1B[16G', // 3. Left. Cleanup '\x1B[0K', '\x1B[1D', '\x1B[16G', ' // e', '\x1B[15G', @@ -388,15 +379,8 @@ const tests = [ '\x1B[1D', '\x1B[16G', ' // e', '\x1B[14G', // 5. 'A' - Cleanup '\x1B[16G', '\x1B[0K', '\x1B[14G', - // Refresh - '\x1B[1G', '\x1B[0J', `${prompt}autocompletAeM`, '\x1B[15G', - // 6. Backspace. Refresh - '\x1B[1G', '\x1B[0J', `${prompt}autocompleteM`, - '\x1B[14G', '\x1B[16G', ' // e', - '\x1B[14G', '\x1B[16G', ' // e', - '\x1B[14G', '\x1B[16G', + '\x1B[2C', // 7. Go to end. Cleanup - '\x1B[0K', '\x1B[14G', '\x1B[2C', 'e', '\n// 123', '\x1B[17G', '\x1B[1A', '\x1B[1B', '\x1B[2K', '\x1B[1A', @@ -404,44 +388,42 @@ const tests = [ '\x1B[1G', '\x1B[0J', `${prompt}autocompleteM`, '\x1B[16G', // Autocomplete ' // e', '\x1B[16G', - '\n// 123', '\x1B[16G', - '\x1B[1A', '\x1B[1B', '\x1B[2K', '\x1B[1A', + ' // e', '\x1B[16G', // 9. Word left. Cleanup '\x1B[0K', '\x1B[13D', '\x1B[16G', ' // e', '\x1B[3G', '\x1B[16G', // 10. Word right. Cleanup '\x1B[0K', '\x1B[3G', '\x1B[13C', ' // e', '\x1B[16G', - '\n// 123', '\x1B[16G', - '\x1B[1A', '\x1B[1B', '\x1B[2K', '\x1B[1A', // 11. ESCAPE '\x1B[0K', + 'e', + '\n// 123', '\x1B[17G', + '\x1B[1A', '\x1B[1B', '\x1B[2K', '\x1B[1A', // 12. ENTER '\r\n', - 'Uncaught ReferenceError: autocompleteM is not defined\n', + '123\n', '\x1B[1G', '\x1B[0J', // 13. UP prompt, '\x1B[3G', '\x1B[1G', '\x1B[0J', - `${prompt}autocompleteM`, '\x1B[16G', - ' // e', '\x1B[16G', - '\n// 123', '\x1B[16G', + `${prompt}autocompleteMe`, '\x1B[17G', + '\n// 123', '\x1B[17G', '\x1B[1A', '\x1B[1B', '\x1B[2K', '\x1B[1A', // 14. LEFT - '\x1B[0K', '\x1B[1D', '\x1B[16G', - ' // e', '\x1B[15G', '\x1B[16G', + '\x1B[1D', + '\n// 123', '\x1B[16G', + '\x1B[1A', '\x1B[1B', '\x1B[2K', '\x1B[1A', // 15. ENTER - '\x1B[0K', '\x1B[15G', '\x1B[1C', + '\x1B[1C', '\r\n', - 'Uncaught ReferenceError: autocompleteM is not defined\n', + '123\n', '\x1B[1G', '\x1B[0J', prompt, '\x1B[3G', // 16. UP '\x1B[1G', '\x1B[0J', - `${prompt}autocompleteM`, '\x1B[16G', - ' // e', '\x1B[16G', - '\n// 123', '\x1B[16G', + `${prompt}autocompleteMe`, '\x1B[17G', + '\n// 123', '\x1B[17G', '\x1B[1A', '\x1B[1B', '\x1B[2K', '\x1B[1A', - '\x1B[0K', // 17. ENTER - 'e', '\r\n', + '\r\n', '123\n', '\x1B[1G', '\x1B[0J', prompt, '\x1B[3G', @@ -586,9 +568,8 @@ const tests = [ expected: [ prompt, ...'const util = {}', 'undefined\n', - prompt, ...'ut', ...(prev ? [' // il', '\n// {}', - 'il', '\n// {}'] : ['il']), - '{}\n', + prompt, ...'ut', ...(prev ? [' // il', 'il', + '\n// {}', '{}\n'] : ['il']), prompt, ], clean: false diff --git a/test/parallel/test-repl-prevent-unwanted-autocompletion-on-enter.js b/test/parallel/test-repl-prevent-unwanted-autocompletion-on-enter.js new file mode 100644 index 00000000000000..6284408b95c403 --- /dev/null +++ b/test/parallel/test-repl-prevent-unwanted-autocompletion-on-enter.js @@ -0,0 +1,35 @@ +'use strict'; +require('../common'); +const repl = require('repl'); +const { describe, it } = require('node:test'); +const ArrayStream = require('../common/arraystream'); +const assert = require('assert'); +const outputStream = new ArrayStream(); +let accum = ''; +outputStream.write = (data) => accum += data.replace('\r', ''); + +function prepareREPL() { + const replServer = repl.start({ + prompt: '', + input: new ArrayStream(), + output: outputStream, + allowBlockingCompletions: true, + }); + + + return replServer; +} + + +describe('REPL Prevent unwanted autocompletion on pressing Enter', () => { + const code = [ + 'typeof Reflect.construct', + 'typeof Reflect.const', + ]; + + it(`should not autocomplete constructor`, async () => { + const { input } = prepareREPL(); + input.run(code); + assert.strictEqual(accum, '\'function\'\n\'undefined\'\n'); + }); +}); diff --git a/test/parallel/test-repl-preview.js b/test/parallel/test-repl-preview.js index 9ab84b5c9f3ae4..89e188a275e2be 100644 --- a/test/parallel/test-repl-preview.js +++ b/test/parallel/test-repl-preview.js @@ -25,6 +25,7 @@ class REPLStream extends Stream { for (const entry of data) { this.emit('data', entry); } + this.emit('data', '\t'); this.emit('data', '\n'); } write(chunk) { @@ -76,6 +77,7 @@ async function tests(options) { noPreview: '[Function: foo]', preview: [ 'foo', + '\x1B[90m[Function: foo]\x1B[39m\x1B[11G\x1B[1A\x1B[1B\x1B[2K\x1B[1A', '\x1B[90m[Function: foo]\x1B[39m\x1B[11G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r', '\x1B[36m[Function: foo]\x1B[39m', ] @@ -83,11 +85,8 @@ async function tests(options) { input: 'koo', noPreview: '[Function: koo]', preview: [ - 'k\x1B[90moo\x1B[39m\x1B[9G', - '\x1B[90m[Function: koo]\x1B[39m\x1B[9G\x1B[1A\x1B[1B\x1B[2K\x1B[1A' + - '\x1B[0Ko\x1B[90mo\x1B[39m\x1B[10G', - '\x1B[90m[Function: koo]\x1B[39m\x1B[10G\x1B[1A\x1B[1B\x1B[2K\x1B[1A' + - '\x1B[0Ko', + 'k\x1B[90moo\x1B[39m\x1B[9G\x1B[0Ko\x1B[90mo\x1B[39m\x1B[10G\x1B[0Ko', + '\x1B[90m[Function: koo]\x1B[39m\x1B[11G\x1B[1A\x1B[1B\x1B[2K\x1B[1A', '\x1B[90m[Function: koo]\x1B[39m\x1B[11G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r', '\x1B[36m[Function: koo]\x1B[39m', ] @@ -99,10 +98,12 @@ async function tests(options) { input: " { b: 1 }['b'] === 1", noPreview: '\x1B[33mtrue\x1B[39m', preview: [ - " { b: 1 }['b']", - '\x1B[90m1\x1B[39m\x1B[22G\x1B[1A\x1B[1B\x1B[2K\x1B[1A ', - '\x1B[90m1\x1B[39m\x1B[23G\x1B[1A\x1B[1B\x1B[2K\x1B[1A=== 1', - '\x1B[90mtrue\x1B[39m\x1B[28G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r', + ' { b: 1 }', + "\x1B[90m1\x1B[39m\x1B[17G\x1B[1A\x1B[1B\x1B[2K\x1B[1A['b']", + "\x1B[90m[ 'b' ]\x1B[39m\x1B[22G\x1B[1A\x1B[1B\x1B[2K\x1B[1A ", + "\x1B[90m[ 'b' ]\x1B[39m\x1B[23G\x1B[1A\x1B[1B\x1B[2K\x1B[1A=== 1", + '\x1B[90mfalse\x1B[39m\x1B[28G\x1B[1A\x1B[1B\x1B[2K\x1B[1A', + '\x1B[90mfalse\x1B[39m\x1B[28G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r', '\x1B[33mtrue\x1B[39m', ] }, { @@ -113,6 +114,7 @@ async function tests(options) { '\x1B[90m1\x1B[39m\x1B[21G\x1B[1A\x1B[1B\x1B[2K\x1B[1A ', '\x1B[90m1\x1B[39m\x1B[22G\x1B[1A\x1B[1B\x1B[2K\x1B[1A=== 1', '\x1B[90mtrue\x1B[39m\x1B[27G\x1B[1A\x1B[1B\x1B[2K\x1B[1A;', + '\x1B[90mfalse\x1B[39m\x1B[28G\x1B[1A\x1B[1B\x1B[2K\x1B[1A', '\x1B[90mfalse\x1B[39m\x1B[28G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r', '\x1B[33mfalse\x1B[39m', ] @@ -128,6 +130,7 @@ async function tests(options) { noPreview: '\x1B[33mtrue\x1B[39m', preview: [ '{ a: tru\x1B[90me\x1B[39m\x1B[16G\x1B[0Ke };', + '\x1B[90mtrue\x1B[39m\x1B[20G\x1B[1A\x1B[1B\x1B[2K\x1B[1A', '\x1B[90mtrue\x1B[39m\x1B[20G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r', '\x1B[33mtrue\x1B[39m', ] @@ -136,7 +139,8 @@ async function tests(options) { noPreview: '\x1B[33mtrue\x1B[39m', preview: [ ' { a: tru\x1B[90me\x1B[39m\x1B[18G\x1B[0Ke}', - '\x1B[90m{ a: true }\x1B[39m\x1B[20G\x1B[1A\x1B[1B\x1B[2K\x1B[1A;', + '\x1B[90mtrue\x1B[39m\x1B[20G\x1B[1A\x1B[1B\x1B[2K\x1B[1A;', + '\x1B[90mtrue\x1B[39m\x1B[21G\x1B[1A\x1B[1B\x1B[2K\x1B[1A', '\x1B[90mtrue\x1B[39m\x1B[21G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r', '\x1B[33mtrue\x1B[39m', ] @@ -146,6 +150,7 @@ async function tests(options) { preview: [ '1n + 2', '\x1B[90mType[39m\x1B[14G\x1B[1A\x1B[1B\x1B[2K\x1B[1An', + '\x1B[90m3n\x1B[39m\x1B[15G\x1B[1A\x1B[1B\x1B[2K\x1B[1A', '\x1B[90m3n\x1B[39m\x1B[15G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r', '\x1B[33m3n\x1B[39m', ] @@ -154,6 +159,7 @@ async function tests(options) { noPreview: '\x1B[33m1\x1B[39m', preview: [ '{};1', + '\x1B[90m1\x1B[39m\x1B[12G\x1B[1A\x1B[1B\x1B[2K\x1B[1A', '\x1B[90m1\x1B[39m\x1B[12G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r', '\x1B[33m1\x1B[39m', ] @@ -196,6 +202,7 @@ async function tests(options) { noPreview: "{ \x1B[32m'{'\x1B[39m: \x1B[33m0\x1B[39m }", preview: [ "{'{':0}", + "\x1B[90m{ '{': 0 }\x1B[39m\x1B[15G\x1B[1A\x1B[1B\x1B[2K\x1B[1A", "\x1B[90m{ '{': 0 }\x1B[39m\x1B[15G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r", "{ \x1B[32m'{'\x1B[39m: \x1B[33m0\x1B[39m }", ], @@ -211,6 +218,7 @@ async function tests(options) { noPreview: '{}', preview: [ '{},{}', + '\x1B[90m{}\x1B[39m\x1B[13G\x1B[1A\x1B[1B\x1B[2K\x1B[1A', '\x1B[90m{}\x1B[39m\x1B[13G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r', '{}', ], @@ -231,6 +239,7 @@ async function tests(options) { noPreview: 'Uncaught \x1B[33m0\x1B[39m', preview: [ '{throw 0}', + '\x1B[90m0\x1B[39m\x1B[17G\x1B[1A\x1B[1B\x1B[2K\x1B[1A', '\x1B[90m0\x1B[39m\x1B[17G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r', 'Uncaught \x1B[33m0\x1B[39m', ],