11cb0ef41Sopenharmony_ci// Flags: --expose-internals 21cb0ef41Sopenharmony_ci'use strict'; 31cb0ef41Sopenharmony_ciconst common = require('../common'); 41cb0ef41Sopenharmony_cicommon.skipIfDumbTerminal(); 51cb0ef41Sopenharmony_ci 61cb0ef41Sopenharmony_ciconst assert = require('assert'); 71cb0ef41Sopenharmony_ciconst readline = require('readline/promises'); 81cb0ef41Sopenharmony_ciconst { 91cb0ef41Sopenharmony_ci getStringWidth, 101cb0ef41Sopenharmony_ci stripVTControlCharacters 111cb0ef41Sopenharmony_ci} = require('internal/util/inspect'); 121cb0ef41Sopenharmony_ciconst EventEmitter = require('events').EventEmitter; 131cb0ef41Sopenharmony_ciconst { Writable, Readable } = require('stream'); 141cb0ef41Sopenharmony_ci 151cb0ef41Sopenharmony_ciclass FakeInput extends EventEmitter { 161cb0ef41Sopenharmony_ci resume() {} 171cb0ef41Sopenharmony_ci pause() {} 181cb0ef41Sopenharmony_ci write() {} 191cb0ef41Sopenharmony_ci end() {} 201cb0ef41Sopenharmony_ci} 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_cifunction isWarned(emitter) { 231cb0ef41Sopenharmony_ci for (const name in emitter) { 241cb0ef41Sopenharmony_ci const listeners = emitter[name]; 251cb0ef41Sopenharmony_ci if (listeners.warned) return true; 261cb0ef41Sopenharmony_ci } 271cb0ef41Sopenharmony_ci return false; 281cb0ef41Sopenharmony_ci} 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_cifunction getInterface(options) { 311cb0ef41Sopenharmony_ci const fi = new FakeInput(); 321cb0ef41Sopenharmony_ci const rli = new readline.Interface({ 331cb0ef41Sopenharmony_ci input: fi, 341cb0ef41Sopenharmony_ci output: fi, 351cb0ef41Sopenharmony_ci ...options, 361cb0ef41Sopenharmony_ci }); 371cb0ef41Sopenharmony_ci return [rli, fi]; 381cb0ef41Sopenharmony_ci} 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_cifunction assertCursorRowsAndCols(rli, rows, cols) { 411cb0ef41Sopenharmony_ci const cursorPos = rli.getCursorPos(); 421cb0ef41Sopenharmony_ci assert.strictEqual(cursorPos.rows, rows); 431cb0ef41Sopenharmony_ci assert.strictEqual(cursorPos.cols, cols); 441cb0ef41Sopenharmony_ci} 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ci[ 471cb0ef41Sopenharmony_ci undefined, 481cb0ef41Sopenharmony_ci 50, 491cb0ef41Sopenharmony_ci 0, 501cb0ef41Sopenharmony_ci 100.5, 511cb0ef41Sopenharmony_ci 5000, 521cb0ef41Sopenharmony_ci].forEach((crlfDelay) => { 531cb0ef41Sopenharmony_ci const [rli] = getInterface({ crlfDelay }); 541cb0ef41Sopenharmony_ci assert.strictEqual(rli.crlfDelay, Math.max(crlfDelay || 100, 100)); 551cb0ef41Sopenharmony_ci rli.close(); 561cb0ef41Sopenharmony_ci}); 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ci{ 591cb0ef41Sopenharmony_ci const input = new FakeInput(); 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_ci // Constructor throws if completer is not a function or undefined 621cb0ef41Sopenharmony_ci assert.throws(() => { 631cb0ef41Sopenharmony_ci readline.createInterface({ 641cb0ef41Sopenharmony_ci input, 651cb0ef41Sopenharmony_ci completer: 'string is not valid' 661cb0ef41Sopenharmony_ci }); 671cb0ef41Sopenharmony_ci }, { 681cb0ef41Sopenharmony_ci name: 'TypeError', 691cb0ef41Sopenharmony_ci code: 'ERR_INVALID_ARG_VALUE' 701cb0ef41Sopenharmony_ci }); 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ci assert.throws(() => { 731cb0ef41Sopenharmony_ci readline.createInterface({ 741cb0ef41Sopenharmony_ci input, 751cb0ef41Sopenharmony_ci completer: '' 761cb0ef41Sopenharmony_ci }); 771cb0ef41Sopenharmony_ci }, { 781cb0ef41Sopenharmony_ci name: 'TypeError', 791cb0ef41Sopenharmony_ci code: 'ERR_INVALID_ARG_VALUE' 801cb0ef41Sopenharmony_ci }); 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_ci assert.throws(() => { 831cb0ef41Sopenharmony_ci readline.createInterface({ 841cb0ef41Sopenharmony_ci input, 851cb0ef41Sopenharmony_ci completer: false 861cb0ef41Sopenharmony_ci }); 871cb0ef41Sopenharmony_ci }, { 881cb0ef41Sopenharmony_ci name: 'TypeError', 891cb0ef41Sopenharmony_ci code: 'ERR_INVALID_ARG_VALUE' 901cb0ef41Sopenharmony_ci }); 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ci // Constructor throws if history is not an array 931cb0ef41Sopenharmony_ci ['not an array', 123, 123n, {}, true, Symbol(), null].forEach((history) => { 941cb0ef41Sopenharmony_ci assert.throws(() => { 951cb0ef41Sopenharmony_ci readline.createInterface({ 961cb0ef41Sopenharmony_ci input, 971cb0ef41Sopenharmony_ci history, 981cb0ef41Sopenharmony_ci }); 991cb0ef41Sopenharmony_ci }, { 1001cb0ef41Sopenharmony_ci name: 'TypeError', 1011cb0ef41Sopenharmony_ci code: 'ERR_INVALID_ARG_TYPE' 1021cb0ef41Sopenharmony_ci }); 1031cb0ef41Sopenharmony_ci }); 1041cb0ef41Sopenharmony_ci 1051cb0ef41Sopenharmony_ci // Constructor throws if historySize is not a positive number 1061cb0ef41Sopenharmony_ci ['not a number', -1, NaN, {}, true, Symbol(), null].forEach((historySize) => { 1071cb0ef41Sopenharmony_ci assert.throws(() => { 1081cb0ef41Sopenharmony_ci readline.createInterface({ 1091cb0ef41Sopenharmony_ci input, 1101cb0ef41Sopenharmony_ci historySize, 1111cb0ef41Sopenharmony_ci }); 1121cb0ef41Sopenharmony_ci }, { 1131cb0ef41Sopenharmony_ci name: 'RangeError', 1141cb0ef41Sopenharmony_ci code: 'ERR_INVALID_ARG_VALUE' 1151cb0ef41Sopenharmony_ci }); 1161cb0ef41Sopenharmony_ci }); 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_ci // Check for invalid tab sizes. 1191cb0ef41Sopenharmony_ci assert.throws( 1201cb0ef41Sopenharmony_ci () => new readline.Interface({ 1211cb0ef41Sopenharmony_ci input, 1221cb0ef41Sopenharmony_ci tabSize: 0 1231cb0ef41Sopenharmony_ci }), 1241cb0ef41Sopenharmony_ci { code: 'ERR_OUT_OF_RANGE' } 1251cb0ef41Sopenharmony_ci ); 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_ci assert.throws( 1281cb0ef41Sopenharmony_ci () => new readline.Interface({ 1291cb0ef41Sopenharmony_ci input, 1301cb0ef41Sopenharmony_ci tabSize: '4' 1311cb0ef41Sopenharmony_ci }), 1321cb0ef41Sopenharmony_ci { code: 'ERR_INVALID_ARG_TYPE' } 1331cb0ef41Sopenharmony_ci ); 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_ci assert.throws( 1361cb0ef41Sopenharmony_ci () => new readline.Interface({ 1371cb0ef41Sopenharmony_ci input, 1381cb0ef41Sopenharmony_ci tabSize: 4.5 1391cb0ef41Sopenharmony_ci }), 1401cb0ef41Sopenharmony_ci { 1411cb0ef41Sopenharmony_ci code: 'ERR_OUT_OF_RANGE', 1421cb0ef41Sopenharmony_ci message: 'The value of "tabSize" is out of range. ' + 1431cb0ef41Sopenharmony_ci 'It must be an integer. Received 4.5' 1441cb0ef41Sopenharmony_ci } 1451cb0ef41Sopenharmony_ci ); 1461cb0ef41Sopenharmony_ci} 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_ci// Sending a single character with no newline 1491cb0ef41Sopenharmony_ci{ 1501cb0ef41Sopenharmony_ci const fi = new FakeInput(); 1511cb0ef41Sopenharmony_ci const rli = new readline.Interface(fi, {}); 1521cb0ef41Sopenharmony_ci rli.on('line', common.mustNotCall()); 1531cb0ef41Sopenharmony_ci fi.emit('data', 'a'); 1541cb0ef41Sopenharmony_ci rli.close(); 1551cb0ef41Sopenharmony_ci} 1561cb0ef41Sopenharmony_ci 1571cb0ef41Sopenharmony_ci// Sending multiple newlines at once that does not end with a new line and a 1581cb0ef41Sopenharmony_ci// `end` event(last line is). \r should behave like \n when alone. 1591cb0ef41Sopenharmony_ci{ 1601cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true }); 1611cb0ef41Sopenharmony_ci const expectedLines = ['foo', 'bar', 'baz', 'bat']; 1621cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 1631cb0ef41Sopenharmony_ci assert.strictEqual(line, expectedLines.shift()); 1641cb0ef41Sopenharmony_ci }, expectedLines.length - 1)); 1651cb0ef41Sopenharmony_ci fi.emit('data', expectedLines.join('\r')); 1661cb0ef41Sopenharmony_ci rli.close(); 1671cb0ef41Sopenharmony_ci} 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_ci// \r at start of input should output blank line 1701cb0ef41Sopenharmony_ci{ 1711cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true }); 1721cb0ef41Sopenharmony_ci const expectedLines = ['', 'foo' ]; 1731cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 1741cb0ef41Sopenharmony_ci assert.strictEqual(line, expectedLines.shift()); 1751cb0ef41Sopenharmony_ci }, expectedLines.length)); 1761cb0ef41Sopenharmony_ci fi.emit('data', '\rfoo\r'); 1771cb0ef41Sopenharmony_ci rli.close(); 1781cb0ef41Sopenharmony_ci} 1791cb0ef41Sopenharmony_ci 1801cb0ef41Sopenharmony_ci// \t does not become part of the input when there is a completer function 1811cb0ef41Sopenharmony_ci{ 1821cb0ef41Sopenharmony_ci const completer = (line) => [[], line]; 1831cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, completer }); 1841cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 1851cb0ef41Sopenharmony_ci assert.strictEqual(line, 'foo'); 1861cb0ef41Sopenharmony_ci })); 1871cb0ef41Sopenharmony_ci for (const character of '\tfo\to\t') { 1881cb0ef41Sopenharmony_ci fi.emit('data', character); 1891cb0ef41Sopenharmony_ci } 1901cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 1911cb0ef41Sopenharmony_ci rli.close(); 1921cb0ef41Sopenharmony_ci} 1931cb0ef41Sopenharmony_ci 1941cb0ef41Sopenharmony_ci// \t when there is no completer function should behave like an ordinary 1951cb0ef41Sopenharmony_ci// character 1961cb0ef41Sopenharmony_ci{ 1971cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true }); 1981cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 1991cb0ef41Sopenharmony_ci assert.strictEqual(line, '\t'); 2001cb0ef41Sopenharmony_ci })); 2011cb0ef41Sopenharmony_ci fi.emit('data', '\t'); 2021cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 2031cb0ef41Sopenharmony_ci rli.close(); 2041cb0ef41Sopenharmony_ci} 2051cb0ef41Sopenharmony_ci 2061cb0ef41Sopenharmony_ci// Adding history lines should emit the history event with 2071cb0ef41Sopenharmony_ci// the history array 2081cb0ef41Sopenharmony_ci{ 2091cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true }); 2101cb0ef41Sopenharmony_ci const expectedLines = ['foo', 'bar', 'baz', 'bat']; 2111cb0ef41Sopenharmony_ci rli.on('history', common.mustCall((history) => { 2121cb0ef41Sopenharmony_ci const expectedHistory = expectedLines.slice(0, history.length).reverse(); 2131cb0ef41Sopenharmony_ci assert.deepStrictEqual(history, expectedHistory); 2141cb0ef41Sopenharmony_ci }, expectedLines.length)); 2151cb0ef41Sopenharmony_ci for (const line of expectedLines) { 2161cb0ef41Sopenharmony_ci fi.emit('data', `${line}\n`); 2171cb0ef41Sopenharmony_ci } 2181cb0ef41Sopenharmony_ci rli.close(); 2191cb0ef41Sopenharmony_ci} 2201cb0ef41Sopenharmony_ci 2211cb0ef41Sopenharmony_ci// Altering the history array in the listener should not alter 2221cb0ef41Sopenharmony_ci// the line being processed 2231cb0ef41Sopenharmony_ci{ 2241cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true }); 2251cb0ef41Sopenharmony_ci const expectedLine = 'foo'; 2261cb0ef41Sopenharmony_ci rli.on('history', common.mustCall((history) => { 2271cb0ef41Sopenharmony_ci assert.strictEqual(history[0], expectedLine); 2281cb0ef41Sopenharmony_ci history.shift(); 2291cb0ef41Sopenharmony_ci })); 2301cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 2311cb0ef41Sopenharmony_ci assert.strictEqual(line, expectedLine); 2321cb0ef41Sopenharmony_ci assert.strictEqual(rli.history.length, 0); 2331cb0ef41Sopenharmony_ci })); 2341cb0ef41Sopenharmony_ci fi.emit('data', `${expectedLine}\n`); 2351cb0ef41Sopenharmony_ci rli.close(); 2361cb0ef41Sopenharmony_ci} 2371cb0ef41Sopenharmony_ci 2381cb0ef41Sopenharmony_ci// Duplicate lines are removed from history when 2391cb0ef41Sopenharmony_ci// `options.removeHistoryDuplicates` is `true` 2401cb0ef41Sopenharmony_ci{ 2411cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ 2421cb0ef41Sopenharmony_ci terminal: true, 2431cb0ef41Sopenharmony_ci removeHistoryDuplicates: true 2441cb0ef41Sopenharmony_ci }); 2451cb0ef41Sopenharmony_ci const expectedLines = ['foo', 'bar', 'baz', 'bar', 'bat', 'bat']; 2461cb0ef41Sopenharmony_ci // ['foo', 'baz', 'bar', bat']; 2471cb0ef41Sopenharmony_ci let callCount = 0; 2481cb0ef41Sopenharmony_ci rli.on('line', function(line) { 2491cb0ef41Sopenharmony_ci assert.strictEqual(line, expectedLines[callCount]); 2501cb0ef41Sopenharmony_ci callCount++; 2511cb0ef41Sopenharmony_ci }); 2521cb0ef41Sopenharmony_ci fi.emit('data', `${expectedLines.join('\n')}\n`); 2531cb0ef41Sopenharmony_ci assert.strictEqual(callCount, expectedLines.length); 2541cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'bat' 2551cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, expectedLines[--callCount]); 2561cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'bar' 2571cb0ef41Sopenharmony_ci assert.notStrictEqual(rli.line, expectedLines[--callCount]); 2581cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, expectedLines[--callCount]); 2591cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'baz' 2601cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, expectedLines[--callCount]); 2611cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'foo' 2621cb0ef41Sopenharmony_ci assert.notStrictEqual(rli.line, expectedLines[--callCount]); 2631cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, expectedLines[--callCount]); 2641cb0ef41Sopenharmony_ci assert.strictEqual(callCount, 0); 2651cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'down' }); // 'baz' 2661cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'baz'); 2671cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, 2); 2681cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'n', ctrl: true }); // 'bar' 2691cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'bar'); 2701cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, 1); 2711cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'n', ctrl: true }); 2721cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'bat'); 2731cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, 0); 2741cb0ef41Sopenharmony_ci // Activate the substring history search. 2751cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'down' }); // 'bat' 2761cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'bat'); 2771cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, -1); 2781cb0ef41Sopenharmony_ci // Deactivate substring history search. 2791cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'backspace' }); // 'ba' 2801cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, -1); 2811cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'ba'); 2821cb0ef41Sopenharmony_ci // Activate the substring history search. 2831cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'down' }); // 'ba' 2841cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, -1); 2851cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'ba'); 2861cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'down' }); // 'ba' 2871cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, -1); 2881cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'ba'); 2891cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'bat' 2901cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, 0); 2911cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'bat'); 2921cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'bar' 2931cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, 1); 2941cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'bar'); 2951cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'baz' 2961cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, 2); 2971cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'baz'); 2981cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'ba' 2991cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, 4); 3001cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'ba'); 3011cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'ba' 3021cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, 4); 3031cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'ba'); 3041cb0ef41Sopenharmony_ci // Deactivate substring history search and reset history index. 3051cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'right' }); // 'ba' 3061cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, -1); 3071cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'ba'); 3081cb0ef41Sopenharmony_ci // Substring history search activated. 3091cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'ba' 3101cb0ef41Sopenharmony_ci assert.strictEqual(rli.historyIndex, 0); 3111cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, 'bat'); 3121cb0ef41Sopenharmony_ci rli.close(); 3131cb0ef41Sopenharmony_ci} 3141cb0ef41Sopenharmony_ci 3151cb0ef41Sopenharmony_ci// Duplicate lines are not removed from history when 3161cb0ef41Sopenharmony_ci// `options.removeHistoryDuplicates` is `false` 3171cb0ef41Sopenharmony_ci{ 3181cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ 3191cb0ef41Sopenharmony_ci terminal: true, 3201cb0ef41Sopenharmony_ci removeHistoryDuplicates: false 3211cb0ef41Sopenharmony_ci }); 3221cb0ef41Sopenharmony_ci const expectedLines = ['foo', 'bar', 'baz', 'bar', 'bat', 'bat']; 3231cb0ef41Sopenharmony_ci let callCount = 0; 3241cb0ef41Sopenharmony_ci rli.on('line', function(line) { 3251cb0ef41Sopenharmony_ci assert.strictEqual(line, expectedLines[callCount]); 3261cb0ef41Sopenharmony_ci callCount++; 3271cb0ef41Sopenharmony_ci }); 3281cb0ef41Sopenharmony_ci fi.emit('data', `${expectedLines.join('\n')}\n`); 3291cb0ef41Sopenharmony_ci assert.strictEqual(callCount, expectedLines.length); 3301cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'bat' 3311cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, expectedLines[--callCount]); 3321cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'bar' 3331cb0ef41Sopenharmony_ci assert.notStrictEqual(rli.line, expectedLines[--callCount]); 3341cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, expectedLines[--callCount]); 3351cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'baz' 3361cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, expectedLines[--callCount]); 3371cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'bar' 3381cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, expectedLines[--callCount]); 3391cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'up' }); // 'foo' 3401cb0ef41Sopenharmony_ci assert.strictEqual(rli.line, expectedLines[--callCount]); 3411cb0ef41Sopenharmony_ci assert.strictEqual(callCount, 0); 3421cb0ef41Sopenharmony_ci rli.close(); 3431cb0ef41Sopenharmony_ci} 3441cb0ef41Sopenharmony_ci 3451cb0ef41Sopenharmony_ci// Regression test for repl freeze, #1968: 3461cb0ef41Sopenharmony_ci// check that nothing fails if 'keypress' event throws. 3471cb0ef41Sopenharmony_ci{ 3481cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true }); 3491cb0ef41Sopenharmony_ci const keys = []; 3501cb0ef41Sopenharmony_ci const err = new Error('bad thing happened'); 3511cb0ef41Sopenharmony_ci fi.on('keypress', function(key) { 3521cb0ef41Sopenharmony_ci keys.push(key); 3531cb0ef41Sopenharmony_ci if (key === 'X') { 3541cb0ef41Sopenharmony_ci throw err; 3551cb0ef41Sopenharmony_ci } 3561cb0ef41Sopenharmony_ci }); 3571cb0ef41Sopenharmony_ci assert.throws( 3581cb0ef41Sopenharmony_ci () => fi.emit('data', 'fooX'), 3591cb0ef41Sopenharmony_ci (e) => { 3601cb0ef41Sopenharmony_ci assert.strictEqual(e, err); 3611cb0ef41Sopenharmony_ci return true; 3621cb0ef41Sopenharmony_ci } 3631cb0ef41Sopenharmony_ci ); 3641cb0ef41Sopenharmony_ci fi.emit('data', 'bar'); 3651cb0ef41Sopenharmony_ci assert.strictEqual(keys.join(''), 'fooXbar'); 3661cb0ef41Sopenharmony_ci rli.close(); 3671cb0ef41Sopenharmony_ci} 3681cb0ef41Sopenharmony_ci 3691cb0ef41Sopenharmony_ci// History is bound 3701cb0ef41Sopenharmony_ci{ 3711cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, historySize: 2 }); 3721cb0ef41Sopenharmony_ci const lines = ['line 1', 'line 2', 'line 3']; 3731cb0ef41Sopenharmony_ci fi.emit('data', lines.join('\n') + '\n'); 3741cb0ef41Sopenharmony_ci assert.strictEqual(rli.history.length, 2); 3751cb0ef41Sopenharmony_ci assert.strictEqual(rli.history[0], 'line 3'); 3761cb0ef41Sopenharmony_ci assert.strictEqual(rli.history[1], 'line 2'); 3771cb0ef41Sopenharmony_ci} 3781cb0ef41Sopenharmony_ci 3791cb0ef41Sopenharmony_ci// Question 3801cb0ef41Sopenharmony_ci{ 3811cb0ef41Sopenharmony_ci const [rli] = getInterface({ terminal: true }); 3821cb0ef41Sopenharmony_ci const expectedLines = ['foo']; 3831cb0ef41Sopenharmony_ci rli.question(expectedLines[0]).then(() => rli.close()); 3841cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, expectedLines[0].length); 3851cb0ef41Sopenharmony_ci rli.close(); 3861cb0ef41Sopenharmony_ci} 3871cb0ef41Sopenharmony_ci 3881cb0ef41Sopenharmony_ci// Sending a multi-line question 3891cb0ef41Sopenharmony_ci{ 3901cb0ef41Sopenharmony_ci const [rli] = getInterface({ terminal: true }); 3911cb0ef41Sopenharmony_ci const expectedLines = ['foo', 'bar']; 3921cb0ef41Sopenharmony_ci rli.question(expectedLines.join('\n')).then(() => rli.close()); 3931cb0ef41Sopenharmony_ci assertCursorRowsAndCols( 3941cb0ef41Sopenharmony_ci rli, expectedLines.length - 1, expectedLines.slice(-1)[0].length); 3951cb0ef41Sopenharmony_ci rli.close(); 3961cb0ef41Sopenharmony_ci} 3971cb0ef41Sopenharmony_ci 3981cb0ef41Sopenharmony_ci{ 3991cb0ef41Sopenharmony_ci // Beginning and end of line 4001cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 4011cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 4021cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'a' }); 4031cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 4041cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'e' }); 4051cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 19); 4061cb0ef41Sopenharmony_ci rli.close(); 4071cb0ef41Sopenharmony_ci} 4081cb0ef41Sopenharmony_ci 4091cb0ef41Sopenharmony_ci{ 4101cb0ef41Sopenharmony_ci // Back and Forward one character 4111cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 4121cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 4131cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 19); 4141cb0ef41Sopenharmony_ci 4151cb0ef41Sopenharmony_ci // Back one character 4161cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'b' }); 4171cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 18); 4181cb0ef41Sopenharmony_ci // Back one character 4191cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'b' }); 4201cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 17); 4211cb0ef41Sopenharmony_ci // Forward one character 4221cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'f' }); 4231cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 18); 4241cb0ef41Sopenharmony_ci // Forward one character 4251cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'f' }); 4261cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 19); 4271cb0ef41Sopenharmony_ci rli.close(); 4281cb0ef41Sopenharmony_ci} 4291cb0ef41Sopenharmony_ci 4301cb0ef41Sopenharmony_ci// Back and Forward one astral character 4311cb0ef41Sopenharmony_ci{ 4321cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 4331cb0ef41Sopenharmony_ci fi.emit('data', ''); 4341cb0ef41Sopenharmony_ci 4351cb0ef41Sopenharmony_ci // Move left one character/code point 4361cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'left' }); 4371cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 4381cb0ef41Sopenharmony_ci 4391cb0ef41Sopenharmony_ci // Move right one character/code point 4401cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'right' }); 4411cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 2); 4421cb0ef41Sopenharmony_ci 4431cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 4441cb0ef41Sopenharmony_ci assert.strictEqual(line, ''); 4451cb0ef41Sopenharmony_ci })); 4461cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 4471cb0ef41Sopenharmony_ci rli.close(); 4481cb0ef41Sopenharmony_ci} 4491cb0ef41Sopenharmony_ci 4501cb0ef41Sopenharmony_ci// Two astral characters left 4511cb0ef41Sopenharmony_ci{ 4521cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 4531cb0ef41Sopenharmony_ci fi.emit('data', ''); 4541cb0ef41Sopenharmony_ci 4551cb0ef41Sopenharmony_ci // Move left one character/code point 4561cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'left' }); 4571cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 4581cb0ef41Sopenharmony_ci 4591cb0ef41Sopenharmony_ci fi.emit('data', ''); 4601cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 2); 4611cb0ef41Sopenharmony_ci 4621cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 4631cb0ef41Sopenharmony_ci assert.strictEqual(line, ''); 4641cb0ef41Sopenharmony_ci })); 4651cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 4661cb0ef41Sopenharmony_ci rli.close(); 4671cb0ef41Sopenharmony_ci} 4681cb0ef41Sopenharmony_ci 4691cb0ef41Sopenharmony_ci// Two astral characters right 4701cb0ef41Sopenharmony_ci{ 4711cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 4721cb0ef41Sopenharmony_ci fi.emit('data', ''); 4731cb0ef41Sopenharmony_ci 4741cb0ef41Sopenharmony_ci // Move left one character/code point 4751cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { name: 'right' }); 4761cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 2); 4771cb0ef41Sopenharmony_ci 4781cb0ef41Sopenharmony_ci fi.emit('data', ''); 4791cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 4); 4801cb0ef41Sopenharmony_ci 4811cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 4821cb0ef41Sopenharmony_ci assert.strictEqual(line, ''); 4831cb0ef41Sopenharmony_ci })); 4841cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 4851cb0ef41Sopenharmony_ci rli.close(); 4861cb0ef41Sopenharmony_ci} 4871cb0ef41Sopenharmony_ci 4881cb0ef41Sopenharmony_ci{ 4891cb0ef41Sopenharmony_ci // `wordLeft` and `wordRight` 4901cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 4911cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 4921cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'left' }); 4931cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 16); 4941cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { meta: true, name: 'b' }); 4951cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 10); 4961cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'right' }); 4971cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 16); 4981cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { meta: true, name: 'f' }); 4991cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 19); 5001cb0ef41Sopenharmony_ci rli.close(); 5011cb0ef41Sopenharmony_ci} 5021cb0ef41Sopenharmony_ci 5031cb0ef41Sopenharmony_ci// `deleteWordLeft` 5041cb0ef41Sopenharmony_ci[ 5051cb0ef41Sopenharmony_ci { ctrl: true, name: 'w' }, 5061cb0ef41Sopenharmony_ci { ctrl: true, name: 'backspace' }, 5071cb0ef41Sopenharmony_ci { meta: true, name: 'backspace' }, 5081cb0ef41Sopenharmony_ci].forEach((deleteWordLeftKey) => { 5091cb0ef41Sopenharmony_ci let [rli, fi] = getInterface({ terminal: true, prompt: '' }); 5101cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 5111cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'left' }); 5121cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 5131cb0ef41Sopenharmony_ci assert.strictEqual(line, 'the quick fox'); 5141cb0ef41Sopenharmony_ci })); 5151cb0ef41Sopenharmony_ci fi.emit('keypress', '.', deleteWordLeftKey); 5161cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 5171cb0ef41Sopenharmony_ci rli.close(); 5181cb0ef41Sopenharmony_ci 5191cb0ef41Sopenharmony_ci // No effect if pressed at beginning of line 5201cb0ef41Sopenharmony_ci [rli, fi] = getInterface({ terminal: true, prompt: '' }); 5211cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 5221cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'a' }); 5231cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 5241cb0ef41Sopenharmony_ci assert.strictEqual(line, 'the quick brown fox'); 5251cb0ef41Sopenharmony_ci })); 5261cb0ef41Sopenharmony_ci fi.emit('keypress', '.', deleteWordLeftKey); 5271cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 5281cb0ef41Sopenharmony_ci rli.close(); 5291cb0ef41Sopenharmony_ci}); 5301cb0ef41Sopenharmony_ci 5311cb0ef41Sopenharmony_ci// `deleteWordRight` 5321cb0ef41Sopenharmony_ci[ 5331cb0ef41Sopenharmony_ci { ctrl: true, name: 'delete' }, 5341cb0ef41Sopenharmony_ci { meta: true, name: 'delete' }, 5351cb0ef41Sopenharmony_ci { meta: true, name: 'd' }, 5361cb0ef41Sopenharmony_ci].forEach((deleteWordRightKey) => { 5371cb0ef41Sopenharmony_ci let [rli, fi] = getInterface({ terminal: true, prompt: '' }); 5381cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 5391cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'left' }); 5401cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'left' }); 5411cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 5421cb0ef41Sopenharmony_ci assert.strictEqual(line, 'the quick fox'); 5431cb0ef41Sopenharmony_ci })); 5441cb0ef41Sopenharmony_ci fi.emit('keypress', '.', deleteWordRightKey); 5451cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 5461cb0ef41Sopenharmony_ci rli.close(); 5471cb0ef41Sopenharmony_ci 5481cb0ef41Sopenharmony_ci // No effect if pressed at end of line 5491cb0ef41Sopenharmony_ci [rli, fi] = getInterface({ terminal: true, prompt: '' }); 5501cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 5511cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 5521cb0ef41Sopenharmony_ci assert.strictEqual(line, 'the quick brown fox'); 5531cb0ef41Sopenharmony_ci })); 5541cb0ef41Sopenharmony_ci fi.emit('keypress', '.', deleteWordRightKey); 5551cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 5561cb0ef41Sopenharmony_ci rli.close(); 5571cb0ef41Sopenharmony_ci}); 5581cb0ef41Sopenharmony_ci 5591cb0ef41Sopenharmony_ci// deleteLeft 5601cb0ef41Sopenharmony_ci{ 5611cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 5621cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 5631cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 19); 5641cb0ef41Sopenharmony_ci 5651cb0ef41Sopenharmony_ci // Delete left character 5661cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'h' }); 5671cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 18); 5681cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 5691cb0ef41Sopenharmony_ci assert.strictEqual(line, 'the quick brown fo'); 5701cb0ef41Sopenharmony_ci })); 5711cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 5721cb0ef41Sopenharmony_ci rli.close(); 5731cb0ef41Sopenharmony_ci} 5741cb0ef41Sopenharmony_ci 5751cb0ef41Sopenharmony_ci// deleteLeft astral character 5761cb0ef41Sopenharmony_ci{ 5771cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 5781cb0ef41Sopenharmony_ci fi.emit('data', ''); 5791cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 2); 5801cb0ef41Sopenharmony_ci // Delete left character 5811cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'h' }); 5821cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 5831cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 5841cb0ef41Sopenharmony_ci assert.strictEqual(line, ''); 5851cb0ef41Sopenharmony_ci })); 5861cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 5871cb0ef41Sopenharmony_ci rli.close(); 5881cb0ef41Sopenharmony_ci} 5891cb0ef41Sopenharmony_ci 5901cb0ef41Sopenharmony_ci// deleteRight 5911cb0ef41Sopenharmony_ci{ 5921cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 5931cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 5941cb0ef41Sopenharmony_ci 5951cb0ef41Sopenharmony_ci // Go to the start of the line 5961cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'a' }); 5971cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 5981cb0ef41Sopenharmony_ci 5991cb0ef41Sopenharmony_ci // Delete right character 6001cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'd' }); 6011cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 6021cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 6031cb0ef41Sopenharmony_ci assert.strictEqual(line, 'he quick brown fox'); 6041cb0ef41Sopenharmony_ci })); 6051cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 6061cb0ef41Sopenharmony_ci rli.close(); 6071cb0ef41Sopenharmony_ci} 6081cb0ef41Sopenharmony_ci 6091cb0ef41Sopenharmony_ci// deleteRight astral character 6101cb0ef41Sopenharmony_ci{ 6111cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 6121cb0ef41Sopenharmony_ci fi.emit('data', ''); 6131cb0ef41Sopenharmony_ci 6141cb0ef41Sopenharmony_ci // Go to the start of the line 6151cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'a' }); 6161cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 6171cb0ef41Sopenharmony_ci 6181cb0ef41Sopenharmony_ci // Delete right character 6191cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'd' }); 6201cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 6211cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 6221cb0ef41Sopenharmony_ci assert.strictEqual(line, ''); 6231cb0ef41Sopenharmony_ci })); 6241cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 6251cb0ef41Sopenharmony_ci rli.close(); 6261cb0ef41Sopenharmony_ci} 6271cb0ef41Sopenharmony_ci 6281cb0ef41Sopenharmony_ci// deleteLineLeft 6291cb0ef41Sopenharmony_ci{ 6301cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 6311cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 6321cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 19); 6331cb0ef41Sopenharmony_ci 6341cb0ef41Sopenharmony_ci // Delete from current to start of line 6351cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, shift: true, name: 'backspace' }); 6361cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 6371cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 6381cb0ef41Sopenharmony_ci assert.strictEqual(line, ''); 6391cb0ef41Sopenharmony_ci })); 6401cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 6411cb0ef41Sopenharmony_ci rli.close(); 6421cb0ef41Sopenharmony_ci} 6431cb0ef41Sopenharmony_ci 6441cb0ef41Sopenharmony_ci// deleteLineRight 6451cb0ef41Sopenharmony_ci{ 6461cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 6471cb0ef41Sopenharmony_ci fi.emit('data', 'the quick brown fox'); 6481cb0ef41Sopenharmony_ci 6491cb0ef41Sopenharmony_ci // Go to the start of the line 6501cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'a' }); 6511cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 6521cb0ef41Sopenharmony_ci 6531cb0ef41Sopenharmony_ci // Delete from current to end of line 6541cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, shift: true, name: 'delete' }); 6551cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 0); 6561cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 6571cb0ef41Sopenharmony_ci assert.strictEqual(line, ''); 6581cb0ef41Sopenharmony_ci })); 6591cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 6601cb0ef41Sopenharmony_ci rli.close(); 6611cb0ef41Sopenharmony_ci} 6621cb0ef41Sopenharmony_ci 6631cb0ef41Sopenharmony_ci// Close readline interface 6641cb0ef41Sopenharmony_ci{ 6651cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 6661cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'c' }); 6671cb0ef41Sopenharmony_ci assert(rli.closed); 6681cb0ef41Sopenharmony_ci} 6691cb0ef41Sopenharmony_ci 6701cb0ef41Sopenharmony_ci// Multi-line input cursor position 6711cb0ef41Sopenharmony_ci{ 6721cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 6731cb0ef41Sopenharmony_ci fi.columns = 10; 6741cb0ef41Sopenharmony_ci fi.emit('data', 'multi-line text'); 6751cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 1, 5); 6761cb0ef41Sopenharmony_ci rli.close(); 6771cb0ef41Sopenharmony_ci} 6781cb0ef41Sopenharmony_ci 6791cb0ef41Sopenharmony_ci// Multi-line input cursor position and long tabs 6801cb0ef41Sopenharmony_ci{ 6811cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ tabSize: 16, terminal: true, prompt: '' }); 6821cb0ef41Sopenharmony_ci fi.columns = 10; 6831cb0ef41Sopenharmony_ci fi.emit('data', 'multi-line\ttext \t'); 6841cb0ef41Sopenharmony_ci assert.strictEqual(rli.cursor, 17); 6851cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 3, 2); 6861cb0ef41Sopenharmony_ci rli.close(); 6871cb0ef41Sopenharmony_ci} 6881cb0ef41Sopenharmony_ci 6891cb0ef41Sopenharmony_ci// Check for the default tab size. 6901cb0ef41Sopenharmony_ci{ 6911cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 6921cb0ef41Sopenharmony_ci fi.emit('data', 'the quick\tbrown\tfox'); 6931cb0ef41Sopenharmony_ci assert.strictEqual(rli.cursor, 19); 6941cb0ef41Sopenharmony_ci // The first tab is 7 spaces long, the second one 3 spaces. 6951cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 27); 6961cb0ef41Sopenharmony_ci} 6971cb0ef41Sopenharmony_ci 6981cb0ef41Sopenharmony_ci// Multi-line prompt cursor position 6991cb0ef41Sopenharmony_ci{ 7001cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ 7011cb0ef41Sopenharmony_ci terminal: true, 7021cb0ef41Sopenharmony_ci prompt: '\nfilledline\nwraping text\n> ' 7031cb0ef41Sopenharmony_ci }); 7041cb0ef41Sopenharmony_ci fi.columns = 10; 7051cb0ef41Sopenharmony_ci fi.emit('data', 't'); 7061cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 4, 3); 7071cb0ef41Sopenharmony_ci rli.close(); 7081cb0ef41Sopenharmony_ci} 7091cb0ef41Sopenharmony_ci 7101cb0ef41Sopenharmony_ci// Clear the whole screen 7111cb0ef41Sopenharmony_ci{ 7121cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal: true, prompt: '' }); 7131cb0ef41Sopenharmony_ci const lines = ['line 1', 'line 2', 'line 3']; 7141cb0ef41Sopenharmony_ci fi.emit('data', lines.join('\n')); 7151cb0ef41Sopenharmony_ci fi.emit('keypress', '.', { ctrl: true, name: 'l' }); 7161cb0ef41Sopenharmony_ci assertCursorRowsAndCols(rli, 0, 6); 7171cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 7181cb0ef41Sopenharmony_ci assert.strictEqual(line, 'line 3'); 7191cb0ef41Sopenharmony_ci })); 7201cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 7211cb0ef41Sopenharmony_ci rli.close(); 7221cb0ef41Sopenharmony_ci} 7231cb0ef41Sopenharmony_ci 7241cb0ef41Sopenharmony_ci// Wide characters should be treated as two columns. 7251cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('a'), 1); 7261cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('あ'), 2); 7271cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('谢'), 2); 7281cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('고'), 2); 7291cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth(String.fromCodePoint(0x1f251)), 2); 7301cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('abcde'), 5); 7311cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('古池や'), 6); 7321cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('ノード.js'), 9); 7331cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('你好'), 4); 7341cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('안녕하세요'), 10); 7351cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('A\ud83c\ude00BC'), 5); 7361cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth(''), 8); 7371cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('あ'), 9); 7381cb0ef41Sopenharmony_ci// TODO(BridgeAR): This should have a width of 4. 7391cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('⓬⓪'), 2); 7401cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('\u0301\u200D\u200E'), 0); 7411cb0ef41Sopenharmony_ci 7421cb0ef41Sopenharmony_ci// Check if vt control chars are stripped 7431cb0ef41Sopenharmony_ciassert.strictEqual(stripVTControlCharacters('\u001b[31m> \u001b[39m'), '> '); 7441cb0ef41Sopenharmony_ciassert.strictEqual( 7451cb0ef41Sopenharmony_ci stripVTControlCharacters('\u001b[31m> \u001b[39m> '), 7461cb0ef41Sopenharmony_ci '> > ' 7471cb0ef41Sopenharmony_ci); 7481cb0ef41Sopenharmony_ciassert.strictEqual(stripVTControlCharacters('\u001b[31m\u001b[39m'), ''); 7491cb0ef41Sopenharmony_ciassert.strictEqual(stripVTControlCharacters('> '), '> '); 7501cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('\u001b[31m> \u001b[39m'), 2); 7511cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('\u001b[31m> \u001b[39m> '), 4); 7521cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('\u001b[31m\u001b[39m'), 0); 7531cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('> '), 2); 7541cb0ef41Sopenharmony_ci 7551cb0ef41Sopenharmony_ci// Check EventEmitter memory leak 7561cb0ef41Sopenharmony_cifor (let i = 0; i < 12; i++) { 7571cb0ef41Sopenharmony_ci const rl = readline.createInterface({ 7581cb0ef41Sopenharmony_ci input: process.stdin, 7591cb0ef41Sopenharmony_ci output: process.stdout 7601cb0ef41Sopenharmony_ci }); 7611cb0ef41Sopenharmony_ci rl.close(); 7621cb0ef41Sopenharmony_ci assert.strictEqual(isWarned(process.stdin._events), false); 7631cb0ef41Sopenharmony_ci assert.strictEqual(isWarned(process.stdout._events), false); 7641cb0ef41Sopenharmony_ci} 7651cb0ef41Sopenharmony_ci 7661cb0ef41Sopenharmony_ci[true, false].forEach(function(terminal) { 7671cb0ef41Sopenharmony_ci // Disable history 7681cb0ef41Sopenharmony_ci { 7691cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal, historySize: 0 }); 7701cb0ef41Sopenharmony_ci assert.strictEqual(rli.historySize, 0); 7711cb0ef41Sopenharmony_ci 7721cb0ef41Sopenharmony_ci fi.emit('data', 'asdf\n'); 7731cb0ef41Sopenharmony_ci assert.deepStrictEqual(rli.history, []); 7741cb0ef41Sopenharmony_ci rli.close(); 7751cb0ef41Sopenharmony_ci } 7761cb0ef41Sopenharmony_ci 7771cb0ef41Sopenharmony_ci // Default history size 30 7781cb0ef41Sopenharmony_ci { 7791cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal }); 7801cb0ef41Sopenharmony_ci assert.strictEqual(rli.historySize, 30); 7811cb0ef41Sopenharmony_ci 7821cb0ef41Sopenharmony_ci fi.emit('data', 'asdf\n'); 7831cb0ef41Sopenharmony_ci assert.deepStrictEqual(rli.history, terminal ? ['asdf'] : []); 7841cb0ef41Sopenharmony_ci rli.close(); 7851cb0ef41Sopenharmony_ci } 7861cb0ef41Sopenharmony_ci 7871cb0ef41Sopenharmony_ci // Sending a full line 7881cb0ef41Sopenharmony_ci { 7891cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal }); 7901cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 7911cb0ef41Sopenharmony_ci assert.strictEqual(line, 'asdf'); 7921cb0ef41Sopenharmony_ci })); 7931cb0ef41Sopenharmony_ci fi.emit('data', 'asdf\n'); 7941cb0ef41Sopenharmony_ci } 7951cb0ef41Sopenharmony_ci 7961cb0ef41Sopenharmony_ci // Ensure that options.signal.removeEventListener was called 7971cb0ef41Sopenharmony_ci { 7981cb0ef41Sopenharmony_ci const ac = new AbortController(); 7991cb0ef41Sopenharmony_ci const signal = ac.signal; 8001cb0ef41Sopenharmony_ci const [rli] = getInterface({ terminal }); 8011cb0ef41Sopenharmony_ci signal.removeEventListener = common.mustCall( 8021cb0ef41Sopenharmony_ci (event, onAbortFn) => { 8031cb0ef41Sopenharmony_ci assert.strictEqual(event, 'abort'); 8041cb0ef41Sopenharmony_ci assert.strictEqual(onAbortFn.name, 'onAbort'); 8051cb0ef41Sopenharmony_ci }); 8061cb0ef41Sopenharmony_ci 8071cb0ef41Sopenharmony_ci rli.question('hello?', { signal }).then(common.mustCall()); 8081cb0ef41Sopenharmony_ci 8091cb0ef41Sopenharmony_ci rli.write('bar\n'); 8101cb0ef41Sopenharmony_ci ac.abort(); 8111cb0ef41Sopenharmony_ci rli.close(); 8121cb0ef41Sopenharmony_ci } 8131cb0ef41Sopenharmony_ci 8141cb0ef41Sopenharmony_ci // Sending a blank line 8151cb0ef41Sopenharmony_ci { 8161cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal }); 8171cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 8181cb0ef41Sopenharmony_ci assert.strictEqual(line, ''); 8191cb0ef41Sopenharmony_ci })); 8201cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 8211cb0ef41Sopenharmony_ci } 8221cb0ef41Sopenharmony_ci 8231cb0ef41Sopenharmony_ci // Sending a single character with no newline and then a newline 8241cb0ef41Sopenharmony_ci { 8251cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal }); 8261cb0ef41Sopenharmony_ci let called = false; 8271cb0ef41Sopenharmony_ci rli.on('line', (line) => { 8281cb0ef41Sopenharmony_ci called = true; 8291cb0ef41Sopenharmony_ci assert.strictEqual(line, 'a'); 8301cb0ef41Sopenharmony_ci }); 8311cb0ef41Sopenharmony_ci fi.emit('data', 'a'); 8321cb0ef41Sopenharmony_ci assert.ok(!called); 8331cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 8341cb0ef41Sopenharmony_ci assert.ok(called); 8351cb0ef41Sopenharmony_ci rli.close(); 8361cb0ef41Sopenharmony_ci } 8371cb0ef41Sopenharmony_ci 8381cb0ef41Sopenharmony_ci // Sending multiple newlines at once 8391cb0ef41Sopenharmony_ci { 8401cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal }); 8411cb0ef41Sopenharmony_ci const expectedLines = ['foo', 'bar', 'baz']; 8421cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 8431cb0ef41Sopenharmony_ci assert.strictEqual(line, expectedLines.shift()); 8441cb0ef41Sopenharmony_ci }, expectedLines.length)); 8451cb0ef41Sopenharmony_ci fi.emit('data', `${expectedLines.join('\n')}\n`); 8461cb0ef41Sopenharmony_ci rli.close(); 8471cb0ef41Sopenharmony_ci } 8481cb0ef41Sopenharmony_ci 8491cb0ef41Sopenharmony_ci // Sending multiple newlines at once that does not end with a new line 8501cb0ef41Sopenharmony_ci { 8511cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal }); 8521cb0ef41Sopenharmony_ci const expectedLines = ['foo', 'bar', 'baz', 'bat']; 8531cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 8541cb0ef41Sopenharmony_ci assert.strictEqual(line, expectedLines.shift()); 8551cb0ef41Sopenharmony_ci }, expectedLines.length - 1)); 8561cb0ef41Sopenharmony_ci fi.emit('data', expectedLines.join('\n')); 8571cb0ef41Sopenharmony_ci rli.close(); 8581cb0ef41Sopenharmony_ci } 8591cb0ef41Sopenharmony_ci 8601cb0ef41Sopenharmony_ci // Sending multiple newlines at once that does not end with a new(empty) 8611cb0ef41Sopenharmony_ci // line and a `end` event 8621cb0ef41Sopenharmony_ci { 8631cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal }); 8641cb0ef41Sopenharmony_ci const expectedLines = ['foo', 'bar', 'baz', '']; 8651cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 8661cb0ef41Sopenharmony_ci assert.strictEqual(line, expectedLines.shift()); 8671cb0ef41Sopenharmony_ci }, expectedLines.length - 1)); 8681cb0ef41Sopenharmony_ci rli.on('close', common.mustCall()); 8691cb0ef41Sopenharmony_ci fi.emit('data', expectedLines.join('\n')); 8701cb0ef41Sopenharmony_ci fi.emit('end'); 8711cb0ef41Sopenharmony_ci rli.close(); 8721cb0ef41Sopenharmony_ci } 8731cb0ef41Sopenharmony_ci 8741cb0ef41Sopenharmony_ci // Sending a multi-byte utf8 char over multiple writes 8751cb0ef41Sopenharmony_ci { 8761cb0ef41Sopenharmony_ci const buf = Buffer.from('☮', 'utf8'); 8771cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal }); 8781cb0ef41Sopenharmony_ci let callCount = 0; 8791cb0ef41Sopenharmony_ci rli.on('line', function(line) { 8801cb0ef41Sopenharmony_ci callCount++; 8811cb0ef41Sopenharmony_ci assert.strictEqual(line, buf.toString('utf8')); 8821cb0ef41Sopenharmony_ci }); 8831cb0ef41Sopenharmony_ci for (const i of buf) { 8841cb0ef41Sopenharmony_ci fi.emit('data', Buffer.from([i])); 8851cb0ef41Sopenharmony_ci } 8861cb0ef41Sopenharmony_ci assert.strictEqual(callCount, 0); 8871cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 8881cb0ef41Sopenharmony_ci assert.strictEqual(callCount, 1); 8891cb0ef41Sopenharmony_ci rli.close(); 8901cb0ef41Sopenharmony_ci } 8911cb0ef41Sopenharmony_ci 8921cb0ef41Sopenharmony_ci // Calling readline without `new` 8931cb0ef41Sopenharmony_ci { 8941cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal }); 8951cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 8961cb0ef41Sopenharmony_ci assert.strictEqual(line, 'asdf'); 8971cb0ef41Sopenharmony_ci })); 8981cb0ef41Sopenharmony_ci fi.emit('data', 'asdf\n'); 8991cb0ef41Sopenharmony_ci rli.close(); 9001cb0ef41Sopenharmony_ci } 9011cb0ef41Sopenharmony_ci 9021cb0ef41Sopenharmony_ci // Calling the question callback 9031cb0ef41Sopenharmony_ci { 9041cb0ef41Sopenharmony_ci const [rli] = getInterface({ terminal }); 9051cb0ef41Sopenharmony_ci rli.question('foo?').then(common.mustCall((answer) => { 9061cb0ef41Sopenharmony_ci assert.strictEqual(answer, 'bar'); 9071cb0ef41Sopenharmony_ci })); 9081cb0ef41Sopenharmony_ci rli.write('bar\n'); 9091cb0ef41Sopenharmony_ci rli.close(); 9101cb0ef41Sopenharmony_ci } 9111cb0ef41Sopenharmony_ci 9121cb0ef41Sopenharmony_ci // Calling the question callback with abort signal 9131cb0ef41Sopenharmony_ci { 9141cb0ef41Sopenharmony_ci const [rli] = getInterface({ terminal }); 9151cb0ef41Sopenharmony_ci const { signal } = new AbortController(); 9161cb0ef41Sopenharmony_ci rli.question('foo?', { signal }).then(common.mustCall((answer) => { 9171cb0ef41Sopenharmony_ci assert.strictEqual(answer, 'bar'); 9181cb0ef41Sopenharmony_ci })); 9191cb0ef41Sopenharmony_ci rli.write('bar\n'); 9201cb0ef41Sopenharmony_ci rli.close(); 9211cb0ef41Sopenharmony_ci } 9221cb0ef41Sopenharmony_ci 9231cb0ef41Sopenharmony_ci // Aborting a question 9241cb0ef41Sopenharmony_ci { 9251cb0ef41Sopenharmony_ci const ac = new AbortController(); 9261cb0ef41Sopenharmony_ci const signal = ac.signal; 9271cb0ef41Sopenharmony_ci const [rli] = getInterface({ terminal }); 9281cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 9291cb0ef41Sopenharmony_ci assert.strictEqual(line, 'bar'); 9301cb0ef41Sopenharmony_ci })); 9311cb0ef41Sopenharmony_ci assert.rejects(rli.question('hello?', { signal }), { name: 'AbortError' }) 9321cb0ef41Sopenharmony_ci .then(common.mustCall()); 9331cb0ef41Sopenharmony_ci ac.abort(); 9341cb0ef41Sopenharmony_ci rli.write('bar\n'); 9351cb0ef41Sopenharmony_ci rli.close(); 9361cb0ef41Sopenharmony_ci } 9371cb0ef41Sopenharmony_ci 9381cb0ef41Sopenharmony_ci (async () => { 9391cb0ef41Sopenharmony_ci const [rli] = getInterface({ terminal }); 9401cb0ef41Sopenharmony_ci const signal = AbortSignal.abort('boom'); 9411cb0ef41Sopenharmony_ci await assert.rejects(rli.question('hello', { signal }), { 9421cb0ef41Sopenharmony_ci cause: 'boom', 9431cb0ef41Sopenharmony_ci }); 9441cb0ef41Sopenharmony_ci rli.close(); 9451cb0ef41Sopenharmony_ci })().then(common.mustCall()); 9461cb0ef41Sopenharmony_ci 9471cb0ef41Sopenharmony_ci // Throw an error when question is executed with an aborted signal 9481cb0ef41Sopenharmony_ci { 9491cb0ef41Sopenharmony_ci const ac = new AbortController(); 9501cb0ef41Sopenharmony_ci const signal = ac.signal; 9511cb0ef41Sopenharmony_ci ac.abort(); 9521cb0ef41Sopenharmony_ci const [rli] = getInterface({ terminal }); 9531cb0ef41Sopenharmony_ci assert.rejects( 9541cb0ef41Sopenharmony_ci rli.question('hello?', { signal }), 9551cb0ef41Sopenharmony_ci { 9561cb0ef41Sopenharmony_ci name: 'AbortError' 9571cb0ef41Sopenharmony_ci } 9581cb0ef41Sopenharmony_ci ).then(common.mustCall()); 9591cb0ef41Sopenharmony_ci rli.close(); 9601cb0ef41Sopenharmony_ci } 9611cb0ef41Sopenharmony_ci 9621cb0ef41Sopenharmony_ci // Call question after close 9631cb0ef41Sopenharmony_ci { 9641cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal }); 9651cb0ef41Sopenharmony_ci rli.question('What\'s your name?').then(common.mustCall((name) => { 9661cb0ef41Sopenharmony_ci assert.strictEqual(name, 'Node.js'); 9671cb0ef41Sopenharmony_ci rli.close(); 9681cb0ef41Sopenharmony_ci rli.question('How are you?') 9691cb0ef41Sopenharmony_ci .then(common.mustNotCall(), common.expectsError({ 9701cb0ef41Sopenharmony_ci code: 'ERR_USE_AFTER_CLOSE', 9711cb0ef41Sopenharmony_ci name: 'Error' 9721cb0ef41Sopenharmony_ci })); 9731cb0ef41Sopenharmony_ci assert.notStrictEqual(rli.getPrompt(), 'How are you?'); 9741cb0ef41Sopenharmony_ci })); 9751cb0ef41Sopenharmony_ci fi.emit('data', 'Node.js\n'); 9761cb0ef41Sopenharmony_ci } 9771cb0ef41Sopenharmony_ci 9781cb0ef41Sopenharmony_ci 9791cb0ef41Sopenharmony_ci // Can create a new readline Interface with a null output argument 9801cb0ef41Sopenharmony_ci { 9811cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ output: null, terminal }); 9821cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 9831cb0ef41Sopenharmony_ci assert.strictEqual(line, 'asdf'); 9841cb0ef41Sopenharmony_ci })); 9851cb0ef41Sopenharmony_ci fi.emit('data', 'asdf\n'); 9861cb0ef41Sopenharmony_ci 9871cb0ef41Sopenharmony_ci rli.setPrompt('ddd> '); 9881cb0ef41Sopenharmony_ci rli.prompt(); 9891cb0ef41Sopenharmony_ci rli.write("really shouldn't be seeing this"); 9901cb0ef41Sopenharmony_ci rli.question('What do you think of node.js? ', function(answer) { 9911cb0ef41Sopenharmony_ci console.log('Thank you for your valuable feedback:', answer); 9921cb0ef41Sopenharmony_ci rli.close(); 9931cb0ef41Sopenharmony_ci }); 9941cb0ef41Sopenharmony_ci } 9951cb0ef41Sopenharmony_ci 9961cb0ef41Sopenharmony_ci // Calling the getPrompt method 9971cb0ef41Sopenharmony_ci { 9981cb0ef41Sopenharmony_ci const expectedPrompts = ['$ ', '> ']; 9991cb0ef41Sopenharmony_ci const [rli] = getInterface({ terminal }); 10001cb0ef41Sopenharmony_ci for (const prompt of expectedPrompts) { 10011cb0ef41Sopenharmony_ci rli.setPrompt(prompt); 10021cb0ef41Sopenharmony_ci assert.strictEqual(rli.getPrompt(), prompt); 10031cb0ef41Sopenharmony_ci } 10041cb0ef41Sopenharmony_ci } 10051cb0ef41Sopenharmony_ci 10061cb0ef41Sopenharmony_ci { 10071cb0ef41Sopenharmony_ci const expected = terminal ? 10081cb0ef41Sopenharmony_ci ['\u001b[1G', '\u001b[0J', '$ ', '\u001b[3G'] : 10091cb0ef41Sopenharmony_ci ['$ ']; 10101cb0ef41Sopenharmony_ci 10111cb0ef41Sopenharmony_ci const output = new Writable({ 10121cb0ef41Sopenharmony_ci write: common.mustCall((chunk, enc, cb) => { 10131cb0ef41Sopenharmony_ci assert.strictEqual(chunk.toString(), expected.shift()); 10141cb0ef41Sopenharmony_ci cb(); 10151cb0ef41Sopenharmony_ci rl.close(); 10161cb0ef41Sopenharmony_ci }, expected.length) 10171cb0ef41Sopenharmony_ci }); 10181cb0ef41Sopenharmony_ci 10191cb0ef41Sopenharmony_ci const rl = readline.createInterface({ 10201cb0ef41Sopenharmony_ci input: new Readable({ read: common.mustCall() }), 10211cb0ef41Sopenharmony_ci output, 10221cb0ef41Sopenharmony_ci prompt: '$ ', 10231cb0ef41Sopenharmony_ci terminal 10241cb0ef41Sopenharmony_ci }); 10251cb0ef41Sopenharmony_ci 10261cb0ef41Sopenharmony_ci rl.prompt(); 10271cb0ef41Sopenharmony_ci 10281cb0ef41Sopenharmony_ci assert.strictEqual(rl.getPrompt(), '$ '); 10291cb0ef41Sopenharmony_ci } 10301cb0ef41Sopenharmony_ci 10311cb0ef41Sopenharmony_ci { 10321cb0ef41Sopenharmony_ci const fi = new FakeInput(); 10331cb0ef41Sopenharmony_ci assert.deepStrictEqual(fi.listeners(terminal ? 'keypress' : 'data'), []); 10341cb0ef41Sopenharmony_ci } 10351cb0ef41Sopenharmony_ci 10361cb0ef41Sopenharmony_ci // Emit two line events when the delay 10371cb0ef41Sopenharmony_ci // between \r and \n exceeds crlfDelay 10381cb0ef41Sopenharmony_ci { 10391cb0ef41Sopenharmony_ci const crlfDelay = 200; 10401cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal, crlfDelay }); 10411cb0ef41Sopenharmony_ci let callCount = 0; 10421cb0ef41Sopenharmony_ci rli.on('line', function(line) { 10431cb0ef41Sopenharmony_ci callCount++; 10441cb0ef41Sopenharmony_ci }); 10451cb0ef41Sopenharmony_ci fi.emit('data', '\r'); 10461cb0ef41Sopenharmony_ci setTimeout(common.mustCall(() => { 10471cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 10481cb0ef41Sopenharmony_ci assert.strictEqual(callCount, 2); 10491cb0ef41Sopenharmony_ci rli.close(); 10501cb0ef41Sopenharmony_ci }), crlfDelay + 10); 10511cb0ef41Sopenharmony_ci } 10521cb0ef41Sopenharmony_ci 10531cb0ef41Sopenharmony_ci // For the purposes of the following tests, we do not care about the exact 10541cb0ef41Sopenharmony_ci // value of crlfDelay, only that the behaviour conforms to what's expected. 10551cb0ef41Sopenharmony_ci // Setting it to Infinity allows the test to succeed even under extreme 10561cb0ef41Sopenharmony_ci // CPU stress. 10571cb0ef41Sopenharmony_ci const crlfDelay = Infinity; 10581cb0ef41Sopenharmony_ci 10591cb0ef41Sopenharmony_ci // Set crlfDelay to `Infinity` is allowed 10601cb0ef41Sopenharmony_ci { 10611cb0ef41Sopenharmony_ci const delay = 200; 10621cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal, crlfDelay }); 10631cb0ef41Sopenharmony_ci let callCount = 0; 10641cb0ef41Sopenharmony_ci rli.on('line', function(line) { 10651cb0ef41Sopenharmony_ci callCount++; 10661cb0ef41Sopenharmony_ci }); 10671cb0ef41Sopenharmony_ci fi.emit('data', '\r'); 10681cb0ef41Sopenharmony_ci setTimeout(common.mustCall(() => { 10691cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 10701cb0ef41Sopenharmony_ci assert.strictEqual(callCount, 1); 10711cb0ef41Sopenharmony_ci rli.close(); 10721cb0ef41Sopenharmony_ci }), delay); 10731cb0ef41Sopenharmony_ci } 10741cb0ef41Sopenharmony_ci 10751cb0ef41Sopenharmony_ci // Sending multiple newlines at once that does not end with a new line 10761cb0ef41Sopenharmony_ci // and a `end` event(last line is) 10771cb0ef41Sopenharmony_ci 10781cb0ef41Sopenharmony_ci // \r\n should emit one line event, not two 10791cb0ef41Sopenharmony_ci { 10801cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal, crlfDelay }); 10811cb0ef41Sopenharmony_ci const expectedLines = ['foo', 'bar', 'baz', 'bat']; 10821cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 10831cb0ef41Sopenharmony_ci assert.strictEqual(line, expectedLines.shift()); 10841cb0ef41Sopenharmony_ci }, expectedLines.length - 1)); 10851cb0ef41Sopenharmony_ci fi.emit('data', expectedLines.join('\r\n')); 10861cb0ef41Sopenharmony_ci rli.close(); 10871cb0ef41Sopenharmony_ci } 10881cb0ef41Sopenharmony_ci 10891cb0ef41Sopenharmony_ci // \r\n should emit one line event when split across multiple writes. 10901cb0ef41Sopenharmony_ci { 10911cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal, crlfDelay }); 10921cb0ef41Sopenharmony_ci const expectedLines = ['foo', 'bar', 'baz', 'bat']; 10931cb0ef41Sopenharmony_ci let callCount = 0; 10941cb0ef41Sopenharmony_ci rli.on('line', common.mustCall((line) => { 10951cb0ef41Sopenharmony_ci assert.strictEqual(line, expectedLines[callCount]); 10961cb0ef41Sopenharmony_ci callCount++; 10971cb0ef41Sopenharmony_ci }, expectedLines.length)); 10981cb0ef41Sopenharmony_ci expectedLines.forEach((line) => { 10991cb0ef41Sopenharmony_ci fi.emit('data', `${line}\r`); 11001cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 11011cb0ef41Sopenharmony_ci }); 11021cb0ef41Sopenharmony_ci rli.close(); 11031cb0ef41Sopenharmony_ci } 11041cb0ef41Sopenharmony_ci 11051cb0ef41Sopenharmony_ci // Emit one line event when the delay between \r and \n is 11061cb0ef41Sopenharmony_ci // over the default crlfDelay but within the setting value. 11071cb0ef41Sopenharmony_ci { 11081cb0ef41Sopenharmony_ci const delay = 125; 11091cb0ef41Sopenharmony_ci const [rli, fi] = getInterface({ terminal, crlfDelay }); 11101cb0ef41Sopenharmony_ci let callCount = 0; 11111cb0ef41Sopenharmony_ci rli.on('line', () => callCount++); 11121cb0ef41Sopenharmony_ci fi.emit('data', '\r'); 11131cb0ef41Sopenharmony_ci setTimeout(common.mustCall(() => { 11141cb0ef41Sopenharmony_ci fi.emit('data', '\n'); 11151cb0ef41Sopenharmony_ci assert.strictEqual(callCount, 1); 11161cb0ef41Sopenharmony_ci rli.close(); 11171cb0ef41Sopenharmony_ci }), delay); 11181cb0ef41Sopenharmony_ci } 11191cb0ef41Sopenharmony_ci}); 11201cb0ef41Sopenharmony_ci 11211cb0ef41Sopenharmony_ci// Ensure that the _wordLeft method works even for large input 11221cb0ef41Sopenharmony_ci{ 11231cb0ef41Sopenharmony_ci const input = new Readable({ 11241cb0ef41Sopenharmony_ci read() { 11251cb0ef41Sopenharmony_ci this.push('\x1B[1;5D'); // CTRL + Left 11261cb0ef41Sopenharmony_ci this.push(null); 11271cb0ef41Sopenharmony_ci }, 11281cb0ef41Sopenharmony_ci }); 11291cb0ef41Sopenharmony_ci const output = new Writable({ 11301cb0ef41Sopenharmony_ci write: common.mustCall((data, encoding, cb) => { 11311cb0ef41Sopenharmony_ci assert.strictEqual(rl.cursor, rl.line.length - 1); 11321cb0ef41Sopenharmony_ci cb(); 11331cb0ef41Sopenharmony_ci }), 11341cb0ef41Sopenharmony_ci }); 11351cb0ef41Sopenharmony_ci const rl = new readline.createInterface({ 11361cb0ef41Sopenharmony_ci input, 11371cb0ef41Sopenharmony_ci output, 11381cb0ef41Sopenharmony_ci terminal: true, 11391cb0ef41Sopenharmony_ci }); 11401cb0ef41Sopenharmony_ci rl.line = `a${' '.repeat(1e6)}a`; 11411cb0ef41Sopenharmony_ci rl.cursor = rl.line.length; 11421cb0ef41Sopenharmony_ci} 1143