11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ciconst { 41cb0ef41Sopenharmony_ci ArrayPrototypeFilter, 51cb0ef41Sopenharmony_ci ArrayPrototypeIncludes, 61cb0ef41Sopenharmony_ci ArrayPrototypeMap, 71cb0ef41Sopenharmony_ci Boolean, 81cb0ef41Sopenharmony_ci FunctionPrototypeBind, 91cb0ef41Sopenharmony_ci MathMin, 101cb0ef41Sopenharmony_ci RegExpPrototypeExec, 111cb0ef41Sopenharmony_ci SafeSet, 121cb0ef41Sopenharmony_ci SafeStringIterator, 131cb0ef41Sopenharmony_ci StringPrototypeEndsWith, 141cb0ef41Sopenharmony_ci StringPrototypeIndexOf, 151cb0ef41Sopenharmony_ci StringPrototypeLastIndexOf, 161cb0ef41Sopenharmony_ci StringPrototypeReplaceAll, 171cb0ef41Sopenharmony_ci StringPrototypeSlice, 181cb0ef41Sopenharmony_ci StringPrototypeStartsWith, 191cb0ef41Sopenharmony_ci StringPrototypeToLowerCase, 201cb0ef41Sopenharmony_ci StringPrototypeTrim, 211cb0ef41Sopenharmony_ci Symbol, 221cb0ef41Sopenharmony_ci} = primordials; 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ciconst { tokTypes: tt, Parser: AcornParser } = 251cb0ef41Sopenharmony_ci require('internal/deps/acorn/acorn/dist/acorn'); 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_ciconst { sendInspectorCommand } = require('internal/util/inspector'); 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_ciconst { 301cb0ef41Sopenharmony_ci ERR_INSPECTOR_NOT_AVAILABLE, 311cb0ef41Sopenharmony_ci} = require('internal/errors').codes; 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ciconst { 341cb0ef41Sopenharmony_ci clearLine, 351cb0ef41Sopenharmony_ci clearScreenDown, 361cb0ef41Sopenharmony_ci cursorTo, 371cb0ef41Sopenharmony_ci moveCursor, 381cb0ef41Sopenharmony_ci} = require('internal/readline/callbacks'); 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ciconst { 411cb0ef41Sopenharmony_ci commonPrefix, 421cb0ef41Sopenharmony_ci kSubstringSearch, 431cb0ef41Sopenharmony_ci} = require('internal/readline/utils'); 441cb0ef41Sopenharmony_ci 451cb0ef41Sopenharmony_ciconst { 461cb0ef41Sopenharmony_ci getStringWidth, 471cb0ef41Sopenharmony_ci inspect, 481cb0ef41Sopenharmony_ci} = require('internal/util/inspect'); 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_cilet debug = require('internal/util/debuglog').debuglog('repl', (fn) => { 511cb0ef41Sopenharmony_ci debug = fn; 521cb0ef41Sopenharmony_ci}); 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_ciconst previewOptions = { 551cb0ef41Sopenharmony_ci colors: false, 561cb0ef41Sopenharmony_ci depth: 1, 571cb0ef41Sopenharmony_ci showHidden: false, 581cb0ef41Sopenharmony_ci}; 591cb0ef41Sopenharmony_ci 601cb0ef41Sopenharmony_ciconst REPL_MODE_STRICT = Symbol('repl-strict'); 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_ci// If the error is that we've unexpectedly ended the input, 631cb0ef41Sopenharmony_ci// then let the user try to recover by adding more input. 641cb0ef41Sopenharmony_ci// Note: `e` (the original exception) is not used by the current implementation, 651cb0ef41Sopenharmony_ci// but may be needed in the future. 661cb0ef41Sopenharmony_cifunction isRecoverableError(e, code) { 671cb0ef41Sopenharmony_ci // For similar reasons as `defaultEval`, wrap expressions starting with a 681cb0ef41Sopenharmony_ci // curly brace with parenthesis. Note: only the open parenthesis is added 691cb0ef41Sopenharmony_ci // here as the point is to test for potentially valid but incomplete 701cb0ef41Sopenharmony_ci // expressions. 711cb0ef41Sopenharmony_ci if (RegExpPrototypeExec(/^\s*\{/, code) !== null && 721cb0ef41Sopenharmony_ci isRecoverableError(e, `(${code}`)) 731cb0ef41Sopenharmony_ci return true; 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci let recoverable = false; 761cb0ef41Sopenharmony_ci 771cb0ef41Sopenharmony_ci // Determine if the point of any error raised is at the end of the input. 781cb0ef41Sopenharmony_ci // There are two cases to consider: 791cb0ef41Sopenharmony_ci // 801cb0ef41Sopenharmony_ci // 1. Any error raised after we have encountered the 'eof' token. 811cb0ef41Sopenharmony_ci // This prevents us from declaring partial tokens (like '2e') as 821cb0ef41Sopenharmony_ci // recoverable. 831cb0ef41Sopenharmony_ci // 841cb0ef41Sopenharmony_ci // 2. Three cases where tokens can legally span lines. This is 851cb0ef41Sopenharmony_ci // template, comment, and strings with a backslash at the end of 861cb0ef41Sopenharmony_ci // the line, indicating a continuation. Note that we need to look 871cb0ef41Sopenharmony_ci // for the specific errors of 'unterminated' kind (not, for example, 881cb0ef41Sopenharmony_ci // a syntax error in a ${} expression in a template), and the only 891cb0ef41Sopenharmony_ci // way to do that currently is to look at the message. Should Acorn 901cb0ef41Sopenharmony_ci // change these messages in the future, this will lead to a test 911cb0ef41Sopenharmony_ci // failure, indicating that this code needs to be updated. 921cb0ef41Sopenharmony_ci // 931cb0ef41Sopenharmony_ci const RecoverableParser = AcornParser 941cb0ef41Sopenharmony_ci .extend( 951cb0ef41Sopenharmony_ci (Parser) => { 961cb0ef41Sopenharmony_ci return class extends Parser { 971cb0ef41Sopenharmony_ci // eslint-disable-next-line no-useless-constructor 981cb0ef41Sopenharmony_ci constructor(options, input, startPos) { 991cb0ef41Sopenharmony_ci super(options, input, startPos); 1001cb0ef41Sopenharmony_ci } 1011cb0ef41Sopenharmony_ci nextToken() { 1021cb0ef41Sopenharmony_ci super.nextToken(); 1031cb0ef41Sopenharmony_ci if (this.type === tt.eof) 1041cb0ef41Sopenharmony_ci recoverable = true; 1051cb0ef41Sopenharmony_ci } 1061cb0ef41Sopenharmony_ci raise(pos, message) { 1071cb0ef41Sopenharmony_ci switch (message) { 1081cb0ef41Sopenharmony_ci case 'Unterminated template': 1091cb0ef41Sopenharmony_ci case 'Unterminated comment': 1101cb0ef41Sopenharmony_ci recoverable = true; 1111cb0ef41Sopenharmony_ci break; 1121cb0ef41Sopenharmony_ci 1131cb0ef41Sopenharmony_ci case 'Unterminated string constant': { 1141cb0ef41Sopenharmony_ci const token = StringPrototypeSlice(this.input, 1151cb0ef41Sopenharmony_ci this.lastTokStart, this.pos); 1161cb0ef41Sopenharmony_ci // See https://www.ecma-international.org/ecma-262/#sec-line-terminators 1171cb0ef41Sopenharmony_ci if (RegExpPrototypeExec(/\\(?:\r\n?|\n|\u2028|\u2029)$/, 1181cb0ef41Sopenharmony_ci token) !== null) { 1191cb0ef41Sopenharmony_ci recoverable = true; 1201cb0ef41Sopenharmony_ci } 1211cb0ef41Sopenharmony_ci } 1221cb0ef41Sopenharmony_ci } 1231cb0ef41Sopenharmony_ci super.raise(pos, message); 1241cb0ef41Sopenharmony_ci } 1251cb0ef41Sopenharmony_ci }; 1261cb0ef41Sopenharmony_ci }, 1271cb0ef41Sopenharmony_ci ); 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ci // Try to parse the code with acorn. If the parse fails, ignore the acorn 1301cb0ef41Sopenharmony_ci // error and return the recoverable status. 1311cb0ef41Sopenharmony_ci try { 1321cb0ef41Sopenharmony_ci RecoverableParser.parse(code, { ecmaVersion: 'latest' }); 1331cb0ef41Sopenharmony_ci 1341cb0ef41Sopenharmony_ci // Odd case: the underlying JS engine (V8, Chakra) rejected this input 1351cb0ef41Sopenharmony_ci // but Acorn detected no issue. Presume that additional text won't 1361cb0ef41Sopenharmony_ci // address this issue. 1371cb0ef41Sopenharmony_ci return false; 1381cb0ef41Sopenharmony_ci } catch { 1391cb0ef41Sopenharmony_ci return recoverable; 1401cb0ef41Sopenharmony_ci } 1411cb0ef41Sopenharmony_ci} 1421cb0ef41Sopenharmony_ci 1431cb0ef41Sopenharmony_cifunction setupPreview(repl, contextSymbol, bufferSymbol, active) { 1441cb0ef41Sopenharmony_ci // Simple terminals can't handle previews. 1451cb0ef41Sopenharmony_ci if (process.env.TERM === 'dumb' || !active) { 1461cb0ef41Sopenharmony_ci return { showPreview() {}, clearPreview() {} }; 1471cb0ef41Sopenharmony_ci } 1481cb0ef41Sopenharmony_ci 1491cb0ef41Sopenharmony_ci let inputPreview = null; 1501cb0ef41Sopenharmony_ci 1511cb0ef41Sopenharmony_ci let previewCompletionCounter = 0; 1521cb0ef41Sopenharmony_ci let completionPreview = null; 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_ci let hasCompletions = false; 1551cb0ef41Sopenharmony_ci 1561cb0ef41Sopenharmony_ci let wrapped = false; 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_ci let escaped = null; 1591cb0ef41Sopenharmony_ci 1601cb0ef41Sopenharmony_ci function getPreviewPos() { 1611cb0ef41Sopenharmony_ci const displayPos = repl._getDisplayPos(`${repl.getPrompt()}${repl.line}`); 1621cb0ef41Sopenharmony_ci const cursorPos = repl.line.length !== repl.cursor ? 1631cb0ef41Sopenharmony_ci repl.getCursorPos() : 1641cb0ef41Sopenharmony_ci displayPos; 1651cb0ef41Sopenharmony_ci return { displayPos, cursorPos }; 1661cb0ef41Sopenharmony_ci } 1671cb0ef41Sopenharmony_ci 1681cb0ef41Sopenharmony_ci function isCursorAtInputEnd() { 1691cb0ef41Sopenharmony_ci const { cursorPos, displayPos } = getPreviewPos(); 1701cb0ef41Sopenharmony_ci return cursorPos.rows === displayPos.rows && 1711cb0ef41Sopenharmony_ci cursorPos.cols === displayPos.cols; 1721cb0ef41Sopenharmony_ci } 1731cb0ef41Sopenharmony_ci 1741cb0ef41Sopenharmony_ci const clearPreview = (key) => { 1751cb0ef41Sopenharmony_ci if (inputPreview !== null) { 1761cb0ef41Sopenharmony_ci const { displayPos, cursorPos } = getPreviewPos(); 1771cb0ef41Sopenharmony_ci const rows = displayPos.rows - cursorPos.rows + 1; 1781cb0ef41Sopenharmony_ci moveCursor(repl.output, 0, rows); 1791cb0ef41Sopenharmony_ci clearLine(repl.output); 1801cb0ef41Sopenharmony_ci moveCursor(repl.output, 0, -rows); 1811cb0ef41Sopenharmony_ci inputPreview = null; 1821cb0ef41Sopenharmony_ci } 1831cb0ef41Sopenharmony_ci if (completionPreview !== null) { 1841cb0ef41Sopenharmony_ci // Prevent cursor moves if not necessary! 1851cb0ef41Sopenharmony_ci const move = repl.line.length !== repl.cursor; 1861cb0ef41Sopenharmony_ci let pos, rows; 1871cb0ef41Sopenharmony_ci if (move) { 1881cb0ef41Sopenharmony_ci pos = getPreviewPos(); 1891cb0ef41Sopenharmony_ci cursorTo(repl.output, pos.displayPos.cols); 1901cb0ef41Sopenharmony_ci rows = pos.displayPos.rows - pos.cursorPos.rows; 1911cb0ef41Sopenharmony_ci moveCursor(repl.output, 0, rows); 1921cb0ef41Sopenharmony_ci } 1931cb0ef41Sopenharmony_ci const totalLine = `${repl.getPrompt()}${repl.line}${completionPreview}`; 1941cb0ef41Sopenharmony_ci const newPos = repl._getDisplayPos(totalLine); 1951cb0ef41Sopenharmony_ci // Minimize work for the terminal. It is enough to clear the right part of 1961cb0ef41Sopenharmony_ci // the current line in case the preview is visible on a single line. 1971cb0ef41Sopenharmony_ci if (newPos.rows === 0 || (pos && pos.displayPos.rows === newPos.rows)) { 1981cb0ef41Sopenharmony_ci clearLine(repl.output, 1); 1991cb0ef41Sopenharmony_ci } else { 2001cb0ef41Sopenharmony_ci clearScreenDown(repl.output); 2011cb0ef41Sopenharmony_ci } 2021cb0ef41Sopenharmony_ci if (move) { 2031cb0ef41Sopenharmony_ci cursorTo(repl.output, pos.cursorPos.cols); 2041cb0ef41Sopenharmony_ci moveCursor(repl.output, 0, -rows); 2051cb0ef41Sopenharmony_ci } 2061cb0ef41Sopenharmony_ci if (!key.ctrl && !key.shift) { 2071cb0ef41Sopenharmony_ci if (key.name === 'escape') { 2081cb0ef41Sopenharmony_ci if (escaped === null && key.meta) { 2091cb0ef41Sopenharmony_ci escaped = repl.line; 2101cb0ef41Sopenharmony_ci } 2111cb0ef41Sopenharmony_ci } else if ((key.name === 'return' || key.name === 'enter') && 2121cb0ef41Sopenharmony_ci !key.meta && 2131cb0ef41Sopenharmony_ci escaped !== repl.line && 2141cb0ef41Sopenharmony_ci isCursorAtInputEnd()) { 2151cb0ef41Sopenharmony_ci repl._insertString(completionPreview); 2161cb0ef41Sopenharmony_ci } 2171cb0ef41Sopenharmony_ci } 2181cb0ef41Sopenharmony_ci completionPreview = null; 2191cb0ef41Sopenharmony_ci } 2201cb0ef41Sopenharmony_ci if (escaped !== repl.line) { 2211cb0ef41Sopenharmony_ci escaped = null; 2221cb0ef41Sopenharmony_ci } 2231cb0ef41Sopenharmony_ci }; 2241cb0ef41Sopenharmony_ci 2251cb0ef41Sopenharmony_ci function showCompletionPreview(line, insertPreview) { 2261cb0ef41Sopenharmony_ci previewCompletionCounter++; 2271cb0ef41Sopenharmony_ci 2281cb0ef41Sopenharmony_ci const count = previewCompletionCounter; 2291cb0ef41Sopenharmony_ci 2301cb0ef41Sopenharmony_ci repl.completer(line, (error, data) => { 2311cb0ef41Sopenharmony_ci // Tab completion might be async and the result might already be outdated. 2321cb0ef41Sopenharmony_ci if (count !== previewCompletionCounter) { 2331cb0ef41Sopenharmony_ci return; 2341cb0ef41Sopenharmony_ci } 2351cb0ef41Sopenharmony_ci 2361cb0ef41Sopenharmony_ci if (error) { 2371cb0ef41Sopenharmony_ci debug('Error while generating completion preview', error); 2381cb0ef41Sopenharmony_ci return; 2391cb0ef41Sopenharmony_ci } 2401cb0ef41Sopenharmony_ci 2411cb0ef41Sopenharmony_ci // Result and the text that was completed. 2421cb0ef41Sopenharmony_ci const { 0: rawCompletions, 1: completeOn } = data; 2431cb0ef41Sopenharmony_ci 2441cb0ef41Sopenharmony_ci if (!rawCompletions || rawCompletions.length === 0) { 2451cb0ef41Sopenharmony_ci return; 2461cb0ef41Sopenharmony_ci } 2471cb0ef41Sopenharmony_ci 2481cb0ef41Sopenharmony_ci hasCompletions = true; 2491cb0ef41Sopenharmony_ci 2501cb0ef41Sopenharmony_ci // If there is a common prefix to all matches, then apply that portion. 2511cb0ef41Sopenharmony_ci const completions = ArrayPrototypeFilter(rawCompletions, Boolean); 2521cb0ef41Sopenharmony_ci const prefix = commonPrefix(completions); 2531cb0ef41Sopenharmony_ci 2541cb0ef41Sopenharmony_ci // No common prefix found. 2551cb0ef41Sopenharmony_ci if (prefix.length <= completeOn.length) { 2561cb0ef41Sopenharmony_ci return; 2571cb0ef41Sopenharmony_ci } 2581cb0ef41Sopenharmony_ci 2591cb0ef41Sopenharmony_ci const suffix = StringPrototypeSlice(prefix, completeOn.length); 2601cb0ef41Sopenharmony_ci 2611cb0ef41Sopenharmony_ci if (insertPreview) { 2621cb0ef41Sopenharmony_ci repl._insertString(suffix); 2631cb0ef41Sopenharmony_ci return; 2641cb0ef41Sopenharmony_ci } 2651cb0ef41Sopenharmony_ci 2661cb0ef41Sopenharmony_ci completionPreview = suffix; 2671cb0ef41Sopenharmony_ci 2681cb0ef41Sopenharmony_ci const result = repl.useColors ? 2691cb0ef41Sopenharmony_ci `\u001b[90m${suffix}\u001b[39m` : 2701cb0ef41Sopenharmony_ci ` // ${suffix}`; 2711cb0ef41Sopenharmony_ci 2721cb0ef41Sopenharmony_ci const { cursorPos, displayPos } = getPreviewPos(); 2731cb0ef41Sopenharmony_ci if (repl.line.length !== repl.cursor) { 2741cb0ef41Sopenharmony_ci cursorTo(repl.output, displayPos.cols); 2751cb0ef41Sopenharmony_ci moveCursor(repl.output, 0, displayPos.rows - cursorPos.rows); 2761cb0ef41Sopenharmony_ci } 2771cb0ef41Sopenharmony_ci repl.output.write(result); 2781cb0ef41Sopenharmony_ci cursorTo(repl.output, cursorPos.cols); 2791cb0ef41Sopenharmony_ci const totalLine = `${repl.getPrompt()}${repl.line}${suffix}`; 2801cb0ef41Sopenharmony_ci const newPos = repl._getDisplayPos(totalLine); 2811cb0ef41Sopenharmony_ci const rows = newPos.rows - cursorPos.rows - (newPos.cols === 0 ? 1 : 0); 2821cb0ef41Sopenharmony_ci moveCursor(repl.output, 0, -rows); 2831cb0ef41Sopenharmony_ci }); 2841cb0ef41Sopenharmony_ci } 2851cb0ef41Sopenharmony_ci 2861cb0ef41Sopenharmony_ci function isInStrictMode(repl) { 2871cb0ef41Sopenharmony_ci return repl.replMode === REPL_MODE_STRICT || ArrayPrototypeIncludes( 2881cb0ef41Sopenharmony_ci ArrayPrototypeMap(process.execArgv, 2891cb0ef41Sopenharmony_ci (e) => StringPrototypeReplaceAll( 2901cb0ef41Sopenharmony_ci StringPrototypeToLowerCase(e), 2911cb0ef41Sopenharmony_ci '_', 2921cb0ef41Sopenharmony_ci '-', 2931cb0ef41Sopenharmony_ci )), 2941cb0ef41Sopenharmony_ci '--use-strict'); 2951cb0ef41Sopenharmony_ci } 2961cb0ef41Sopenharmony_ci 2971cb0ef41Sopenharmony_ci // This returns a code preview for arbitrary input code. 2981cb0ef41Sopenharmony_ci function getInputPreview(input, callback) { 2991cb0ef41Sopenharmony_ci // For similar reasons as `defaultEval`, wrap expressions starting with a 3001cb0ef41Sopenharmony_ci // curly brace with parenthesis. 3011cb0ef41Sopenharmony_ci if (StringPrototypeStartsWith(input, '{') && 3021cb0ef41Sopenharmony_ci !StringPrototypeEndsWith(input, ';') && !wrapped) { 3031cb0ef41Sopenharmony_ci input = `(${input})`; 3041cb0ef41Sopenharmony_ci wrapped = true; 3051cb0ef41Sopenharmony_ci } 3061cb0ef41Sopenharmony_ci sendInspectorCommand((session) => { 3071cb0ef41Sopenharmony_ci session.post('Runtime.evaluate', { 3081cb0ef41Sopenharmony_ci expression: input, 3091cb0ef41Sopenharmony_ci throwOnSideEffect: true, 3101cb0ef41Sopenharmony_ci timeout: 333, 3111cb0ef41Sopenharmony_ci contextId: repl[contextSymbol], 3121cb0ef41Sopenharmony_ci }, (error, preview) => { 3131cb0ef41Sopenharmony_ci if (error) { 3141cb0ef41Sopenharmony_ci callback(error); 3151cb0ef41Sopenharmony_ci return; 3161cb0ef41Sopenharmony_ci } 3171cb0ef41Sopenharmony_ci const { result } = preview; 3181cb0ef41Sopenharmony_ci if (result.value !== undefined) { 3191cb0ef41Sopenharmony_ci callback(null, inspect(result.value, previewOptions)); 3201cb0ef41Sopenharmony_ci // Ignore EvalErrors, SyntaxErrors and ReferenceErrors. It is not clear 3211cb0ef41Sopenharmony_ci // where they came from and if they are recoverable or not. Other errors 3221cb0ef41Sopenharmony_ci // may be inspected. 3231cb0ef41Sopenharmony_ci } else if (preview.exceptionDetails && 3241cb0ef41Sopenharmony_ci (result.className === 'EvalError' || 3251cb0ef41Sopenharmony_ci result.className === 'SyntaxError' || 3261cb0ef41Sopenharmony_ci // Report ReferenceError in case the strict mode is active 3271cb0ef41Sopenharmony_ci // for input that has no completions. 3281cb0ef41Sopenharmony_ci (result.className === 'ReferenceError' && 3291cb0ef41Sopenharmony_ci (hasCompletions || !isInStrictMode(repl))))) { 3301cb0ef41Sopenharmony_ci callback(null, null); 3311cb0ef41Sopenharmony_ci } else if (result.objectId) { 3321cb0ef41Sopenharmony_ci // The writer options might change and have influence on the inspect 3331cb0ef41Sopenharmony_ci // output. The user might change e.g., `showProxy`, `getters` or 3341cb0ef41Sopenharmony_ci // `showHidden`. Use `inspect` instead of `JSON.stringify` to keep 3351cb0ef41Sopenharmony_ci // `Infinity` and similar intact. 3361cb0ef41Sopenharmony_ci const inspectOptions = inspect({ 3371cb0ef41Sopenharmony_ci ...repl.writer.options, 3381cb0ef41Sopenharmony_ci colors: false, 3391cb0ef41Sopenharmony_ci depth: 1, 3401cb0ef41Sopenharmony_ci compact: true, 3411cb0ef41Sopenharmony_ci breakLength: Infinity, 3421cb0ef41Sopenharmony_ci }, previewOptions); 3431cb0ef41Sopenharmony_ci session.post('Runtime.callFunctionOn', { 3441cb0ef41Sopenharmony_ci functionDeclaration: 3451cb0ef41Sopenharmony_ci `(v) => 3461cb0ef41Sopenharmony_ci Reflect 3471cb0ef41Sopenharmony_ci .getOwnPropertyDescriptor(globalThis, 'util') 3481cb0ef41Sopenharmony_ci .get().inspect(v, ${inspectOptions})`, 3491cb0ef41Sopenharmony_ci objectId: result.objectId, 3501cb0ef41Sopenharmony_ci arguments: [result], 3511cb0ef41Sopenharmony_ci }, (error, preview) => { 3521cb0ef41Sopenharmony_ci if (error) { 3531cb0ef41Sopenharmony_ci callback(error); 3541cb0ef41Sopenharmony_ci } else { 3551cb0ef41Sopenharmony_ci callback(null, preview.result.value); 3561cb0ef41Sopenharmony_ci } 3571cb0ef41Sopenharmony_ci }); 3581cb0ef41Sopenharmony_ci } else { 3591cb0ef41Sopenharmony_ci // Either not serializable or undefined. 3601cb0ef41Sopenharmony_ci callback(null, result.unserializableValue || result.type); 3611cb0ef41Sopenharmony_ci } 3621cb0ef41Sopenharmony_ci }); 3631cb0ef41Sopenharmony_ci }, () => callback(new ERR_INSPECTOR_NOT_AVAILABLE())); 3641cb0ef41Sopenharmony_ci } 3651cb0ef41Sopenharmony_ci 3661cb0ef41Sopenharmony_ci const showPreview = (showCompletion = true) => { 3671cb0ef41Sopenharmony_ci // Prevent duplicated previews after a refresh. 3681cb0ef41Sopenharmony_ci if (inputPreview !== null || !repl.isCompletionEnabled) { 3691cb0ef41Sopenharmony_ci return; 3701cb0ef41Sopenharmony_ci } 3711cb0ef41Sopenharmony_ci 3721cb0ef41Sopenharmony_ci const line = StringPrototypeTrim(repl.line); 3731cb0ef41Sopenharmony_ci 3741cb0ef41Sopenharmony_ci // Do not preview in case the line only contains whitespace. 3751cb0ef41Sopenharmony_ci if (line === '') { 3761cb0ef41Sopenharmony_ci return; 3771cb0ef41Sopenharmony_ci } 3781cb0ef41Sopenharmony_ci 3791cb0ef41Sopenharmony_ci hasCompletions = false; 3801cb0ef41Sopenharmony_ci 3811cb0ef41Sopenharmony_ci // Add the autocompletion preview. 3821cb0ef41Sopenharmony_ci if (showCompletion) { 3831cb0ef41Sopenharmony_ci const insertPreview = false; 3841cb0ef41Sopenharmony_ci showCompletionPreview(repl.line, insertPreview); 3851cb0ef41Sopenharmony_ci } 3861cb0ef41Sopenharmony_ci 3871cb0ef41Sopenharmony_ci // Do not preview if the command is buffered. 3881cb0ef41Sopenharmony_ci if (repl[bufferSymbol]) { 3891cb0ef41Sopenharmony_ci return; 3901cb0ef41Sopenharmony_ci } 3911cb0ef41Sopenharmony_ci 3921cb0ef41Sopenharmony_ci const inputPreviewCallback = (error, inspected) => { 3931cb0ef41Sopenharmony_ci if (inspected == null) { 3941cb0ef41Sopenharmony_ci return; 3951cb0ef41Sopenharmony_ci } 3961cb0ef41Sopenharmony_ci 3971cb0ef41Sopenharmony_ci wrapped = false; 3981cb0ef41Sopenharmony_ci 3991cb0ef41Sopenharmony_ci // Ignore the output if the value is identical to the current line. 4001cb0ef41Sopenharmony_ci if (line === inspected) { 4011cb0ef41Sopenharmony_ci return; 4021cb0ef41Sopenharmony_ci } 4031cb0ef41Sopenharmony_ci 4041cb0ef41Sopenharmony_ci if (error) { 4051cb0ef41Sopenharmony_ci debug('Error while generating preview', error); 4061cb0ef41Sopenharmony_ci return; 4071cb0ef41Sopenharmony_ci } 4081cb0ef41Sopenharmony_ci // Do not preview `undefined` if colors are deactivated or explicitly 4091cb0ef41Sopenharmony_ci // requested. 4101cb0ef41Sopenharmony_ci if (inspected === 'undefined' && 4111cb0ef41Sopenharmony_ci (!repl.useColors || repl.ignoreUndefined)) { 4121cb0ef41Sopenharmony_ci return; 4131cb0ef41Sopenharmony_ci } 4141cb0ef41Sopenharmony_ci 4151cb0ef41Sopenharmony_ci inputPreview = inspected; 4161cb0ef41Sopenharmony_ci 4171cb0ef41Sopenharmony_ci // Limit the output to maximum 250 characters. Otherwise it becomes a) 4181cb0ef41Sopenharmony_ci // difficult to read and b) non terminal REPLs would visualize the whole 4191cb0ef41Sopenharmony_ci // output. 4201cb0ef41Sopenharmony_ci let maxColumns = MathMin(repl.columns, 250); 4211cb0ef41Sopenharmony_ci 4221cb0ef41Sopenharmony_ci // Support unicode characters of width other than one by checking the 4231cb0ef41Sopenharmony_ci // actual width. 4241cb0ef41Sopenharmony_ci if (inspected.length * 2 >= maxColumns && 4251cb0ef41Sopenharmony_ci getStringWidth(inspected) > maxColumns) { 4261cb0ef41Sopenharmony_ci maxColumns -= 4 + (repl.useColors ? 0 : 3); 4271cb0ef41Sopenharmony_ci let res = ''; 4281cb0ef41Sopenharmony_ci for (const char of new SafeStringIterator(inspected)) { 4291cb0ef41Sopenharmony_ci maxColumns -= getStringWidth(char); 4301cb0ef41Sopenharmony_ci if (maxColumns < 0) 4311cb0ef41Sopenharmony_ci break; 4321cb0ef41Sopenharmony_ci res += char; 4331cb0ef41Sopenharmony_ci } 4341cb0ef41Sopenharmony_ci inspected = `${res}...`; 4351cb0ef41Sopenharmony_ci } 4361cb0ef41Sopenharmony_ci 4371cb0ef41Sopenharmony_ci // Line breaks are very rare and probably only occur in case of error 4381cb0ef41Sopenharmony_ci // messages with line breaks. 4391cb0ef41Sopenharmony_ci const lineBreakPos = StringPrototypeIndexOf(inspected, '\n'); 4401cb0ef41Sopenharmony_ci if (lineBreakPos !== -1) { 4411cb0ef41Sopenharmony_ci inspected = `${StringPrototypeSlice(inspected, 0, lineBreakPos)}`; 4421cb0ef41Sopenharmony_ci } 4431cb0ef41Sopenharmony_ci 4441cb0ef41Sopenharmony_ci const result = repl.useColors ? 4451cb0ef41Sopenharmony_ci `\u001b[90m${inspected}\u001b[39m` : 4461cb0ef41Sopenharmony_ci `// ${inspected}`; 4471cb0ef41Sopenharmony_ci 4481cb0ef41Sopenharmony_ci const { cursorPos, displayPos } = getPreviewPos(); 4491cb0ef41Sopenharmony_ci const rows = displayPos.rows - cursorPos.rows; 4501cb0ef41Sopenharmony_ci moveCursor(repl.output, 0, rows); 4511cb0ef41Sopenharmony_ci repl.output.write(`\n${result}`); 4521cb0ef41Sopenharmony_ci cursorTo(repl.output, cursorPos.cols); 4531cb0ef41Sopenharmony_ci moveCursor(repl.output, 0, -rows - 1); 4541cb0ef41Sopenharmony_ci }; 4551cb0ef41Sopenharmony_ci 4561cb0ef41Sopenharmony_ci let previewLine = line; 4571cb0ef41Sopenharmony_ci 4581cb0ef41Sopenharmony_ci if (completionPreview !== null && 4591cb0ef41Sopenharmony_ci isCursorAtInputEnd() && 4601cb0ef41Sopenharmony_ci escaped !== repl.line) { 4611cb0ef41Sopenharmony_ci previewLine += completionPreview; 4621cb0ef41Sopenharmony_ci } 4631cb0ef41Sopenharmony_ci 4641cb0ef41Sopenharmony_ci getInputPreview(previewLine, inputPreviewCallback); 4651cb0ef41Sopenharmony_ci if (wrapped) { 4661cb0ef41Sopenharmony_ci getInputPreview(previewLine, inputPreviewCallback); 4671cb0ef41Sopenharmony_ci } 4681cb0ef41Sopenharmony_ci wrapped = false; 4691cb0ef41Sopenharmony_ci }; 4701cb0ef41Sopenharmony_ci 4711cb0ef41Sopenharmony_ci // -------------------------------------------------------------------------// 4721cb0ef41Sopenharmony_ci // Replace multiple interface functions. This is required to fully support // 4731cb0ef41Sopenharmony_ci // previews without changing readlines behavior. // 4741cb0ef41Sopenharmony_ci // -------------------------------------------------------------------------// 4751cb0ef41Sopenharmony_ci 4761cb0ef41Sopenharmony_ci // Refresh prints the whole screen again and the preview will be removed 4771cb0ef41Sopenharmony_ci // during that procedure. Print the preview again. This also makes sure 4781cb0ef41Sopenharmony_ci // the preview is always correct after resizing the terminal window. 4791cb0ef41Sopenharmony_ci const originalRefresh = FunctionPrototypeBind(repl._refreshLine, repl); 4801cb0ef41Sopenharmony_ci repl._refreshLine = () => { 4811cb0ef41Sopenharmony_ci inputPreview = null; 4821cb0ef41Sopenharmony_ci originalRefresh(); 4831cb0ef41Sopenharmony_ci showPreview(); 4841cb0ef41Sopenharmony_ci }; 4851cb0ef41Sopenharmony_ci 4861cb0ef41Sopenharmony_ci let insertCompletionPreview = true; 4871cb0ef41Sopenharmony_ci // Insert the longest common suffix of the current input in case the user 4881cb0ef41Sopenharmony_ci // moves to the right while already being at the current input end. 4891cb0ef41Sopenharmony_ci const originalMoveCursor = FunctionPrototypeBind(repl._moveCursor, repl); 4901cb0ef41Sopenharmony_ci repl._moveCursor = (dx) => { 4911cb0ef41Sopenharmony_ci const currentCursor = repl.cursor; 4921cb0ef41Sopenharmony_ci originalMoveCursor(dx); 4931cb0ef41Sopenharmony_ci if (currentCursor + dx > repl.line.length && 4941cb0ef41Sopenharmony_ci typeof repl.completer === 'function' && 4951cb0ef41Sopenharmony_ci insertCompletionPreview) { 4961cb0ef41Sopenharmony_ci const insertPreview = true; 4971cb0ef41Sopenharmony_ci showCompletionPreview(repl.line, insertPreview); 4981cb0ef41Sopenharmony_ci } 4991cb0ef41Sopenharmony_ci }; 5001cb0ef41Sopenharmony_ci 5011cb0ef41Sopenharmony_ci // This is the only function that interferes with the completion insertion. 5021cb0ef41Sopenharmony_ci // Monkey patch it to prevent inserting the completion when it shouldn't be. 5031cb0ef41Sopenharmony_ci const originalClearLine = FunctionPrototypeBind(repl.clearLine, repl); 5041cb0ef41Sopenharmony_ci repl.clearLine = () => { 5051cb0ef41Sopenharmony_ci insertCompletionPreview = false; 5061cb0ef41Sopenharmony_ci originalClearLine(); 5071cb0ef41Sopenharmony_ci insertCompletionPreview = true; 5081cb0ef41Sopenharmony_ci }; 5091cb0ef41Sopenharmony_ci 5101cb0ef41Sopenharmony_ci return { showPreview, clearPreview }; 5111cb0ef41Sopenharmony_ci} 5121cb0ef41Sopenharmony_ci 5131cb0ef41Sopenharmony_cifunction setupReverseSearch(repl) { 5141cb0ef41Sopenharmony_ci // Simple terminals can't use reverse search. 5151cb0ef41Sopenharmony_ci if (process.env.TERM === 'dumb') { 5161cb0ef41Sopenharmony_ci return { reverseSearch() { return false; } }; 5171cb0ef41Sopenharmony_ci } 5181cb0ef41Sopenharmony_ci 5191cb0ef41Sopenharmony_ci const alreadyMatched = new SafeSet(); 5201cb0ef41Sopenharmony_ci const labels = { 5211cb0ef41Sopenharmony_ci r: 'bck-i-search: ', 5221cb0ef41Sopenharmony_ci s: 'fwd-i-search: ', 5231cb0ef41Sopenharmony_ci }; 5241cb0ef41Sopenharmony_ci let isInReverseSearch = false; 5251cb0ef41Sopenharmony_ci let historyIndex = -1; 5261cb0ef41Sopenharmony_ci let input = ''; 5271cb0ef41Sopenharmony_ci let cursor = -1; 5281cb0ef41Sopenharmony_ci let dir = 'r'; 5291cb0ef41Sopenharmony_ci let lastMatch = -1; 5301cb0ef41Sopenharmony_ci let lastCursor = -1; 5311cb0ef41Sopenharmony_ci let promptPos; 5321cb0ef41Sopenharmony_ci 5331cb0ef41Sopenharmony_ci function checkAndSetDirectionKey(keyName) { 5341cb0ef41Sopenharmony_ci if (!labels[keyName]) { 5351cb0ef41Sopenharmony_ci return false; 5361cb0ef41Sopenharmony_ci } 5371cb0ef41Sopenharmony_ci if (dir !== keyName) { 5381cb0ef41Sopenharmony_ci // Reset the already matched set in case the direction is changed. That 5391cb0ef41Sopenharmony_ci // way it's possible to find those entries again. 5401cb0ef41Sopenharmony_ci alreadyMatched.clear(); 5411cb0ef41Sopenharmony_ci dir = keyName; 5421cb0ef41Sopenharmony_ci } 5431cb0ef41Sopenharmony_ci return true; 5441cb0ef41Sopenharmony_ci } 5451cb0ef41Sopenharmony_ci 5461cb0ef41Sopenharmony_ci function goToNextHistoryIndex() { 5471cb0ef41Sopenharmony_ci // Ignore this entry for further searches and continue to the next 5481cb0ef41Sopenharmony_ci // history entry. 5491cb0ef41Sopenharmony_ci alreadyMatched.add(repl.history[historyIndex]); 5501cb0ef41Sopenharmony_ci historyIndex += dir === 'r' ? 1 : -1; 5511cb0ef41Sopenharmony_ci cursor = -1; 5521cb0ef41Sopenharmony_ci } 5531cb0ef41Sopenharmony_ci 5541cb0ef41Sopenharmony_ci function search() { 5551cb0ef41Sopenharmony_ci // Just print an empty line in case the user removed the search parameter. 5561cb0ef41Sopenharmony_ci if (input === '') { 5571cb0ef41Sopenharmony_ci print(repl.line, `${labels[dir]}_`); 5581cb0ef41Sopenharmony_ci return; 5591cb0ef41Sopenharmony_ci } 5601cb0ef41Sopenharmony_ci // Fix the bounds in case the direction has changed in the meanwhile. 5611cb0ef41Sopenharmony_ci if (dir === 'r') { 5621cb0ef41Sopenharmony_ci if (historyIndex < 0) { 5631cb0ef41Sopenharmony_ci historyIndex = 0; 5641cb0ef41Sopenharmony_ci } 5651cb0ef41Sopenharmony_ci } else if (historyIndex >= repl.history.length) { 5661cb0ef41Sopenharmony_ci historyIndex = repl.history.length - 1; 5671cb0ef41Sopenharmony_ci } 5681cb0ef41Sopenharmony_ci // Check the history entries until a match is found. 5691cb0ef41Sopenharmony_ci while (historyIndex >= 0 && historyIndex < repl.history.length) { 5701cb0ef41Sopenharmony_ci let entry = repl.history[historyIndex]; 5711cb0ef41Sopenharmony_ci // Visualize all potential matches only once. 5721cb0ef41Sopenharmony_ci if (alreadyMatched.has(entry)) { 5731cb0ef41Sopenharmony_ci historyIndex += dir === 'r' ? 1 : -1; 5741cb0ef41Sopenharmony_ci continue; 5751cb0ef41Sopenharmony_ci } 5761cb0ef41Sopenharmony_ci // Match the next entry either from the start or from the end, depending 5771cb0ef41Sopenharmony_ci // on the current direction. 5781cb0ef41Sopenharmony_ci if (dir === 'r') { 5791cb0ef41Sopenharmony_ci // Update the cursor in case it's necessary. 5801cb0ef41Sopenharmony_ci if (cursor === -1) { 5811cb0ef41Sopenharmony_ci cursor = entry.length; 5821cb0ef41Sopenharmony_ci } 5831cb0ef41Sopenharmony_ci cursor = StringPrototypeLastIndexOf(entry, input, cursor - 1); 5841cb0ef41Sopenharmony_ci } else { 5851cb0ef41Sopenharmony_ci cursor = StringPrototypeIndexOf(entry, input, cursor + 1); 5861cb0ef41Sopenharmony_ci } 5871cb0ef41Sopenharmony_ci // Match not found. 5881cb0ef41Sopenharmony_ci if (cursor === -1) { 5891cb0ef41Sopenharmony_ci goToNextHistoryIndex(); 5901cb0ef41Sopenharmony_ci // Match found. 5911cb0ef41Sopenharmony_ci } else { 5921cb0ef41Sopenharmony_ci if (repl.useColors) { 5931cb0ef41Sopenharmony_ci const start = StringPrototypeSlice(entry, 0, cursor); 5941cb0ef41Sopenharmony_ci const end = StringPrototypeSlice(entry, cursor + input.length); 5951cb0ef41Sopenharmony_ci entry = `${start}\x1B[4m${input}\x1B[24m${end}`; 5961cb0ef41Sopenharmony_ci } 5971cb0ef41Sopenharmony_ci print(entry, `${labels[dir]}${input}_`, cursor); 5981cb0ef41Sopenharmony_ci lastMatch = historyIndex; 5991cb0ef41Sopenharmony_ci lastCursor = cursor; 6001cb0ef41Sopenharmony_ci // Explicitly go to the next history item in case no further matches are 6011cb0ef41Sopenharmony_ci // possible with the current entry. 6021cb0ef41Sopenharmony_ci if ((dir === 'r' && cursor === 0) || 6031cb0ef41Sopenharmony_ci (dir === 's' && entry.length === cursor + input.length)) { 6041cb0ef41Sopenharmony_ci goToNextHistoryIndex(); 6051cb0ef41Sopenharmony_ci } 6061cb0ef41Sopenharmony_ci return; 6071cb0ef41Sopenharmony_ci } 6081cb0ef41Sopenharmony_ci } 6091cb0ef41Sopenharmony_ci print(repl.line, `failed-${labels[dir]}${input}_`); 6101cb0ef41Sopenharmony_ci } 6111cb0ef41Sopenharmony_ci 6121cb0ef41Sopenharmony_ci function print(outputLine, inputLine, cursor = repl.cursor) { 6131cb0ef41Sopenharmony_ci // TODO(BridgeAR): Resizing the terminal window hides the overlay. To fix 6141cb0ef41Sopenharmony_ci // that, readline must be aware of this information. It's probably best to 6151cb0ef41Sopenharmony_ci // add a couple of properties to readline that allow to do the following: 6161cb0ef41Sopenharmony_ci // 1. Add arbitrary data to the end of the current line while not counting 6171cb0ef41Sopenharmony_ci // towards the line. This would be useful for the completion previews. 6181cb0ef41Sopenharmony_ci // 2. Add arbitrary extra lines that do not count towards the regular line. 6191cb0ef41Sopenharmony_ci // This would be useful for both, the input preview and the reverse 6201cb0ef41Sopenharmony_ci // search. It might be combined with the first part? 6211cb0ef41Sopenharmony_ci // 3. Add arbitrary input that is "on top" of the current line. That is 6221cb0ef41Sopenharmony_ci // useful for the reverse search. 6231cb0ef41Sopenharmony_ci // 4. To trigger the line refresh, functions should be used to pass through 6241cb0ef41Sopenharmony_ci // the information. Alternatively, getters and setters could be used. 6251cb0ef41Sopenharmony_ci // That might even be more elegant. 6261cb0ef41Sopenharmony_ci // The data would then be accounted for when calling `_refreshLine()`. 6271cb0ef41Sopenharmony_ci // This function would then look similar to: 6281cb0ef41Sopenharmony_ci // repl.overlay(outputLine); 6291cb0ef41Sopenharmony_ci // repl.addTrailingLine(inputLine); 6301cb0ef41Sopenharmony_ci // repl.setCursor(cursor); 6311cb0ef41Sopenharmony_ci // More potential improvements: use something similar to stream.cork(). 6321cb0ef41Sopenharmony_ci // Multiple cursor moves on the same tick could be prevented in case all 6331cb0ef41Sopenharmony_ci // writes from the same tick are combined and the cursor is moved at the 6341cb0ef41Sopenharmony_ci // tick end instead of after each operation. 6351cb0ef41Sopenharmony_ci let rows = 0; 6361cb0ef41Sopenharmony_ci if (lastMatch !== -1) { 6371cb0ef41Sopenharmony_ci const line = StringPrototypeSlice(repl.history[lastMatch], 0, lastCursor); 6381cb0ef41Sopenharmony_ci rows = repl._getDisplayPos(`${repl.getPrompt()}${line}`).rows; 6391cb0ef41Sopenharmony_ci cursorTo(repl.output, promptPos.cols); 6401cb0ef41Sopenharmony_ci } else if (isInReverseSearch && repl.line !== '') { 6411cb0ef41Sopenharmony_ci rows = repl.getCursorPos().rows; 6421cb0ef41Sopenharmony_ci cursorTo(repl.output, promptPos.cols); 6431cb0ef41Sopenharmony_ci } 6441cb0ef41Sopenharmony_ci if (rows !== 0) 6451cb0ef41Sopenharmony_ci moveCursor(repl.output, 0, -rows); 6461cb0ef41Sopenharmony_ci 6471cb0ef41Sopenharmony_ci if (isInReverseSearch) { 6481cb0ef41Sopenharmony_ci clearScreenDown(repl.output); 6491cb0ef41Sopenharmony_ci repl.output.write(`${outputLine}\n${inputLine}`); 6501cb0ef41Sopenharmony_ci } else { 6511cb0ef41Sopenharmony_ci repl.output.write(`\n${inputLine}`); 6521cb0ef41Sopenharmony_ci } 6531cb0ef41Sopenharmony_ci 6541cb0ef41Sopenharmony_ci lastMatch = -1; 6551cb0ef41Sopenharmony_ci 6561cb0ef41Sopenharmony_ci // To know exactly how many rows we have to move the cursor back we need the 6571cb0ef41Sopenharmony_ci // cursor rows, the output rows and the input rows. 6581cb0ef41Sopenharmony_ci const prompt = repl.getPrompt(); 6591cb0ef41Sopenharmony_ci const cursorLine = prompt + StringPrototypeSlice(outputLine, 0, cursor); 6601cb0ef41Sopenharmony_ci const cursorPos = repl._getDisplayPos(cursorLine); 6611cb0ef41Sopenharmony_ci const outputPos = repl._getDisplayPos(`${prompt}${outputLine}`); 6621cb0ef41Sopenharmony_ci const inputPos = repl._getDisplayPos(inputLine); 6631cb0ef41Sopenharmony_ci const inputRows = inputPos.rows - (inputPos.cols === 0 ? 1 : 0); 6641cb0ef41Sopenharmony_ci 6651cb0ef41Sopenharmony_ci rows = -1 - inputRows - (outputPos.rows - cursorPos.rows); 6661cb0ef41Sopenharmony_ci 6671cb0ef41Sopenharmony_ci moveCursor(repl.output, 0, rows); 6681cb0ef41Sopenharmony_ci cursorTo(repl.output, cursorPos.cols); 6691cb0ef41Sopenharmony_ci } 6701cb0ef41Sopenharmony_ci 6711cb0ef41Sopenharmony_ci function reset(string) { 6721cb0ef41Sopenharmony_ci isInReverseSearch = string !== undefined; 6731cb0ef41Sopenharmony_ci 6741cb0ef41Sopenharmony_ci // In case the reverse search ends and a history entry is found, reset the 6751cb0ef41Sopenharmony_ci // line to the found entry. 6761cb0ef41Sopenharmony_ci if (!isInReverseSearch) { 6771cb0ef41Sopenharmony_ci if (lastMatch !== -1) { 6781cb0ef41Sopenharmony_ci repl.line = repl.history[lastMatch]; 6791cb0ef41Sopenharmony_ci repl.cursor = lastCursor; 6801cb0ef41Sopenharmony_ci repl.historyIndex = lastMatch; 6811cb0ef41Sopenharmony_ci } 6821cb0ef41Sopenharmony_ci 6831cb0ef41Sopenharmony_ci lastMatch = -1; 6841cb0ef41Sopenharmony_ci 6851cb0ef41Sopenharmony_ci // Clear screen and write the current repl.line before exiting. 6861cb0ef41Sopenharmony_ci cursorTo(repl.output, promptPos.cols); 6871cb0ef41Sopenharmony_ci moveCursor(repl.output, 0, promptPos.rows); 6881cb0ef41Sopenharmony_ci clearScreenDown(repl.output); 6891cb0ef41Sopenharmony_ci if (repl.line !== '') { 6901cb0ef41Sopenharmony_ci repl.output.write(repl.line); 6911cb0ef41Sopenharmony_ci if (repl.line.length !== repl.cursor) { 6921cb0ef41Sopenharmony_ci const { cols, rows } = repl.getCursorPos(); 6931cb0ef41Sopenharmony_ci cursorTo(repl.output, cols); 6941cb0ef41Sopenharmony_ci moveCursor(repl.output, 0, rows); 6951cb0ef41Sopenharmony_ci } 6961cb0ef41Sopenharmony_ci } 6971cb0ef41Sopenharmony_ci } 6981cb0ef41Sopenharmony_ci 6991cb0ef41Sopenharmony_ci input = string || ''; 7001cb0ef41Sopenharmony_ci cursor = -1; 7011cb0ef41Sopenharmony_ci historyIndex = repl.historyIndex; 7021cb0ef41Sopenharmony_ci alreadyMatched.clear(); 7031cb0ef41Sopenharmony_ci } 7041cb0ef41Sopenharmony_ci 7051cb0ef41Sopenharmony_ci function reverseSearch(string, key) { 7061cb0ef41Sopenharmony_ci if (!isInReverseSearch) { 7071cb0ef41Sopenharmony_ci if (key.ctrl && checkAndSetDirectionKey(key.name)) { 7081cb0ef41Sopenharmony_ci historyIndex = repl.historyIndex; 7091cb0ef41Sopenharmony_ci promptPos = repl._getDisplayPos(`${repl.getPrompt()}`); 7101cb0ef41Sopenharmony_ci print(repl.line, `${labels[dir]}_`); 7111cb0ef41Sopenharmony_ci isInReverseSearch = true; 7121cb0ef41Sopenharmony_ci } 7131cb0ef41Sopenharmony_ci } else if (key.ctrl && checkAndSetDirectionKey(key.name)) { 7141cb0ef41Sopenharmony_ci search(); 7151cb0ef41Sopenharmony_ci } else if (key.name === 'backspace' || 7161cb0ef41Sopenharmony_ci (key.ctrl && (key.name === 'h' || key.name === 'w'))) { 7171cb0ef41Sopenharmony_ci reset(StringPrototypeSlice(input, 0, input.length - 1)); 7181cb0ef41Sopenharmony_ci search(); 7191cb0ef41Sopenharmony_ci // Special handle <ctrl> + c and escape. Those should only cancel the 7201cb0ef41Sopenharmony_ci // reverse search. The original line is visible afterwards again. 7211cb0ef41Sopenharmony_ci } else if ((key.ctrl && key.name === 'c') || key.name === 'escape') { 7221cb0ef41Sopenharmony_ci lastMatch = -1; 7231cb0ef41Sopenharmony_ci reset(); 7241cb0ef41Sopenharmony_ci return true; 7251cb0ef41Sopenharmony_ci // End search in case either enter is pressed or if any non-reverse-search 7261cb0ef41Sopenharmony_ci // key (combination) is pressed. 7271cb0ef41Sopenharmony_ci } else if (key.ctrl || 7281cb0ef41Sopenharmony_ci key.meta || 7291cb0ef41Sopenharmony_ci key.name === 'return' || 7301cb0ef41Sopenharmony_ci key.name === 'enter' || 7311cb0ef41Sopenharmony_ci typeof string !== 'string' || 7321cb0ef41Sopenharmony_ci string === '') { 7331cb0ef41Sopenharmony_ci reset(); 7341cb0ef41Sopenharmony_ci repl[kSubstringSearch] = ''; 7351cb0ef41Sopenharmony_ci } else { 7361cb0ef41Sopenharmony_ci reset(`${input}${string}`); 7371cb0ef41Sopenharmony_ci search(); 7381cb0ef41Sopenharmony_ci } 7391cb0ef41Sopenharmony_ci return isInReverseSearch; 7401cb0ef41Sopenharmony_ci } 7411cb0ef41Sopenharmony_ci 7421cb0ef41Sopenharmony_ci return { reverseSearch }; 7431cb0ef41Sopenharmony_ci} 7441cb0ef41Sopenharmony_ci 7451cb0ef41Sopenharmony_cimodule.exports = { 7461cb0ef41Sopenharmony_ci REPL_MODE_SLOPPY: Symbol('repl-sloppy'), 7471cb0ef41Sopenharmony_ci REPL_MODE_STRICT, 7481cb0ef41Sopenharmony_ci isRecoverableError, 7491cb0ef41Sopenharmony_ci kStandaloneREPL: Symbol('kStandaloneREPL'), 7501cb0ef41Sopenharmony_ci setupPreview, 7511cb0ef41Sopenharmony_ci setupReverseSearch, 7521cb0ef41Sopenharmony_ci}; 753