11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ciconst { 41cb0ef41Sopenharmony_ci ArrayFrom, 51cb0ef41Sopenharmony_ci ArrayPrototypeFilter, 61cb0ef41Sopenharmony_ci ArrayPrototypeIndexOf, 71cb0ef41Sopenharmony_ci ArrayPrototypeJoin, 81cb0ef41Sopenharmony_ci ArrayPrototypeMap, 91cb0ef41Sopenharmony_ci ArrayPrototypePop, 101cb0ef41Sopenharmony_ci ArrayPrototypePush, 111cb0ef41Sopenharmony_ci ArrayPrototypeReverse, 121cb0ef41Sopenharmony_ci ArrayPrototypeSplice, 131cb0ef41Sopenharmony_ci ArrayPrototypeShift, 141cb0ef41Sopenharmony_ci ArrayPrototypeUnshift, 151cb0ef41Sopenharmony_ci DateNow, 161cb0ef41Sopenharmony_ci FunctionPrototypeCall, 171cb0ef41Sopenharmony_ci MathCeil, 181cb0ef41Sopenharmony_ci MathFloor, 191cb0ef41Sopenharmony_ci MathMax, 201cb0ef41Sopenharmony_ci MathMaxApply, 211cb0ef41Sopenharmony_ci NumberIsFinite, 221cb0ef41Sopenharmony_ci NumberIsNaN, 231cb0ef41Sopenharmony_ci ObjectSetPrototypeOf, 241cb0ef41Sopenharmony_ci RegExpPrototypeExec, 251cb0ef41Sopenharmony_ci StringPrototypeCodePointAt, 261cb0ef41Sopenharmony_ci StringPrototypeEndsWith, 271cb0ef41Sopenharmony_ci StringPrototypeRepeat, 281cb0ef41Sopenharmony_ci StringPrototypeSlice, 291cb0ef41Sopenharmony_ci StringPrototypeStartsWith, 301cb0ef41Sopenharmony_ci StringPrototypeTrim, 311cb0ef41Sopenharmony_ci Symbol, 321cb0ef41Sopenharmony_ci SymbolDispose, 331cb0ef41Sopenharmony_ci SymbolAsyncIterator, 341cb0ef41Sopenharmony_ci SafeStringIterator, 351cb0ef41Sopenharmony_ci} = primordials; 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ciconst { codes } = require('internal/errors'); 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_ciconst { 401cb0ef41Sopenharmony_ci ERR_INVALID_ARG_VALUE, 411cb0ef41Sopenharmony_ci ERR_USE_AFTER_CLOSE, 421cb0ef41Sopenharmony_ci} = codes; 431cb0ef41Sopenharmony_ciconst { 441cb0ef41Sopenharmony_ci validateAbortSignal, 451cb0ef41Sopenharmony_ci validateArray, 461cb0ef41Sopenharmony_ci validateString, 471cb0ef41Sopenharmony_ci validateUint32, 481cb0ef41Sopenharmony_ci} = require('internal/validators'); 491cb0ef41Sopenharmony_ciconst { kEmptyObject } = require('internal/util'); 501cb0ef41Sopenharmony_ciconst { 511cb0ef41Sopenharmony_ci inspect, 521cb0ef41Sopenharmony_ci getStringWidth, 531cb0ef41Sopenharmony_ci stripVTControlCharacters, 541cb0ef41Sopenharmony_ci} = require('internal/util/inspect'); 551cb0ef41Sopenharmony_ciconst EventEmitter = require('events'); 561cb0ef41Sopenharmony_ciconst { 571cb0ef41Sopenharmony_ci charLengthAt, 581cb0ef41Sopenharmony_ci charLengthLeft, 591cb0ef41Sopenharmony_ci commonPrefix, 601cb0ef41Sopenharmony_ci kSubstringSearch, 611cb0ef41Sopenharmony_ci} = require('internal/readline/utils'); 621cb0ef41Sopenharmony_cilet emitKeypressEvents; 631cb0ef41Sopenharmony_ciconst { 641cb0ef41Sopenharmony_ci clearScreenDown, 651cb0ef41Sopenharmony_ci cursorTo, 661cb0ef41Sopenharmony_ci moveCursor, 671cb0ef41Sopenharmony_ci} = require('internal/readline/callbacks'); 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ciconst { StringDecoder } = require('string_decoder'); 701cb0ef41Sopenharmony_ci 711cb0ef41Sopenharmony_ci// Lazy load Readable for startup performance. 721cb0ef41Sopenharmony_cilet Readable; 731cb0ef41Sopenharmony_ci 741cb0ef41Sopenharmony_ciconst kHistorySize = 30; 751cb0ef41Sopenharmony_ciconst kMaxUndoRedoStackSize = 2048; 761cb0ef41Sopenharmony_ciconst kMincrlfDelay = 100; 771cb0ef41Sopenharmony_ci// \r\n, \n, or \r followed by something other than \n 781cb0ef41Sopenharmony_ciconst lineEnding = /\r?\n|\r(?!\n)/g; 791cb0ef41Sopenharmony_ci 801cb0ef41Sopenharmony_ciconst kLineObjectStream = Symbol('line object stream'); 811cb0ef41Sopenharmony_ciconst kQuestionCancel = Symbol('kQuestionCancel'); 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ci// GNU readline library - keyseq-timeout is 500ms (default) 841cb0ef41Sopenharmony_ciconst ESCAPE_CODE_TIMEOUT = 500; 851cb0ef41Sopenharmony_ci 861cb0ef41Sopenharmony_ci// Max length of the kill ring 871cb0ef41Sopenharmony_ciconst kMaxLengthOfKillRing = 32; 881cb0ef41Sopenharmony_ci 891cb0ef41Sopenharmony_ciconst kAddHistory = Symbol('_addHistory'); 901cb0ef41Sopenharmony_ciconst kBeforeEdit = Symbol('_beforeEdit'); 911cb0ef41Sopenharmony_ciconst kDecoder = Symbol('_decoder'); 921cb0ef41Sopenharmony_ciconst kDeleteLeft = Symbol('_deleteLeft'); 931cb0ef41Sopenharmony_ciconst kDeleteLineLeft = Symbol('_deleteLineLeft'); 941cb0ef41Sopenharmony_ciconst kDeleteLineRight = Symbol('_deleteLineRight'); 951cb0ef41Sopenharmony_ciconst kDeleteRight = Symbol('_deleteRight'); 961cb0ef41Sopenharmony_ciconst kDeleteWordLeft = Symbol('_deleteWordLeft'); 971cb0ef41Sopenharmony_ciconst kDeleteWordRight = Symbol('_deleteWordRight'); 981cb0ef41Sopenharmony_ciconst kGetDisplayPos = Symbol('_getDisplayPos'); 991cb0ef41Sopenharmony_ciconst kHistoryNext = Symbol('_historyNext'); 1001cb0ef41Sopenharmony_ciconst kHistoryPrev = Symbol('_historyPrev'); 1011cb0ef41Sopenharmony_ciconst kInsertString = Symbol('_insertString'); 1021cb0ef41Sopenharmony_ciconst kLine = Symbol('_line'); 1031cb0ef41Sopenharmony_ciconst kLine_buffer = Symbol('_line_buffer'); 1041cb0ef41Sopenharmony_ciconst kKillRing = Symbol('_killRing'); 1051cb0ef41Sopenharmony_ciconst kKillRingCursor = Symbol('_killRingCursor'); 1061cb0ef41Sopenharmony_ciconst kMoveCursor = Symbol('_moveCursor'); 1071cb0ef41Sopenharmony_ciconst kNormalWrite = Symbol('_normalWrite'); 1081cb0ef41Sopenharmony_ciconst kOldPrompt = Symbol('_oldPrompt'); 1091cb0ef41Sopenharmony_ciconst kOnLine = Symbol('_onLine'); 1101cb0ef41Sopenharmony_ciconst kPreviousKey = Symbol('_previousKey'); 1111cb0ef41Sopenharmony_ciconst kPrompt = Symbol('_prompt'); 1121cb0ef41Sopenharmony_ciconst kPushToKillRing = Symbol('_pushToKillRing'); 1131cb0ef41Sopenharmony_ciconst kPushToUndoStack = Symbol('_pushToUndoStack'); 1141cb0ef41Sopenharmony_ciconst kQuestionCallback = Symbol('_questionCallback'); 1151cb0ef41Sopenharmony_ciconst kRedo = Symbol('_redo'); 1161cb0ef41Sopenharmony_ciconst kRedoStack = Symbol('_redoStack'); 1171cb0ef41Sopenharmony_ciconst kRefreshLine = Symbol('_refreshLine'); 1181cb0ef41Sopenharmony_ciconst kSawKeyPress = Symbol('_sawKeyPress'); 1191cb0ef41Sopenharmony_ciconst kSawReturnAt = Symbol('_sawReturnAt'); 1201cb0ef41Sopenharmony_ciconst kSetRawMode = Symbol('_setRawMode'); 1211cb0ef41Sopenharmony_ciconst kTabComplete = Symbol('_tabComplete'); 1221cb0ef41Sopenharmony_ciconst kTabCompleter = Symbol('_tabCompleter'); 1231cb0ef41Sopenharmony_ciconst kTtyWrite = Symbol('_ttyWrite'); 1241cb0ef41Sopenharmony_ciconst kUndo = Symbol('_undo'); 1251cb0ef41Sopenharmony_ciconst kUndoStack = Symbol('_undoStack'); 1261cb0ef41Sopenharmony_ciconst kWordLeft = Symbol('_wordLeft'); 1271cb0ef41Sopenharmony_ciconst kWordRight = Symbol('_wordRight'); 1281cb0ef41Sopenharmony_ciconst kWriteToOutput = Symbol('_writeToOutput'); 1291cb0ef41Sopenharmony_ciconst kYank = Symbol('_yank'); 1301cb0ef41Sopenharmony_ciconst kYanking = Symbol('_yanking'); 1311cb0ef41Sopenharmony_ciconst kYankPop = Symbol('_yankPop'); 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_cifunction InterfaceConstructor(input, output, completer, terminal) { 1341cb0ef41Sopenharmony_ci this[kSawReturnAt] = 0; 1351cb0ef41Sopenharmony_ci // TODO(BridgeAR): Document this property. The name is not ideal, so we 1361cb0ef41Sopenharmony_ci // might want to expose an alias and document that instead. 1371cb0ef41Sopenharmony_ci this.isCompletionEnabled = true; 1381cb0ef41Sopenharmony_ci this[kSawKeyPress] = false; 1391cb0ef41Sopenharmony_ci this[kPreviousKey] = null; 1401cb0ef41Sopenharmony_ci this.escapeCodeTimeout = ESCAPE_CODE_TIMEOUT; 1411cb0ef41Sopenharmony_ci this.tabSize = 8; 1421cb0ef41Sopenharmony_ci 1431cb0ef41Sopenharmony_ci FunctionPrototypeCall(EventEmitter, this); 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_ci let history; 1461cb0ef41Sopenharmony_ci let historySize; 1471cb0ef41Sopenharmony_ci let removeHistoryDuplicates = false; 1481cb0ef41Sopenharmony_ci let crlfDelay; 1491cb0ef41Sopenharmony_ci let prompt = '> '; 1501cb0ef41Sopenharmony_ci let signal; 1511cb0ef41Sopenharmony_ci 1521cb0ef41Sopenharmony_ci if (input?.input) { 1531cb0ef41Sopenharmony_ci // An options object was given 1541cb0ef41Sopenharmony_ci output = input.output; 1551cb0ef41Sopenharmony_ci completer = input.completer; 1561cb0ef41Sopenharmony_ci terminal = input.terminal; 1571cb0ef41Sopenharmony_ci history = input.history; 1581cb0ef41Sopenharmony_ci historySize = input.historySize; 1591cb0ef41Sopenharmony_ci signal = input.signal; 1601cb0ef41Sopenharmony_ci if (input.tabSize !== undefined) { 1611cb0ef41Sopenharmony_ci validateUint32(input.tabSize, 'tabSize', true); 1621cb0ef41Sopenharmony_ci this.tabSize = input.tabSize; 1631cb0ef41Sopenharmony_ci } 1641cb0ef41Sopenharmony_ci removeHistoryDuplicates = input.removeHistoryDuplicates; 1651cb0ef41Sopenharmony_ci if (input.prompt !== undefined) { 1661cb0ef41Sopenharmony_ci prompt = input.prompt; 1671cb0ef41Sopenharmony_ci } 1681cb0ef41Sopenharmony_ci if (input.escapeCodeTimeout !== undefined) { 1691cb0ef41Sopenharmony_ci if (NumberIsFinite(input.escapeCodeTimeout)) { 1701cb0ef41Sopenharmony_ci this.escapeCodeTimeout = input.escapeCodeTimeout; 1711cb0ef41Sopenharmony_ci } else { 1721cb0ef41Sopenharmony_ci throw new ERR_INVALID_ARG_VALUE( 1731cb0ef41Sopenharmony_ci 'input.escapeCodeTimeout', 1741cb0ef41Sopenharmony_ci this.escapeCodeTimeout, 1751cb0ef41Sopenharmony_ci ); 1761cb0ef41Sopenharmony_ci } 1771cb0ef41Sopenharmony_ci } 1781cb0ef41Sopenharmony_ci 1791cb0ef41Sopenharmony_ci if (signal) { 1801cb0ef41Sopenharmony_ci validateAbortSignal(signal, 'options.signal'); 1811cb0ef41Sopenharmony_ci } 1821cb0ef41Sopenharmony_ci 1831cb0ef41Sopenharmony_ci crlfDelay = input.crlfDelay; 1841cb0ef41Sopenharmony_ci input = input.input; 1851cb0ef41Sopenharmony_ci } 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_ci if (completer !== undefined && typeof completer !== 'function') { 1881cb0ef41Sopenharmony_ci throw new ERR_INVALID_ARG_VALUE('completer', completer); 1891cb0ef41Sopenharmony_ci } 1901cb0ef41Sopenharmony_ci 1911cb0ef41Sopenharmony_ci if (history === undefined) { 1921cb0ef41Sopenharmony_ci history = []; 1931cb0ef41Sopenharmony_ci } else { 1941cb0ef41Sopenharmony_ci validateArray(history, 'history'); 1951cb0ef41Sopenharmony_ci } 1961cb0ef41Sopenharmony_ci 1971cb0ef41Sopenharmony_ci if (historySize === undefined) { 1981cb0ef41Sopenharmony_ci historySize = kHistorySize; 1991cb0ef41Sopenharmony_ci } 2001cb0ef41Sopenharmony_ci 2011cb0ef41Sopenharmony_ci if ( 2021cb0ef41Sopenharmony_ci typeof historySize !== 'number' || 2031cb0ef41Sopenharmony_ci NumberIsNaN(historySize) || 2041cb0ef41Sopenharmony_ci historySize < 0 2051cb0ef41Sopenharmony_ci ) { 2061cb0ef41Sopenharmony_ci throw new ERR_INVALID_ARG_VALUE.RangeError('historySize', historySize); 2071cb0ef41Sopenharmony_ci } 2081cb0ef41Sopenharmony_ci 2091cb0ef41Sopenharmony_ci // Backwards compat; check the isTTY prop of the output stream 2101cb0ef41Sopenharmony_ci // when `terminal` was not specified 2111cb0ef41Sopenharmony_ci if (terminal === undefined && !(output === null || output === undefined)) { 2121cb0ef41Sopenharmony_ci terminal = !!output.isTTY; 2131cb0ef41Sopenharmony_ci } 2141cb0ef41Sopenharmony_ci 2151cb0ef41Sopenharmony_ci const self = this; 2161cb0ef41Sopenharmony_ci 2171cb0ef41Sopenharmony_ci this.line = ''; 2181cb0ef41Sopenharmony_ci this[kSubstringSearch] = null; 2191cb0ef41Sopenharmony_ci this.output = output; 2201cb0ef41Sopenharmony_ci this.input = input; 2211cb0ef41Sopenharmony_ci this[kUndoStack] = []; 2221cb0ef41Sopenharmony_ci this[kRedoStack] = []; 2231cb0ef41Sopenharmony_ci this.history = history; 2241cb0ef41Sopenharmony_ci this.historySize = historySize; 2251cb0ef41Sopenharmony_ci 2261cb0ef41Sopenharmony_ci // The kill ring is a global list of blocks of text that were previously 2271cb0ef41Sopenharmony_ci // killed (deleted). If its size exceeds kMaxLengthOfKillRing, the oldest 2281cb0ef41Sopenharmony_ci // element will be removed to make room for the latest deletion. With kill 2291cb0ef41Sopenharmony_ci // ring, users are able to recall (yank) or cycle (yank pop) among previously 2301cb0ef41Sopenharmony_ci // killed texts, quite similar to the behavior of Emacs. 2311cb0ef41Sopenharmony_ci this[kKillRing] = []; 2321cb0ef41Sopenharmony_ci this[kKillRingCursor] = 0; 2331cb0ef41Sopenharmony_ci 2341cb0ef41Sopenharmony_ci this.removeHistoryDuplicates = !!removeHistoryDuplicates; 2351cb0ef41Sopenharmony_ci this.crlfDelay = crlfDelay ? 2361cb0ef41Sopenharmony_ci MathMax(kMincrlfDelay, crlfDelay) : 2371cb0ef41Sopenharmony_ci kMincrlfDelay; 2381cb0ef41Sopenharmony_ci this.completer = completer; 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ci this.setPrompt(prompt); 2411cb0ef41Sopenharmony_ci 2421cb0ef41Sopenharmony_ci this.terminal = !!terminal; 2431cb0ef41Sopenharmony_ci 2441cb0ef41Sopenharmony_ci 2451cb0ef41Sopenharmony_ci function onerror(err) { 2461cb0ef41Sopenharmony_ci self.emit('error', err); 2471cb0ef41Sopenharmony_ci } 2481cb0ef41Sopenharmony_ci 2491cb0ef41Sopenharmony_ci function ondata(data) { 2501cb0ef41Sopenharmony_ci self[kNormalWrite](data); 2511cb0ef41Sopenharmony_ci } 2521cb0ef41Sopenharmony_ci 2531cb0ef41Sopenharmony_ci function onend() { 2541cb0ef41Sopenharmony_ci if ( 2551cb0ef41Sopenharmony_ci typeof self[kLine_buffer] === 'string' && 2561cb0ef41Sopenharmony_ci self[kLine_buffer].length > 0 2571cb0ef41Sopenharmony_ci ) { 2581cb0ef41Sopenharmony_ci self.emit('line', self[kLine_buffer]); 2591cb0ef41Sopenharmony_ci } 2601cb0ef41Sopenharmony_ci self.close(); 2611cb0ef41Sopenharmony_ci } 2621cb0ef41Sopenharmony_ci 2631cb0ef41Sopenharmony_ci function ontermend() { 2641cb0ef41Sopenharmony_ci if (typeof self.line === 'string' && self.line.length > 0) { 2651cb0ef41Sopenharmony_ci self.emit('line', self.line); 2661cb0ef41Sopenharmony_ci } 2671cb0ef41Sopenharmony_ci self.close(); 2681cb0ef41Sopenharmony_ci } 2691cb0ef41Sopenharmony_ci 2701cb0ef41Sopenharmony_ci function onkeypress(s, key) { 2711cb0ef41Sopenharmony_ci self[kTtyWrite](s, key); 2721cb0ef41Sopenharmony_ci if (key && key.sequence) { 2731cb0ef41Sopenharmony_ci // If the key.sequence is half of a surrogate pair 2741cb0ef41Sopenharmony_ci // (>= 0xd800 and <= 0xdfff), refresh the line so 2751cb0ef41Sopenharmony_ci // the character is displayed appropriately. 2761cb0ef41Sopenharmony_ci const ch = StringPrototypeCodePointAt(key.sequence, 0); 2771cb0ef41Sopenharmony_ci if (ch >= 0xd800 && ch <= 0xdfff) self[kRefreshLine](); 2781cb0ef41Sopenharmony_ci } 2791cb0ef41Sopenharmony_ci } 2801cb0ef41Sopenharmony_ci 2811cb0ef41Sopenharmony_ci function onresize() { 2821cb0ef41Sopenharmony_ci self[kRefreshLine](); 2831cb0ef41Sopenharmony_ci } 2841cb0ef41Sopenharmony_ci 2851cb0ef41Sopenharmony_ci this[kLineObjectStream] = undefined; 2861cb0ef41Sopenharmony_ci 2871cb0ef41Sopenharmony_ci input.on('error', onerror); 2881cb0ef41Sopenharmony_ci 2891cb0ef41Sopenharmony_ci if (!this.terminal) { 2901cb0ef41Sopenharmony_ci function onSelfCloseWithoutTerminal() { 2911cb0ef41Sopenharmony_ci input.removeListener('data', ondata); 2921cb0ef41Sopenharmony_ci input.removeListener('error', onerror); 2931cb0ef41Sopenharmony_ci input.removeListener('end', onend); 2941cb0ef41Sopenharmony_ci } 2951cb0ef41Sopenharmony_ci 2961cb0ef41Sopenharmony_ci input.on('data', ondata); 2971cb0ef41Sopenharmony_ci input.on('end', onend); 2981cb0ef41Sopenharmony_ci self.once('close', onSelfCloseWithoutTerminal); 2991cb0ef41Sopenharmony_ci this[kDecoder] = new StringDecoder('utf8'); 3001cb0ef41Sopenharmony_ci } else { 3011cb0ef41Sopenharmony_ci function onSelfCloseWithTerminal() { 3021cb0ef41Sopenharmony_ci input.removeListener('keypress', onkeypress); 3031cb0ef41Sopenharmony_ci input.removeListener('error', onerror); 3041cb0ef41Sopenharmony_ci input.removeListener('end', ontermend); 3051cb0ef41Sopenharmony_ci if (output !== null && output !== undefined) { 3061cb0ef41Sopenharmony_ci output.removeListener('resize', onresize); 3071cb0ef41Sopenharmony_ci } 3081cb0ef41Sopenharmony_ci } 3091cb0ef41Sopenharmony_ci 3101cb0ef41Sopenharmony_ci emitKeypressEvents ??= require('internal/readline/emitKeypressEvents'); 3111cb0ef41Sopenharmony_ci emitKeypressEvents(input, this); 3121cb0ef41Sopenharmony_ci 3131cb0ef41Sopenharmony_ci // `input` usually refers to stdin 3141cb0ef41Sopenharmony_ci input.on('keypress', onkeypress); 3151cb0ef41Sopenharmony_ci input.on('end', ontermend); 3161cb0ef41Sopenharmony_ci 3171cb0ef41Sopenharmony_ci this[kSetRawMode](true); 3181cb0ef41Sopenharmony_ci this.terminal = true; 3191cb0ef41Sopenharmony_ci 3201cb0ef41Sopenharmony_ci // Cursor position on the line. 3211cb0ef41Sopenharmony_ci this.cursor = 0; 3221cb0ef41Sopenharmony_ci 3231cb0ef41Sopenharmony_ci this.historyIndex = -1; 3241cb0ef41Sopenharmony_ci 3251cb0ef41Sopenharmony_ci if (output !== null && output !== undefined) 3261cb0ef41Sopenharmony_ci output.on('resize', onresize); 3271cb0ef41Sopenharmony_ci 3281cb0ef41Sopenharmony_ci self.once('close', onSelfCloseWithTerminal); 3291cb0ef41Sopenharmony_ci } 3301cb0ef41Sopenharmony_ci 3311cb0ef41Sopenharmony_ci if (signal) { 3321cb0ef41Sopenharmony_ci const onAborted = () => self.close(); 3331cb0ef41Sopenharmony_ci if (signal.aborted) { 3341cb0ef41Sopenharmony_ci process.nextTick(onAborted); 3351cb0ef41Sopenharmony_ci } else { 3361cb0ef41Sopenharmony_ci const disposable = EventEmitter.addAbortListener(signal, onAborted); 3371cb0ef41Sopenharmony_ci self.once('close', disposable[SymbolDispose]); 3381cb0ef41Sopenharmony_ci } 3391cb0ef41Sopenharmony_ci } 3401cb0ef41Sopenharmony_ci 3411cb0ef41Sopenharmony_ci // Current line 3421cb0ef41Sopenharmony_ci this.line = ''; 3431cb0ef41Sopenharmony_ci 3441cb0ef41Sopenharmony_ci input.resume(); 3451cb0ef41Sopenharmony_ci} 3461cb0ef41Sopenharmony_ci 3471cb0ef41Sopenharmony_ciObjectSetPrototypeOf(InterfaceConstructor.prototype, EventEmitter.prototype); 3481cb0ef41Sopenharmony_ciObjectSetPrototypeOf(InterfaceConstructor, EventEmitter); 3491cb0ef41Sopenharmony_ci 3501cb0ef41Sopenharmony_ciclass Interface extends InterfaceConstructor { 3511cb0ef41Sopenharmony_ci // eslint-disable-next-line no-useless-constructor 3521cb0ef41Sopenharmony_ci constructor(input, output, completer, terminal) { 3531cb0ef41Sopenharmony_ci super(input, output, completer, terminal); 3541cb0ef41Sopenharmony_ci } 3551cb0ef41Sopenharmony_ci get columns() { 3561cb0ef41Sopenharmony_ci if (this.output && this.output.columns) return this.output.columns; 3571cb0ef41Sopenharmony_ci return Infinity; 3581cb0ef41Sopenharmony_ci } 3591cb0ef41Sopenharmony_ci 3601cb0ef41Sopenharmony_ci /** 3611cb0ef41Sopenharmony_ci * Sets the prompt written to the output. 3621cb0ef41Sopenharmony_ci * @param {string} prompt 3631cb0ef41Sopenharmony_ci * @returns {void} 3641cb0ef41Sopenharmony_ci */ 3651cb0ef41Sopenharmony_ci setPrompt(prompt) { 3661cb0ef41Sopenharmony_ci this[kPrompt] = prompt; 3671cb0ef41Sopenharmony_ci } 3681cb0ef41Sopenharmony_ci 3691cb0ef41Sopenharmony_ci /** 3701cb0ef41Sopenharmony_ci * Returns the current prompt used by `rl.prompt()`. 3711cb0ef41Sopenharmony_ci * @returns {string} 3721cb0ef41Sopenharmony_ci */ 3731cb0ef41Sopenharmony_ci getPrompt() { 3741cb0ef41Sopenharmony_ci return this[kPrompt]; 3751cb0ef41Sopenharmony_ci } 3761cb0ef41Sopenharmony_ci 3771cb0ef41Sopenharmony_ci [kSetRawMode](mode) { 3781cb0ef41Sopenharmony_ci const wasInRawMode = this.input.isRaw; 3791cb0ef41Sopenharmony_ci 3801cb0ef41Sopenharmony_ci if (typeof this.input.setRawMode === 'function') { 3811cb0ef41Sopenharmony_ci this.input.setRawMode(mode); 3821cb0ef41Sopenharmony_ci } 3831cb0ef41Sopenharmony_ci 3841cb0ef41Sopenharmony_ci return wasInRawMode; 3851cb0ef41Sopenharmony_ci } 3861cb0ef41Sopenharmony_ci 3871cb0ef41Sopenharmony_ci /** 3881cb0ef41Sopenharmony_ci * Writes the configured `prompt` to a new line in `output`. 3891cb0ef41Sopenharmony_ci * @param {boolean} [preserveCursor] 3901cb0ef41Sopenharmony_ci * @returns {void} 3911cb0ef41Sopenharmony_ci */ 3921cb0ef41Sopenharmony_ci prompt(preserveCursor) { 3931cb0ef41Sopenharmony_ci if (this.paused) this.resume(); 3941cb0ef41Sopenharmony_ci if (this.terminal && process.env.TERM !== 'dumb') { 3951cb0ef41Sopenharmony_ci if (!preserveCursor) this.cursor = 0; 3961cb0ef41Sopenharmony_ci this[kRefreshLine](); 3971cb0ef41Sopenharmony_ci } else { 3981cb0ef41Sopenharmony_ci this[kWriteToOutput](this[kPrompt]); 3991cb0ef41Sopenharmony_ci } 4001cb0ef41Sopenharmony_ci } 4011cb0ef41Sopenharmony_ci 4021cb0ef41Sopenharmony_ci question(query, cb) { 4031cb0ef41Sopenharmony_ci if (this.closed) { 4041cb0ef41Sopenharmony_ci throw new ERR_USE_AFTER_CLOSE('readline'); 4051cb0ef41Sopenharmony_ci } 4061cb0ef41Sopenharmony_ci if (this[kQuestionCallback]) { 4071cb0ef41Sopenharmony_ci this.prompt(); 4081cb0ef41Sopenharmony_ci } else { 4091cb0ef41Sopenharmony_ci this[kOldPrompt] = this[kPrompt]; 4101cb0ef41Sopenharmony_ci this.setPrompt(query); 4111cb0ef41Sopenharmony_ci this[kQuestionCallback] = cb; 4121cb0ef41Sopenharmony_ci this.prompt(); 4131cb0ef41Sopenharmony_ci } 4141cb0ef41Sopenharmony_ci } 4151cb0ef41Sopenharmony_ci 4161cb0ef41Sopenharmony_ci [kOnLine](line) { 4171cb0ef41Sopenharmony_ci if (this[kQuestionCallback]) { 4181cb0ef41Sopenharmony_ci const cb = this[kQuestionCallback]; 4191cb0ef41Sopenharmony_ci this[kQuestionCallback] = null; 4201cb0ef41Sopenharmony_ci this.setPrompt(this[kOldPrompt]); 4211cb0ef41Sopenharmony_ci cb(line); 4221cb0ef41Sopenharmony_ci } else { 4231cb0ef41Sopenharmony_ci this.emit('line', line); 4241cb0ef41Sopenharmony_ci } 4251cb0ef41Sopenharmony_ci } 4261cb0ef41Sopenharmony_ci 4271cb0ef41Sopenharmony_ci [kBeforeEdit](oldText, oldCursor) { 4281cb0ef41Sopenharmony_ci this[kPushToUndoStack](oldText, oldCursor); 4291cb0ef41Sopenharmony_ci } 4301cb0ef41Sopenharmony_ci 4311cb0ef41Sopenharmony_ci [kQuestionCancel]() { 4321cb0ef41Sopenharmony_ci if (this[kQuestionCallback]) { 4331cb0ef41Sopenharmony_ci this[kQuestionCallback] = null; 4341cb0ef41Sopenharmony_ci this.setPrompt(this[kOldPrompt]); 4351cb0ef41Sopenharmony_ci this.clearLine(); 4361cb0ef41Sopenharmony_ci } 4371cb0ef41Sopenharmony_ci } 4381cb0ef41Sopenharmony_ci 4391cb0ef41Sopenharmony_ci [kWriteToOutput](stringToWrite) { 4401cb0ef41Sopenharmony_ci validateString(stringToWrite, 'stringToWrite'); 4411cb0ef41Sopenharmony_ci 4421cb0ef41Sopenharmony_ci if (this.output !== null && this.output !== undefined) { 4431cb0ef41Sopenharmony_ci this.output.write(stringToWrite); 4441cb0ef41Sopenharmony_ci } 4451cb0ef41Sopenharmony_ci } 4461cb0ef41Sopenharmony_ci 4471cb0ef41Sopenharmony_ci [kAddHistory]() { 4481cb0ef41Sopenharmony_ci if (this.line.length === 0) return ''; 4491cb0ef41Sopenharmony_ci 4501cb0ef41Sopenharmony_ci // If the history is disabled then return the line 4511cb0ef41Sopenharmony_ci if (this.historySize === 0) return this.line; 4521cb0ef41Sopenharmony_ci 4531cb0ef41Sopenharmony_ci // If the trimmed line is empty then return the line 4541cb0ef41Sopenharmony_ci if (StringPrototypeTrim(this.line).length === 0) return this.line; 4551cb0ef41Sopenharmony_ci 4561cb0ef41Sopenharmony_ci if (this.history.length === 0 || this.history[0] !== this.line) { 4571cb0ef41Sopenharmony_ci if (this.removeHistoryDuplicates) { 4581cb0ef41Sopenharmony_ci // Remove older history line if identical to new one 4591cb0ef41Sopenharmony_ci const dupIndex = ArrayPrototypeIndexOf(this.history, this.line); 4601cb0ef41Sopenharmony_ci if (dupIndex !== -1) ArrayPrototypeSplice(this.history, dupIndex, 1); 4611cb0ef41Sopenharmony_ci } 4621cb0ef41Sopenharmony_ci 4631cb0ef41Sopenharmony_ci ArrayPrototypeUnshift(this.history, this.line); 4641cb0ef41Sopenharmony_ci 4651cb0ef41Sopenharmony_ci // Only store so many 4661cb0ef41Sopenharmony_ci if (this.history.length > this.historySize) 4671cb0ef41Sopenharmony_ci ArrayPrototypePop(this.history); 4681cb0ef41Sopenharmony_ci } 4691cb0ef41Sopenharmony_ci 4701cb0ef41Sopenharmony_ci this.historyIndex = -1; 4711cb0ef41Sopenharmony_ci 4721cb0ef41Sopenharmony_ci // The listener could change the history object, possibly 4731cb0ef41Sopenharmony_ci // to remove the last added entry if it is sensitive and should 4741cb0ef41Sopenharmony_ci // not be persisted in the history, like a password 4751cb0ef41Sopenharmony_ci const line = this.history[0]; 4761cb0ef41Sopenharmony_ci 4771cb0ef41Sopenharmony_ci // Emit history event to notify listeners of update 4781cb0ef41Sopenharmony_ci this.emit('history', this.history); 4791cb0ef41Sopenharmony_ci 4801cb0ef41Sopenharmony_ci return line; 4811cb0ef41Sopenharmony_ci } 4821cb0ef41Sopenharmony_ci 4831cb0ef41Sopenharmony_ci [kRefreshLine]() { 4841cb0ef41Sopenharmony_ci // line length 4851cb0ef41Sopenharmony_ci const line = this[kPrompt] + this.line; 4861cb0ef41Sopenharmony_ci const dispPos = this[kGetDisplayPos](line); 4871cb0ef41Sopenharmony_ci const lineCols = dispPos.cols; 4881cb0ef41Sopenharmony_ci const lineRows = dispPos.rows; 4891cb0ef41Sopenharmony_ci 4901cb0ef41Sopenharmony_ci // cursor position 4911cb0ef41Sopenharmony_ci const cursorPos = this.getCursorPos(); 4921cb0ef41Sopenharmony_ci 4931cb0ef41Sopenharmony_ci // First move to the bottom of the current line, based on cursor pos 4941cb0ef41Sopenharmony_ci const prevRows = this.prevRows || 0; 4951cb0ef41Sopenharmony_ci if (prevRows > 0) { 4961cb0ef41Sopenharmony_ci moveCursor(this.output, 0, -prevRows); 4971cb0ef41Sopenharmony_ci } 4981cb0ef41Sopenharmony_ci 4991cb0ef41Sopenharmony_ci // Cursor to left edge. 5001cb0ef41Sopenharmony_ci cursorTo(this.output, 0); 5011cb0ef41Sopenharmony_ci // erase data 5021cb0ef41Sopenharmony_ci clearScreenDown(this.output); 5031cb0ef41Sopenharmony_ci 5041cb0ef41Sopenharmony_ci // Write the prompt and the current buffer content. 5051cb0ef41Sopenharmony_ci this[kWriteToOutput](line); 5061cb0ef41Sopenharmony_ci 5071cb0ef41Sopenharmony_ci // Force terminal to allocate a new line 5081cb0ef41Sopenharmony_ci if (lineCols === 0) { 5091cb0ef41Sopenharmony_ci this[kWriteToOutput](' '); 5101cb0ef41Sopenharmony_ci } 5111cb0ef41Sopenharmony_ci 5121cb0ef41Sopenharmony_ci // Move cursor to original position. 5131cb0ef41Sopenharmony_ci cursorTo(this.output, cursorPos.cols); 5141cb0ef41Sopenharmony_ci 5151cb0ef41Sopenharmony_ci const diff = lineRows - cursorPos.rows; 5161cb0ef41Sopenharmony_ci if (diff > 0) { 5171cb0ef41Sopenharmony_ci moveCursor(this.output, 0, -diff); 5181cb0ef41Sopenharmony_ci } 5191cb0ef41Sopenharmony_ci 5201cb0ef41Sopenharmony_ci this.prevRows = cursorPos.rows; 5211cb0ef41Sopenharmony_ci } 5221cb0ef41Sopenharmony_ci 5231cb0ef41Sopenharmony_ci /** 5241cb0ef41Sopenharmony_ci * Closes the `readline.Interface` instance. 5251cb0ef41Sopenharmony_ci * @returns {void} 5261cb0ef41Sopenharmony_ci */ 5271cb0ef41Sopenharmony_ci close() { 5281cb0ef41Sopenharmony_ci if (this.closed) return; 5291cb0ef41Sopenharmony_ci this.pause(); 5301cb0ef41Sopenharmony_ci if (this.terminal) { 5311cb0ef41Sopenharmony_ci this[kSetRawMode](false); 5321cb0ef41Sopenharmony_ci } 5331cb0ef41Sopenharmony_ci this.closed = true; 5341cb0ef41Sopenharmony_ci this.emit('close'); 5351cb0ef41Sopenharmony_ci } 5361cb0ef41Sopenharmony_ci 5371cb0ef41Sopenharmony_ci /** 5381cb0ef41Sopenharmony_ci * Pauses the `input` stream. 5391cb0ef41Sopenharmony_ci * @returns {void | Interface} 5401cb0ef41Sopenharmony_ci */ 5411cb0ef41Sopenharmony_ci pause() { 5421cb0ef41Sopenharmony_ci if (this.paused) return; 5431cb0ef41Sopenharmony_ci this.input.pause(); 5441cb0ef41Sopenharmony_ci this.paused = true; 5451cb0ef41Sopenharmony_ci this.emit('pause'); 5461cb0ef41Sopenharmony_ci return this; 5471cb0ef41Sopenharmony_ci } 5481cb0ef41Sopenharmony_ci 5491cb0ef41Sopenharmony_ci /** 5501cb0ef41Sopenharmony_ci * Resumes the `input` stream if paused. 5511cb0ef41Sopenharmony_ci * @returns {void | Interface} 5521cb0ef41Sopenharmony_ci */ 5531cb0ef41Sopenharmony_ci resume() { 5541cb0ef41Sopenharmony_ci if (!this.paused) return; 5551cb0ef41Sopenharmony_ci this.input.resume(); 5561cb0ef41Sopenharmony_ci this.paused = false; 5571cb0ef41Sopenharmony_ci this.emit('resume'); 5581cb0ef41Sopenharmony_ci return this; 5591cb0ef41Sopenharmony_ci } 5601cb0ef41Sopenharmony_ci 5611cb0ef41Sopenharmony_ci /** 5621cb0ef41Sopenharmony_ci * Writes either `data` or a `key` sequence identified by 5631cb0ef41Sopenharmony_ci * `key` to the `output`. 5641cb0ef41Sopenharmony_ci * @param {string} d 5651cb0ef41Sopenharmony_ci * @param {{ 5661cb0ef41Sopenharmony_ci * ctrl?: boolean; 5671cb0ef41Sopenharmony_ci * meta?: boolean; 5681cb0ef41Sopenharmony_ci * shift?: boolean; 5691cb0ef41Sopenharmony_ci * name?: string; 5701cb0ef41Sopenharmony_ci * }} [key] 5711cb0ef41Sopenharmony_ci * @returns {void} 5721cb0ef41Sopenharmony_ci */ 5731cb0ef41Sopenharmony_ci write(d, key) { 5741cb0ef41Sopenharmony_ci if (this.paused) this.resume(); 5751cb0ef41Sopenharmony_ci if (this.terminal) { 5761cb0ef41Sopenharmony_ci this[kTtyWrite](d, key); 5771cb0ef41Sopenharmony_ci } else { 5781cb0ef41Sopenharmony_ci this[kNormalWrite](d); 5791cb0ef41Sopenharmony_ci } 5801cb0ef41Sopenharmony_ci } 5811cb0ef41Sopenharmony_ci 5821cb0ef41Sopenharmony_ci [kNormalWrite](b) { 5831cb0ef41Sopenharmony_ci if (b === undefined) { 5841cb0ef41Sopenharmony_ci return; 5851cb0ef41Sopenharmony_ci } 5861cb0ef41Sopenharmony_ci let string = this[kDecoder].write(b); 5871cb0ef41Sopenharmony_ci if ( 5881cb0ef41Sopenharmony_ci this[kSawReturnAt] && 5891cb0ef41Sopenharmony_ci DateNow() - this[kSawReturnAt] <= this.crlfDelay 5901cb0ef41Sopenharmony_ci ) { 5911cb0ef41Sopenharmony_ci if (StringPrototypeCodePointAt(string) === 10) string = StringPrototypeSlice(string, 1); 5921cb0ef41Sopenharmony_ci this[kSawReturnAt] = 0; 5931cb0ef41Sopenharmony_ci } 5941cb0ef41Sopenharmony_ci 5951cb0ef41Sopenharmony_ci // Run test() on the new string chunk, not on the entire line buffer. 5961cb0ef41Sopenharmony_ci let newPartContainsEnding = RegExpPrototypeExec(lineEnding, string); 5971cb0ef41Sopenharmony_ci if (newPartContainsEnding !== null) { 5981cb0ef41Sopenharmony_ci if (this[kLine_buffer]) { 5991cb0ef41Sopenharmony_ci string = this[kLine_buffer] + string; 6001cb0ef41Sopenharmony_ci this[kLine_buffer] = null; 6011cb0ef41Sopenharmony_ci lineEnding.lastIndex = 0; // Start the search from the beginning of the string. 6021cb0ef41Sopenharmony_ci newPartContainsEnding = RegExpPrototypeExec(lineEnding, string); 6031cb0ef41Sopenharmony_ci } 6041cb0ef41Sopenharmony_ci this[kSawReturnAt] = StringPrototypeEndsWith(string, '\r') ? 6051cb0ef41Sopenharmony_ci DateNow() : 6061cb0ef41Sopenharmony_ci 0; 6071cb0ef41Sopenharmony_ci 6081cb0ef41Sopenharmony_ci const indexes = [0, newPartContainsEnding.index, lineEnding.lastIndex]; 6091cb0ef41Sopenharmony_ci let nextMatch; 6101cb0ef41Sopenharmony_ci while ((nextMatch = RegExpPrototypeExec(lineEnding, string)) !== null) { 6111cb0ef41Sopenharmony_ci ArrayPrototypePush(indexes, nextMatch.index, lineEnding.lastIndex); 6121cb0ef41Sopenharmony_ci } 6131cb0ef41Sopenharmony_ci const lastIndex = indexes.length - 1; 6141cb0ef41Sopenharmony_ci // Either '' or (conceivably) the unfinished portion of the next line 6151cb0ef41Sopenharmony_ci this[kLine_buffer] = StringPrototypeSlice(string, indexes[lastIndex]); 6161cb0ef41Sopenharmony_ci for (let i = 1; i < lastIndex; i += 2) { 6171cb0ef41Sopenharmony_ci this[kOnLine](StringPrototypeSlice(string, indexes[i - 1], indexes[i])); 6181cb0ef41Sopenharmony_ci } 6191cb0ef41Sopenharmony_ci } else if (string) { 6201cb0ef41Sopenharmony_ci // No newlines this time, save what we have for next time 6211cb0ef41Sopenharmony_ci if (this[kLine_buffer]) { 6221cb0ef41Sopenharmony_ci this[kLine_buffer] += string; 6231cb0ef41Sopenharmony_ci } else { 6241cb0ef41Sopenharmony_ci this[kLine_buffer] = string; 6251cb0ef41Sopenharmony_ci } 6261cb0ef41Sopenharmony_ci } 6271cb0ef41Sopenharmony_ci } 6281cb0ef41Sopenharmony_ci 6291cb0ef41Sopenharmony_ci [kInsertString](c) { 6301cb0ef41Sopenharmony_ci this[kBeforeEdit](this.line, this.cursor); 6311cb0ef41Sopenharmony_ci if (this.cursor < this.line.length) { 6321cb0ef41Sopenharmony_ci const beg = StringPrototypeSlice(this.line, 0, this.cursor); 6331cb0ef41Sopenharmony_ci const end = StringPrototypeSlice( 6341cb0ef41Sopenharmony_ci this.line, 6351cb0ef41Sopenharmony_ci this.cursor, 6361cb0ef41Sopenharmony_ci this.line.length, 6371cb0ef41Sopenharmony_ci ); 6381cb0ef41Sopenharmony_ci this.line = beg + c + end; 6391cb0ef41Sopenharmony_ci this.cursor += c.length; 6401cb0ef41Sopenharmony_ci this[kRefreshLine](); 6411cb0ef41Sopenharmony_ci } else { 6421cb0ef41Sopenharmony_ci const oldPos = this.getCursorPos(); 6431cb0ef41Sopenharmony_ci this.line += c; 6441cb0ef41Sopenharmony_ci this.cursor += c.length; 6451cb0ef41Sopenharmony_ci const newPos = this.getCursorPos(); 6461cb0ef41Sopenharmony_ci 6471cb0ef41Sopenharmony_ci if (oldPos.rows < newPos.rows) { 6481cb0ef41Sopenharmony_ci this[kRefreshLine](); 6491cb0ef41Sopenharmony_ci } else { 6501cb0ef41Sopenharmony_ci this[kWriteToOutput](c); 6511cb0ef41Sopenharmony_ci } 6521cb0ef41Sopenharmony_ci } 6531cb0ef41Sopenharmony_ci } 6541cb0ef41Sopenharmony_ci 6551cb0ef41Sopenharmony_ci async [kTabComplete](lastKeypressWasTab) { 6561cb0ef41Sopenharmony_ci this.pause(); 6571cb0ef41Sopenharmony_ci const string = StringPrototypeSlice(this.line, 0, this.cursor); 6581cb0ef41Sopenharmony_ci let value; 6591cb0ef41Sopenharmony_ci try { 6601cb0ef41Sopenharmony_ci value = await this.completer(string); 6611cb0ef41Sopenharmony_ci } catch (err) { 6621cb0ef41Sopenharmony_ci this[kWriteToOutput](`Tab completion error: ${inspect(err)}`); 6631cb0ef41Sopenharmony_ci return; 6641cb0ef41Sopenharmony_ci } finally { 6651cb0ef41Sopenharmony_ci this.resume(); 6661cb0ef41Sopenharmony_ci } 6671cb0ef41Sopenharmony_ci this[kTabCompleter](lastKeypressWasTab, value); 6681cb0ef41Sopenharmony_ci } 6691cb0ef41Sopenharmony_ci 6701cb0ef41Sopenharmony_ci [kTabCompleter](lastKeypressWasTab, { 0: completions, 1: completeOn }) { 6711cb0ef41Sopenharmony_ci // Result and the text that was completed. 6721cb0ef41Sopenharmony_ci 6731cb0ef41Sopenharmony_ci if (!completions || completions.length === 0) { 6741cb0ef41Sopenharmony_ci return; 6751cb0ef41Sopenharmony_ci } 6761cb0ef41Sopenharmony_ci 6771cb0ef41Sopenharmony_ci // If there is a common prefix to all matches, then apply that portion. 6781cb0ef41Sopenharmony_ci const prefix = commonPrefix( 6791cb0ef41Sopenharmony_ci ArrayPrototypeFilter(completions, (e) => e !== ''), 6801cb0ef41Sopenharmony_ci ); 6811cb0ef41Sopenharmony_ci if (StringPrototypeStartsWith(prefix, completeOn) && 6821cb0ef41Sopenharmony_ci prefix.length > completeOn.length) { 6831cb0ef41Sopenharmony_ci this[kInsertString](StringPrototypeSlice(prefix, completeOn.length)); 6841cb0ef41Sopenharmony_ci return; 6851cb0ef41Sopenharmony_ci } else if (!StringPrototypeStartsWith(completeOn, prefix)) { 6861cb0ef41Sopenharmony_ci this.line = StringPrototypeSlice(this.line, 6871cb0ef41Sopenharmony_ci 0, 6881cb0ef41Sopenharmony_ci this.cursor - completeOn.length) + 6891cb0ef41Sopenharmony_ci prefix + 6901cb0ef41Sopenharmony_ci StringPrototypeSlice(this.line, 6911cb0ef41Sopenharmony_ci this.cursor, 6921cb0ef41Sopenharmony_ci this.line.length); 6931cb0ef41Sopenharmony_ci this.cursor = this.cursor - completeOn.length + prefix.length; 6941cb0ef41Sopenharmony_ci this._refreshLine(); 6951cb0ef41Sopenharmony_ci return; 6961cb0ef41Sopenharmony_ci } 6971cb0ef41Sopenharmony_ci 6981cb0ef41Sopenharmony_ci if (!lastKeypressWasTab) { 6991cb0ef41Sopenharmony_ci return; 7001cb0ef41Sopenharmony_ci } 7011cb0ef41Sopenharmony_ci 7021cb0ef41Sopenharmony_ci this[kBeforeEdit](this.line, this.cursor); 7031cb0ef41Sopenharmony_ci 7041cb0ef41Sopenharmony_ci // Apply/show completions. 7051cb0ef41Sopenharmony_ci const completionsWidth = ArrayPrototypeMap(completions, (e) => 7061cb0ef41Sopenharmony_ci getStringWidth(e), 7071cb0ef41Sopenharmony_ci ); 7081cb0ef41Sopenharmony_ci const width = MathMaxApply(completionsWidth) + 2; // 2 space padding 7091cb0ef41Sopenharmony_ci let maxColumns = MathFloor(this.columns / width) || 1; 7101cb0ef41Sopenharmony_ci if (maxColumns === Infinity) { 7111cb0ef41Sopenharmony_ci maxColumns = 1; 7121cb0ef41Sopenharmony_ci } 7131cb0ef41Sopenharmony_ci let output = '\r\n'; 7141cb0ef41Sopenharmony_ci let lineIndex = 0; 7151cb0ef41Sopenharmony_ci let whitespace = 0; 7161cb0ef41Sopenharmony_ci for (let i = 0; i < completions.length; i++) { 7171cb0ef41Sopenharmony_ci const completion = completions[i]; 7181cb0ef41Sopenharmony_ci if (completion === '' || lineIndex === maxColumns) { 7191cb0ef41Sopenharmony_ci output += '\r\n'; 7201cb0ef41Sopenharmony_ci lineIndex = 0; 7211cb0ef41Sopenharmony_ci whitespace = 0; 7221cb0ef41Sopenharmony_ci } else { 7231cb0ef41Sopenharmony_ci output += StringPrototypeRepeat(' ', whitespace); 7241cb0ef41Sopenharmony_ci } 7251cb0ef41Sopenharmony_ci if (completion !== '') { 7261cb0ef41Sopenharmony_ci output += completion; 7271cb0ef41Sopenharmony_ci whitespace = width - completionsWidth[i]; 7281cb0ef41Sopenharmony_ci lineIndex++; 7291cb0ef41Sopenharmony_ci } else { 7301cb0ef41Sopenharmony_ci output += '\r\n'; 7311cb0ef41Sopenharmony_ci } 7321cb0ef41Sopenharmony_ci } 7331cb0ef41Sopenharmony_ci if (lineIndex !== 0) { 7341cb0ef41Sopenharmony_ci output += '\r\n\r\n'; 7351cb0ef41Sopenharmony_ci } 7361cb0ef41Sopenharmony_ci this[kWriteToOutput](output); 7371cb0ef41Sopenharmony_ci this[kRefreshLine](); 7381cb0ef41Sopenharmony_ci } 7391cb0ef41Sopenharmony_ci 7401cb0ef41Sopenharmony_ci [kWordLeft]() { 7411cb0ef41Sopenharmony_ci if (this.cursor > 0) { 7421cb0ef41Sopenharmony_ci // Reverse the string and match a word near beginning 7431cb0ef41Sopenharmony_ci // to avoid quadratic time complexity 7441cb0ef41Sopenharmony_ci const leading = StringPrototypeSlice(this.line, 0, this.cursor); 7451cb0ef41Sopenharmony_ci const reversed = ArrayPrototypeJoin( 7461cb0ef41Sopenharmony_ci ArrayPrototypeReverse(ArrayFrom(leading)), 7471cb0ef41Sopenharmony_ci '', 7481cb0ef41Sopenharmony_ci ); 7491cb0ef41Sopenharmony_ci const match = RegExpPrototypeExec(/^\s*(?:[^\w\s]+|\w+)?/, reversed); 7501cb0ef41Sopenharmony_ci this[kMoveCursor](-match[0].length); 7511cb0ef41Sopenharmony_ci } 7521cb0ef41Sopenharmony_ci } 7531cb0ef41Sopenharmony_ci 7541cb0ef41Sopenharmony_ci [kWordRight]() { 7551cb0ef41Sopenharmony_ci if (this.cursor < this.line.length) { 7561cb0ef41Sopenharmony_ci const trailing = StringPrototypeSlice(this.line, this.cursor); 7571cb0ef41Sopenharmony_ci const match = RegExpPrototypeExec(/^(?:\s+|[^\w\s]+|\w+)\s*/, trailing); 7581cb0ef41Sopenharmony_ci this[kMoveCursor](match[0].length); 7591cb0ef41Sopenharmony_ci } 7601cb0ef41Sopenharmony_ci } 7611cb0ef41Sopenharmony_ci 7621cb0ef41Sopenharmony_ci [kDeleteLeft]() { 7631cb0ef41Sopenharmony_ci if (this.cursor > 0 && this.line.length > 0) { 7641cb0ef41Sopenharmony_ci this[kBeforeEdit](this.line, this.cursor); 7651cb0ef41Sopenharmony_ci // The number of UTF-16 units comprising the character to the left 7661cb0ef41Sopenharmony_ci const charSize = charLengthLeft(this.line, this.cursor); 7671cb0ef41Sopenharmony_ci this.line = 7681cb0ef41Sopenharmony_ci StringPrototypeSlice(this.line, 0, this.cursor - charSize) + 7691cb0ef41Sopenharmony_ci StringPrototypeSlice(this.line, this.cursor, this.line.length); 7701cb0ef41Sopenharmony_ci 7711cb0ef41Sopenharmony_ci this.cursor -= charSize; 7721cb0ef41Sopenharmony_ci this[kRefreshLine](); 7731cb0ef41Sopenharmony_ci } 7741cb0ef41Sopenharmony_ci } 7751cb0ef41Sopenharmony_ci 7761cb0ef41Sopenharmony_ci [kDeleteRight]() { 7771cb0ef41Sopenharmony_ci if (this.cursor < this.line.length) { 7781cb0ef41Sopenharmony_ci this[kBeforeEdit](this.line, this.cursor); 7791cb0ef41Sopenharmony_ci // The number of UTF-16 units comprising the character to the left 7801cb0ef41Sopenharmony_ci const charSize = charLengthAt(this.line, this.cursor); 7811cb0ef41Sopenharmony_ci this.line = 7821cb0ef41Sopenharmony_ci StringPrototypeSlice(this.line, 0, this.cursor) + 7831cb0ef41Sopenharmony_ci StringPrototypeSlice( 7841cb0ef41Sopenharmony_ci this.line, 7851cb0ef41Sopenharmony_ci this.cursor + charSize, 7861cb0ef41Sopenharmony_ci this.line.length, 7871cb0ef41Sopenharmony_ci ); 7881cb0ef41Sopenharmony_ci this[kRefreshLine](); 7891cb0ef41Sopenharmony_ci } 7901cb0ef41Sopenharmony_ci } 7911cb0ef41Sopenharmony_ci 7921cb0ef41Sopenharmony_ci [kDeleteWordLeft]() { 7931cb0ef41Sopenharmony_ci if (this.cursor > 0) { 7941cb0ef41Sopenharmony_ci this[kBeforeEdit](this.line, this.cursor); 7951cb0ef41Sopenharmony_ci // Reverse the string and match a word near beginning 7961cb0ef41Sopenharmony_ci // to avoid quadratic time complexity 7971cb0ef41Sopenharmony_ci let leading = StringPrototypeSlice(this.line, 0, this.cursor); 7981cb0ef41Sopenharmony_ci const reversed = ArrayPrototypeJoin( 7991cb0ef41Sopenharmony_ci ArrayPrototypeReverse(ArrayFrom(leading)), 8001cb0ef41Sopenharmony_ci '', 8011cb0ef41Sopenharmony_ci ); 8021cb0ef41Sopenharmony_ci const match = RegExpPrototypeExec(/^\s*(?:[^\w\s]+|\w+)?/, reversed); 8031cb0ef41Sopenharmony_ci leading = StringPrototypeSlice( 8041cb0ef41Sopenharmony_ci leading, 8051cb0ef41Sopenharmony_ci 0, 8061cb0ef41Sopenharmony_ci leading.length - match[0].length, 8071cb0ef41Sopenharmony_ci ); 8081cb0ef41Sopenharmony_ci this.line = 8091cb0ef41Sopenharmony_ci leading + 8101cb0ef41Sopenharmony_ci StringPrototypeSlice(this.line, this.cursor, this.line.length); 8111cb0ef41Sopenharmony_ci this.cursor = leading.length; 8121cb0ef41Sopenharmony_ci this[kRefreshLine](); 8131cb0ef41Sopenharmony_ci } 8141cb0ef41Sopenharmony_ci } 8151cb0ef41Sopenharmony_ci 8161cb0ef41Sopenharmony_ci [kDeleteWordRight]() { 8171cb0ef41Sopenharmony_ci if (this.cursor < this.line.length) { 8181cb0ef41Sopenharmony_ci this[kBeforeEdit](this.line, this.cursor); 8191cb0ef41Sopenharmony_ci const trailing = StringPrototypeSlice(this.line, this.cursor); 8201cb0ef41Sopenharmony_ci const match = RegExpPrototypeExec(/^(?:\s+|\W+|\w+)\s*/, trailing); 8211cb0ef41Sopenharmony_ci this.line = 8221cb0ef41Sopenharmony_ci StringPrototypeSlice(this.line, 0, this.cursor) + 8231cb0ef41Sopenharmony_ci StringPrototypeSlice(trailing, match[0].length); 8241cb0ef41Sopenharmony_ci this[kRefreshLine](); 8251cb0ef41Sopenharmony_ci } 8261cb0ef41Sopenharmony_ci } 8271cb0ef41Sopenharmony_ci 8281cb0ef41Sopenharmony_ci [kDeleteLineLeft]() { 8291cb0ef41Sopenharmony_ci this[kBeforeEdit](this.line, this.cursor); 8301cb0ef41Sopenharmony_ci const del = StringPrototypeSlice(this.line, 0, this.cursor); 8311cb0ef41Sopenharmony_ci this.line = StringPrototypeSlice(this.line, this.cursor); 8321cb0ef41Sopenharmony_ci this.cursor = 0; 8331cb0ef41Sopenharmony_ci this[kPushToKillRing](del); 8341cb0ef41Sopenharmony_ci this[kRefreshLine](); 8351cb0ef41Sopenharmony_ci } 8361cb0ef41Sopenharmony_ci 8371cb0ef41Sopenharmony_ci [kDeleteLineRight]() { 8381cb0ef41Sopenharmony_ci this[kBeforeEdit](this.line, this.cursor); 8391cb0ef41Sopenharmony_ci const del = StringPrototypeSlice(this.line, this.cursor); 8401cb0ef41Sopenharmony_ci this.line = StringPrototypeSlice(this.line, 0, this.cursor); 8411cb0ef41Sopenharmony_ci this[kPushToKillRing](del); 8421cb0ef41Sopenharmony_ci this[kRefreshLine](); 8431cb0ef41Sopenharmony_ci } 8441cb0ef41Sopenharmony_ci 8451cb0ef41Sopenharmony_ci [kPushToKillRing](del) { 8461cb0ef41Sopenharmony_ci if (!del || del === this[kKillRing][0]) return; 8471cb0ef41Sopenharmony_ci ArrayPrototypeUnshift(this[kKillRing], del); 8481cb0ef41Sopenharmony_ci this[kKillRingCursor] = 0; 8491cb0ef41Sopenharmony_ci while (this[kKillRing].length > kMaxLengthOfKillRing) 8501cb0ef41Sopenharmony_ci ArrayPrototypePop(this[kKillRing]); 8511cb0ef41Sopenharmony_ci } 8521cb0ef41Sopenharmony_ci 8531cb0ef41Sopenharmony_ci [kYank]() { 8541cb0ef41Sopenharmony_ci if (this[kKillRing].length > 0) { 8551cb0ef41Sopenharmony_ci this[kYanking] = true; 8561cb0ef41Sopenharmony_ci this[kInsertString](this[kKillRing][this[kKillRingCursor]]); 8571cb0ef41Sopenharmony_ci } 8581cb0ef41Sopenharmony_ci } 8591cb0ef41Sopenharmony_ci 8601cb0ef41Sopenharmony_ci [kYankPop]() { 8611cb0ef41Sopenharmony_ci if (!this[kYanking]) { 8621cb0ef41Sopenharmony_ci return; 8631cb0ef41Sopenharmony_ci } 8641cb0ef41Sopenharmony_ci if (this[kKillRing].length > 1) { 8651cb0ef41Sopenharmony_ci const lastYank = this[kKillRing][this[kKillRingCursor]]; 8661cb0ef41Sopenharmony_ci this[kKillRingCursor]++; 8671cb0ef41Sopenharmony_ci if (this[kKillRingCursor] >= this[kKillRing].length) { 8681cb0ef41Sopenharmony_ci this[kKillRingCursor] = 0; 8691cb0ef41Sopenharmony_ci } 8701cb0ef41Sopenharmony_ci const currentYank = this[kKillRing][this[kKillRingCursor]]; 8711cb0ef41Sopenharmony_ci const head = 8721cb0ef41Sopenharmony_ci StringPrototypeSlice(this.line, 0, this.cursor - lastYank.length); 8731cb0ef41Sopenharmony_ci const tail = 8741cb0ef41Sopenharmony_ci StringPrototypeSlice(this.line, this.cursor); 8751cb0ef41Sopenharmony_ci this.line = head + currentYank + tail; 8761cb0ef41Sopenharmony_ci this.cursor = head.length + currentYank.length; 8771cb0ef41Sopenharmony_ci this[kRefreshLine](); 8781cb0ef41Sopenharmony_ci } 8791cb0ef41Sopenharmony_ci } 8801cb0ef41Sopenharmony_ci 8811cb0ef41Sopenharmony_ci clearLine() { 8821cb0ef41Sopenharmony_ci this[kMoveCursor](+Infinity); 8831cb0ef41Sopenharmony_ci this[kWriteToOutput]('\r\n'); 8841cb0ef41Sopenharmony_ci this.line = ''; 8851cb0ef41Sopenharmony_ci this.cursor = 0; 8861cb0ef41Sopenharmony_ci this.prevRows = 0; 8871cb0ef41Sopenharmony_ci } 8881cb0ef41Sopenharmony_ci 8891cb0ef41Sopenharmony_ci [kLine]() { 8901cb0ef41Sopenharmony_ci const line = this[kAddHistory](); 8911cb0ef41Sopenharmony_ci this[kUndoStack] = []; 8921cb0ef41Sopenharmony_ci this[kRedoStack] = []; 8931cb0ef41Sopenharmony_ci this.clearLine(); 8941cb0ef41Sopenharmony_ci this[kOnLine](line); 8951cb0ef41Sopenharmony_ci } 8961cb0ef41Sopenharmony_ci 8971cb0ef41Sopenharmony_ci [kPushToUndoStack](text, cursor) { 8981cb0ef41Sopenharmony_ci if (ArrayPrototypePush(this[kUndoStack], { text, cursor }) > 8991cb0ef41Sopenharmony_ci kMaxUndoRedoStackSize) { 9001cb0ef41Sopenharmony_ci ArrayPrototypeShift(this[kUndoStack]); 9011cb0ef41Sopenharmony_ci } 9021cb0ef41Sopenharmony_ci } 9031cb0ef41Sopenharmony_ci 9041cb0ef41Sopenharmony_ci [kUndo]() { 9051cb0ef41Sopenharmony_ci if (this[kUndoStack].length <= 0) return; 9061cb0ef41Sopenharmony_ci 9071cb0ef41Sopenharmony_ci ArrayPrototypePush( 9081cb0ef41Sopenharmony_ci this[kRedoStack], 9091cb0ef41Sopenharmony_ci { text: this.line, cursor: this.cursor }, 9101cb0ef41Sopenharmony_ci ); 9111cb0ef41Sopenharmony_ci 9121cb0ef41Sopenharmony_ci const entry = ArrayPrototypePop(this[kUndoStack]); 9131cb0ef41Sopenharmony_ci this.line = entry.text; 9141cb0ef41Sopenharmony_ci this.cursor = entry.cursor; 9151cb0ef41Sopenharmony_ci 9161cb0ef41Sopenharmony_ci this[kRefreshLine](); 9171cb0ef41Sopenharmony_ci } 9181cb0ef41Sopenharmony_ci 9191cb0ef41Sopenharmony_ci [kRedo]() { 9201cb0ef41Sopenharmony_ci if (this[kRedoStack].length <= 0) return; 9211cb0ef41Sopenharmony_ci 9221cb0ef41Sopenharmony_ci ArrayPrototypePush( 9231cb0ef41Sopenharmony_ci this[kUndoStack], 9241cb0ef41Sopenharmony_ci { text: this.line, cursor: this.cursor }, 9251cb0ef41Sopenharmony_ci ); 9261cb0ef41Sopenharmony_ci 9271cb0ef41Sopenharmony_ci const entry = ArrayPrototypePop(this[kRedoStack]); 9281cb0ef41Sopenharmony_ci this.line = entry.text; 9291cb0ef41Sopenharmony_ci this.cursor = entry.cursor; 9301cb0ef41Sopenharmony_ci 9311cb0ef41Sopenharmony_ci this[kRefreshLine](); 9321cb0ef41Sopenharmony_ci } 9331cb0ef41Sopenharmony_ci 9341cb0ef41Sopenharmony_ci // TODO(BridgeAR): Add underscores to the search part and a red background in 9351cb0ef41Sopenharmony_ci // case no match is found. This should only be the visual part and not the 9361cb0ef41Sopenharmony_ci // actual line content! 9371cb0ef41Sopenharmony_ci // TODO(BridgeAR): In case the substring based search is active and the end is 9381cb0ef41Sopenharmony_ci // reached, show a comment how to search the history as before. E.g., using 9391cb0ef41Sopenharmony_ci // <ctrl> + N. Only show this after two/three UPs or DOWNs, not on the first 9401cb0ef41Sopenharmony_ci // one. 9411cb0ef41Sopenharmony_ci [kHistoryNext]() { 9421cb0ef41Sopenharmony_ci if (this.historyIndex >= 0) { 9431cb0ef41Sopenharmony_ci this[kBeforeEdit](this.line, this.cursor); 9441cb0ef41Sopenharmony_ci const search = this[kSubstringSearch] || ''; 9451cb0ef41Sopenharmony_ci let index = this.historyIndex - 1; 9461cb0ef41Sopenharmony_ci while ( 9471cb0ef41Sopenharmony_ci index >= 0 && 9481cb0ef41Sopenharmony_ci (!StringPrototypeStartsWith(this.history[index], search) || 9491cb0ef41Sopenharmony_ci this.line === this.history[index]) 9501cb0ef41Sopenharmony_ci ) { 9511cb0ef41Sopenharmony_ci index--; 9521cb0ef41Sopenharmony_ci } 9531cb0ef41Sopenharmony_ci if (index === -1) { 9541cb0ef41Sopenharmony_ci this.line = search; 9551cb0ef41Sopenharmony_ci } else { 9561cb0ef41Sopenharmony_ci this.line = this.history[index]; 9571cb0ef41Sopenharmony_ci } 9581cb0ef41Sopenharmony_ci this.historyIndex = index; 9591cb0ef41Sopenharmony_ci this.cursor = this.line.length; // Set cursor to end of line. 9601cb0ef41Sopenharmony_ci this[kRefreshLine](); 9611cb0ef41Sopenharmony_ci } 9621cb0ef41Sopenharmony_ci } 9631cb0ef41Sopenharmony_ci 9641cb0ef41Sopenharmony_ci [kHistoryPrev]() { 9651cb0ef41Sopenharmony_ci if (this.historyIndex < this.history.length && this.history.length) { 9661cb0ef41Sopenharmony_ci this[kBeforeEdit](this.line, this.cursor); 9671cb0ef41Sopenharmony_ci const search = this[kSubstringSearch] || ''; 9681cb0ef41Sopenharmony_ci let index = this.historyIndex + 1; 9691cb0ef41Sopenharmony_ci while ( 9701cb0ef41Sopenharmony_ci index < this.history.length && 9711cb0ef41Sopenharmony_ci (!StringPrototypeStartsWith(this.history[index], search) || 9721cb0ef41Sopenharmony_ci this.line === this.history[index]) 9731cb0ef41Sopenharmony_ci ) { 9741cb0ef41Sopenharmony_ci index++; 9751cb0ef41Sopenharmony_ci } 9761cb0ef41Sopenharmony_ci if (index === this.history.length) { 9771cb0ef41Sopenharmony_ci this.line = search; 9781cb0ef41Sopenharmony_ci } else { 9791cb0ef41Sopenharmony_ci this.line = this.history[index]; 9801cb0ef41Sopenharmony_ci } 9811cb0ef41Sopenharmony_ci this.historyIndex = index; 9821cb0ef41Sopenharmony_ci this.cursor = this.line.length; // Set cursor to end of line. 9831cb0ef41Sopenharmony_ci this[kRefreshLine](); 9841cb0ef41Sopenharmony_ci } 9851cb0ef41Sopenharmony_ci } 9861cb0ef41Sopenharmony_ci 9871cb0ef41Sopenharmony_ci // Returns the last character's display position of the given string 9881cb0ef41Sopenharmony_ci [kGetDisplayPos](str) { 9891cb0ef41Sopenharmony_ci let offset = 0; 9901cb0ef41Sopenharmony_ci const col = this.columns; 9911cb0ef41Sopenharmony_ci let rows = 0; 9921cb0ef41Sopenharmony_ci str = stripVTControlCharacters(str); 9931cb0ef41Sopenharmony_ci for (const char of new SafeStringIterator(str)) { 9941cb0ef41Sopenharmony_ci if (char === '\n') { 9951cb0ef41Sopenharmony_ci // Rows must be incremented by 1 even if offset = 0 or col = +Infinity. 9961cb0ef41Sopenharmony_ci rows += MathCeil(offset / col) || 1; 9971cb0ef41Sopenharmony_ci offset = 0; 9981cb0ef41Sopenharmony_ci continue; 9991cb0ef41Sopenharmony_ci } 10001cb0ef41Sopenharmony_ci // Tabs must be aligned by an offset of the tab size. 10011cb0ef41Sopenharmony_ci if (char === '\t') { 10021cb0ef41Sopenharmony_ci offset += this.tabSize - (offset % this.tabSize); 10031cb0ef41Sopenharmony_ci continue; 10041cb0ef41Sopenharmony_ci } 10051cb0ef41Sopenharmony_ci const width = getStringWidth(char, false /* stripVTControlCharacters */); 10061cb0ef41Sopenharmony_ci if (width === 0 || width === 1) { 10071cb0ef41Sopenharmony_ci offset += width; 10081cb0ef41Sopenharmony_ci } else { 10091cb0ef41Sopenharmony_ci // width === 2 10101cb0ef41Sopenharmony_ci if ((offset + 1) % col === 0) { 10111cb0ef41Sopenharmony_ci offset++; 10121cb0ef41Sopenharmony_ci } 10131cb0ef41Sopenharmony_ci offset += 2; 10141cb0ef41Sopenharmony_ci } 10151cb0ef41Sopenharmony_ci } 10161cb0ef41Sopenharmony_ci const cols = offset % col; 10171cb0ef41Sopenharmony_ci rows += (offset - cols) / col; 10181cb0ef41Sopenharmony_ci return { cols, rows }; 10191cb0ef41Sopenharmony_ci } 10201cb0ef41Sopenharmony_ci 10211cb0ef41Sopenharmony_ci /** 10221cb0ef41Sopenharmony_ci * Returns the real position of the cursor in relation 10231cb0ef41Sopenharmony_ci * to the input prompt + string. 10241cb0ef41Sopenharmony_ci * @returns {{ 10251cb0ef41Sopenharmony_ci * rows: number; 10261cb0ef41Sopenharmony_ci * cols: number; 10271cb0ef41Sopenharmony_ci * }} 10281cb0ef41Sopenharmony_ci */ 10291cb0ef41Sopenharmony_ci getCursorPos() { 10301cb0ef41Sopenharmony_ci const strBeforeCursor = 10311cb0ef41Sopenharmony_ci this[kPrompt] + StringPrototypeSlice(this.line, 0, this.cursor); 10321cb0ef41Sopenharmony_ci return this[kGetDisplayPos](strBeforeCursor); 10331cb0ef41Sopenharmony_ci } 10341cb0ef41Sopenharmony_ci 10351cb0ef41Sopenharmony_ci // This function moves cursor dx places to the right 10361cb0ef41Sopenharmony_ci // (-dx for left) and refreshes the line if it is needed. 10371cb0ef41Sopenharmony_ci [kMoveCursor](dx) { 10381cb0ef41Sopenharmony_ci if (dx === 0) { 10391cb0ef41Sopenharmony_ci return; 10401cb0ef41Sopenharmony_ci } 10411cb0ef41Sopenharmony_ci const oldPos = this.getCursorPos(); 10421cb0ef41Sopenharmony_ci this.cursor += dx; 10431cb0ef41Sopenharmony_ci 10441cb0ef41Sopenharmony_ci // Bounds check 10451cb0ef41Sopenharmony_ci if (this.cursor < 0) { 10461cb0ef41Sopenharmony_ci this.cursor = 0; 10471cb0ef41Sopenharmony_ci } else if (this.cursor > this.line.length) { 10481cb0ef41Sopenharmony_ci this.cursor = this.line.length; 10491cb0ef41Sopenharmony_ci } 10501cb0ef41Sopenharmony_ci 10511cb0ef41Sopenharmony_ci const newPos = this.getCursorPos(); 10521cb0ef41Sopenharmony_ci 10531cb0ef41Sopenharmony_ci // Check if cursor stayed on the line. 10541cb0ef41Sopenharmony_ci if (oldPos.rows === newPos.rows) { 10551cb0ef41Sopenharmony_ci const diffWidth = newPos.cols - oldPos.cols; 10561cb0ef41Sopenharmony_ci moveCursor(this.output, diffWidth, 0); 10571cb0ef41Sopenharmony_ci } else { 10581cb0ef41Sopenharmony_ci this[kRefreshLine](); 10591cb0ef41Sopenharmony_ci } 10601cb0ef41Sopenharmony_ci } 10611cb0ef41Sopenharmony_ci 10621cb0ef41Sopenharmony_ci // Handle a write from the tty 10631cb0ef41Sopenharmony_ci [kTtyWrite](s, key) { 10641cb0ef41Sopenharmony_ci const previousKey = this[kPreviousKey]; 10651cb0ef41Sopenharmony_ci key = key || kEmptyObject; 10661cb0ef41Sopenharmony_ci this[kPreviousKey] = key; 10671cb0ef41Sopenharmony_ci 10681cb0ef41Sopenharmony_ci if (!key.meta || key.name !== 'y') { 10691cb0ef41Sopenharmony_ci // Reset yanking state unless we are doing yank pop. 10701cb0ef41Sopenharmony_ci this[kYanking] = false; 10711cb0ef41Sopenharmony_ci } 10721cb0ef41Sopenharmony_ci 10731cb0ef41Sopenharmony_ci // Activate or deactivate substring search. 10741cb0ef41Sopenharmony_ci if ( 10751cb0ef41Sopenharmony_ci (key.name === 'up' || key.name === 'down') && 10761cb0ef41Sopenharmony_ci !key.ctrl && 10771cb0ef41Sopenharmony_ci !key.meta && 10781cb0ef41Sopenharmony_ci !key.shift 10791cb0ef41Sopenharmony_ci ) { 10801cb0ef41Sopenharmony_ci if (this[kSubstringSearch] === null) { 10811cb0ef41Sopenharmony_ci this[kSubstringSearch] = StringPrototypeSlice( 10821cb0ef41Sopenharmony_ci this.line, 10831cb0ef41Sopenharmony_ci 0, 10841cb0ef41Sopenharmony_ci this.cursor, 10851cb0ef41Sopenharmony_ci ); 10861cb0ef41Sopenharmony_ci } 10871cb0ef41Sopenharmony_ci } else if (this[kSubstringSearch] !== null) { 10881cb0ef41Sopenharmony_ci this[kSubstringSearch] = null; 10891cb0ef41Sopenharmony_ci // Reset the index in case there's no match. 10901cb0ef41Sopenharmony_ci if (this.history.length === this.historyIndex) { 10911cb0ef41Sopenharmony_ci this.historyIndex = -1; 10921cb0ef41Sopenharmony_ci } 10931cb0ef41Sopenharmony_ci } 10941cb0ef41Sopenharmony_ci 10951cb0ef41Sopenharmony_ci // Undo & Redo 10961cb0ef41Sopenharmony_ci if (typeof key.sequence === 'string') { 10971cb0ef41Sopenharmony_ci switch (StringPrototypeCodePointAt(key.sequence, 0)) { 10981cb0ef41Sopenharmony_ci case 0x1f: 10991cb0ef41Sopenharmony_ci this[kUndo](); 11001cb0ef41Sopenharmony_ci return; 11011cb0ef41Sopenharmony_ci case 0x1e: 11021cb0ef41Sopenharmony_ci this[kRedo](); 11031cb0ef41Sopenharmony_ci return; 11041cb0ef41Sopenharmony_ci default: 11051cb0ef41Sopenharmony_ci break; 11061cb0ef41Sopenharmony_ci } 11071cb0ef41Sopenharmony_ci } 11081cb0ef41Sopenharmony_ci 11091cb0ef41Sopenharmony_ci // Ignore escape key, fixes 11101cb0ef41Sopenharmony_ci // https://github.com/nodejs/node-v0.x-archive/issues/2876. 11111cb0ef41Sopenharmony_ci if (key.name === 'escape') return; 11121cb0ef41Sopenharmony_ci 11131cb0ef41Sopenharmony_ci if (key.ctrl && key.shift) { 11141cb0ef41Sopenharmony_ci /* Control and shift pressed */ 11151cb0ef41Sopenharmony_ci switch (key.name) { 11161cb0ef41Sopenharmony_ci // TODO(BridgeAR): The transmitted escape sequence is `\b` and that is 11171cb0ef41Sopenharmony_ci // identical to <ctrl>-h. It should have a unique escape sequence. 11181cb0ef41Sopenharmony_ci case 'backspace': 11191cb0ef41Sopenharmony_ci this[kDeleteLineLeft](); 11201cb0ef41Sopenharmony_ci break; 11211cb0ef41Sopenharmony_ci 11221cb0ef41Sopenharmony_ci case 'delete': 11231cb0ef41Sopenharmony_ci this[kDeleteLineRight](); 11241cb0ef41Sopenharmony_ci break; 11251cb0ef41Sopenharmony_ci } 11261cb0ef41Sopenharmony_ci } else if (key.ctrl) { 11271cb0ef41Sopenharmony_ci /* Control key pressed */ 11281cb0ef41Sopenharmony_ci 11291cb0ef41Sopenharmony_ci switch (key.name) { 11301cb0ef41Sopenharmony_ci case 'c': 11311cb0ef41Sopenharmony_ci if (this.listenerCount('SIGINT') > 0) { 11321cb0ef41Sopenharmony_ci this.emit('SIGINT'); 11331cb0ef41Sopenharmony_ci } else { 11341cb0ef41Sopenharmony_ci // This readline instance is finished 11351cb0ef41Sopenharmony_ci this.close(); 11361cb0ef41Sopenharmony_ci } 11371cb0ef41Sopenharmony_ci break; 11381cb0ef41Sopenharmony_ci 11391cb0ef41Sopenharmony_ci case 'h': // delete left 11401cb0ef41Sopenharmony_ci this[kDeleteLeft](); 11411cb0ef41Sopenharmony_ci break; 11421cb0ef41Sopenharmony_ci 11431cb0ef41Sopenharmony_ci case 'd': // delete right or EOF 11441cb0ef41Sopenharmony_ci if (this.cursor === 0 && this.line.length === 0) { 11451cb0ef41Sopenharmony_ci // This readline instance is finished 11461cb0ef41Sopenharmony_ci this.close(); 11471cb0ef41Sopenharmony_ci } else if (this.cursor < this.line.length) { 11481cb0ef41Sopenharmony_ci this[kDeleteRight](); 11491cb0ef41Sopenharmony_ci } 11501cb0ef41Sopenharmony_ci break; 11511cb0ef41Sopenharmony_ci 11521cb0ef41Sopenharmony_ci case 'u': // Delete from current to start of line 11531cb0ef41Sopenharmony_ci this[kDeleteLineLeft](); 11541cb0ef41Sopenharmony_ci break; 11551cb0ef41Sopenharmony_ci 11561cb0ef41Sopenharmony_ci case 'k': // Delete from current to end of line 11571cb0ef41Sopenharmony_ci this[kDeleteLineRight](); 11581cb0ef41Sopenharmony_ci break; 11591cb0ef41Sopenharmony_ci 11601cb0ef41Sopenharmony_ci case 'a': // Go to the start of the line 11611cb0ef41Sopenharmony_ci this[kMoveCursor](-Infinity); 11621cb0ef41Sopenharmony_ci break; 11631cb0ef41Sopenharmony_ci 11641cb0ef41Sopenharmony_ci case 'e': // Go to the end of the line 11651cb0ef41Sopenharmony_ci this[kMoveCursor](+Infinity); 11661cb0ef41Sopenharmony_ci break; 11671cb0ef41Sopenharmony_ci 11681cb0ef41Sopenharmony_ci case 'b': // back one character 11691cb0ef41Sopenharmony_ci this[kMoveCursor](-charLengthLeft(this.line, this.cursor)); 11701cb0ef41Sopenharmony_ci break; 11711cb0ef41Sopenharmony_ci 11721cb0ef41Sopenharmony_ci case 'f': // Forward one character 11731cb0ef41Sopenharmony_ci this[kMoveCursor](+charLengthAt(this.line, this.cursor)); 11741cb0ef41Sopenharmony_ci break; 11751cb0ef41Sopenharmony_ci 11761cb0ef41Sopenharmony_ci case 'l': // Clear the whole screen 11771cb0ef41Sopenharmony_ci cursorTo(this.output, 0, 0); 11781cb0ef41Sopenharmony_ci clearScreenDown(this.output); 11791cb0ef41Sopenharmony_ci this[kRefreshLine](); 11801cb0ef41Sopenharmony_ci break; 11811cb0ef41Sopenharmony_ci 11821cb0ef41Sopenharmony_ci case 'n': // next history item 11831cb0ef41Sopenharmony_ci this[kHistoryNext](); 11841cb0ef41Sopenharmony_ci break; 11851cb0ef41Sopenharmony_ci 11861cb0ef41Sopenharmony_ci case 'p': // Previous history item 11871cb0ef41Sopenharmony_ci this[kHistoryPrev](); 11881cb0ef41Sopenharmony_ci break; 11891cb0ef41Sopenharmony_ci 11901cb0ef41Sopenharmony_ci case 'y': // Yank killed string 11911cb0ef41Sopenharmony_ci this[kYank](); 11921cb0ef41Sopenharmony_ci break; 11931cb0ef41Sopenharmony_ci 11941cb0ef41Sopenharmony_ci case 'z': 11951cb0ef41Sopenharmony_ci if (process.platform === 'win32') break; 11961cb0ef41Sopenharmony_ci if (this.listenerCount('SIGTSTP') > 0) { 11971cb0ef41Sopenharmony_ci this.emit('SIGTSTP'); 11981cb0ef41Sopenharmony_ci } else { 11991cb0ef41Sopenharmony_ci process.once('SIGCONT', () => { 12001cb0ef41Sopenharmony_ci // Don't raise events if stream has already been abandoned. 12011cb0ef41Sopenharmony_ci if (!this.paused) { 12021cb0ef41Sopenharmony_ci // Stream must be paused and resumed after SIGCONT to catch 12031cb0ef41Sopenharmony_ci // SIGINT, SIGTSTP, and EOF. 12041cb0ef41Sopenharmony_ci this.pause(); 12051cb0ef41Sopenharmony_ci this.emit('SIGCONT'); 12061cb0ef41Sopenharmony_ci } 12071cb0ef41Sopenharmony_ci // Explicitly re-enable "raw mode" and move the cursor to 12081cb0ef41Sopenharmony_ci // the correct position. 12091cb0ef41Sopenharmony_ci // See https://github.com/joyent/node/issues/3295. 12101cb0ef41Sopenharmony_ci this[kSetRawMode](true); 12111cb0ef41Sopenharmony_ci this[kRefreshLine](); 12121cb0ef41Sopenharmony_ci }); 12131cb0ef41Sopenharmony_ci this[kSetRawMode](false); 12141cb0ef41Sopenharmony_ci process.kill(process.pid, 'SIGTSTP'); 12151cb0ef41Sopenharmony_ci } 12161cb0ef41Sopenharmony_ci break; 12171cb0ef41Sopenharmony_ci 12181cb0ef41Sopenharmony_ci case 'w': // Delete backwards to a word boundary 12191cb0ef41Sopenharmony_ci // TODO(BridgeAR): The transmitted escape sequence is `\b` and that is 12201cb0ef41Sopenharmony_ci // identical to <ctrl>-h. It should have a unique escape sequence. 12211cb0ef41Sopenharmony_ci // Falls through 12221cb0ef41Sopenharmony_ci case 'backspace': 12231cb0ef41Sopenharmony_ci this[kDeleteWordLeft](); 12241cb0ef41Sopenharmony_ci break; 12251cb0ef41Sopenharmony_ci 12261cb0ef41Sopenharmony_ci case 'delete': // Delete forward to a word boundary 12271cb0ef41Sopenharmony_ci this[kDeleteWordRight](); 12281cb0ef41Sopenharmony_ci break; 12291cb0ef41Sopenharmony_ci 12301cb0ef41Sopenharmony_ci case 'left': 12311cb0ef41Sopenharmony_ci this[kWordLeft](); 12321cb0ef41Sopenharmony_ci break; 12331cb0ef41Sopenharmony_ci 12341cb0ef41Sopenharmony_ci case 'right': 12351cb0ef41Sopenharmony_ci this[kWordRight](); 12361cb0ef41Sopenharmony_ci break; 12371cb0ef41Sopenharmony_ci } 12381cb0ef41Sopenharmony_ci } else if (key.meta) { 12391cb0ef41Sopenharmony_ci /* Meta key pressed */ 12401cb0ef41Sopenharmony_ci 12411cb0ef41Sopenharmony_ci switch (key.name) { 12421cb0ef41Sopenharmony_ci case 'b': // backward word 12431cb0ef41Sopenharmony_ci this[kWordLeft](); 12441cb0ef41Sopenharmony_ci break; 12451cb0ef41Sopenharmony_ci 12461cb0ef41Sopenharmony_ci case 'f': // forward word 12471cb0ef41Sopenharmony_ci this[kWordRight](); 12481cb0ef41Sopenharmony_ci break; 12491cb0ef41Sopenharmony_ci 12501cb0ef41Sopenharmony_ci case 'd': // delete forward word 12511cb0ef41Sopenharmony_ci case 'delete': 12521cb0ef41Sopenharmony_ci this[kDeleteWordRight](); 12531cb0ef41Sopenharmony_ci break; 12541cb0ef41Sopenharmony_ci 12551cb0ef41Sopenharmony_ci case 'backspace': // Delete backwards to a word boundary 12561cb0ef41Sopenharmony_ci this[kDeleteWordLeft](); 12571cb0ef41Sopenharmony_ci break; 12581cb0ef41Sopenharmony_ci 12591cb0ef41Sopenharmony_ci case 'y': // Doing yank pop 12601cb0ef41Sopenharmony_ci this[kYankPop](); 12611cb0ef41Sopenharmony_ci break; 12621cb0ef41Sopenharmony_ci } 12631cb0ef41Sopenharmony_ci } else { 12641cb0ef41Sopenharmony_ci /* No modifier keys used */ 12651cb0ef41Sopenharmony_ci 12661cb0ef41Sopenharmony_ci // \r bookkeeping is only relevant if a \n comes right after. 12671cb0ef41Sopenharmony_ci if (this[kSawReturnAt] && key.name !== 'enter') this[kSawReturnAt] = 0; 12681cb0ef41Sopenharmony_ci 12691cb0ef41Sopenharmony_ci switch (key.name) { 12701cb0ef41Sopenharmony_ci case 'return': // Carriage return, i.e. \r 12711cb0ef41Sopenharmony_ci this[kSawReturnAt] = DateNow(); 12721cb0ef41Sopenharmony_ci this[kLine](); 12731cb0ef41Sopenharmony_ci break; 12741cb0ef41Sopenharmony_ci 12751cb0ef41Sopenharmony_ci case 'enter': 12761cb0ef41Sopenharmony_ci // When key interval > crlfDelay 12771cb0ef41Sopenharmony_ci if ( 12781cb0ef41Sopenharmony_ci this[kSawReturnAt] === 0 || 12791cb0ef41Sopenharmony_ci DateNow() - this[kSawReturnAt] > this.crlfDelay 12801cb0ef41Sopenharmony_ci ) { 12811cb0ef41Sopenharmony_ci this[kLine](); 12821cb0ef41Sopenharmony_ci } 12831cb0ef41Sopenharmony_ci this[kSawReturnAt] = 0; 12841cb0ef41Sopenharmony_ci break; 12851cb0ef41Sopenharmony_ci 12861cb0ef41Sopenharmony_ci case 'backspace': 12871cb0ef41Sopenharmony_ci this[kDeleteLeft](); 12881cb0ef41Sopenharmony_ci break; 12891cb0ef41Sopenharmony_ci 12901cb0ef41Sopenharmony_ci case 'delete': 12911cb0ef41Sopenharmony_ci this[kDeleteRight](); 12921cb0ef41Sopenharmony_ci break; 12931cb0ef41Sopenharmony_ci 12941cb0ef41Sopenharmony_ci case 'left': 12951cb0ef41Sopenharmony_ci // Obtain the code point to the left 12961cb0ef41Sopenharmony_ci this[kMoveCursor](-charLengthLeft(this.line, this.cursor)); 12971cb0ef41Sopenharmony_ci break; 12981cb0ef41Sopenharmony_ci 12991cb0ef41Sopenharmony_ci case 'right': 13001cb0ef41Sopenharmony_ci this[kMoveCursor](+charLengthAt(this.line, this.cursor)); 13011cb0ef41Sopenharmony_ci break; 13021cb0ef41Sopenharmony_ci 13031cb0ef41Sopenharmony_ci case 'home': 13041cb0ef41Sopenharmony_ci this[kMoveCursor](-Infinity); 13051cb0ef41Sopenharmony_ci break; 13061cb0ef41Sopenharmony_ci 13071cb0ef41Sopenharmony_ci case 'end': 13081cb0ef41Sopenharmony_ci this[kMoveCursor](+Infinity); 13091cb0ef41Sopenharmony_ci break; 13101cb0ef41Sopenharmony_ci 13111cb0ef41Sopenharmony_ci case 'up': 13121cb0ef41Sopenharmony_ci this[kHistoryPrev](); 13131cb0ef41Sopenharmony_ci break; 13141cb0ef41Sopenharmony_ci 13151cb0ef41Sopenharmony_ci case 'down': 13161cb0ef41Sopenharmony_ci this[kHistoryNext](); 13171cb0ef41Sopenharmony_ci break; 13181cb0ef41Sopenharmony_ci 13191cb0ef41Sopenharmony_ci case 'tab': 13201cb0ef41Sopenharmony_ci // If tab completion enabled, do that... 13211cb0ef41Sopenharmony_ci if ( 13221cb0ef41Sopenharmony_ci typeof this.completer === 'function' && 13231cb0ef41Sopenharmony_ci this.isCompletionEnabled 13241cb0ef41Sopenharmony_ci ) { 13251cb0ef41Sopenharmony_ci const lastKeypressWasTab = 13261cb0ef41Sopenharmony_ci previousKey && previousKey.name === 'tab'; 13271cb0ef41Sopenharmony_ci this[kTabComplete](lastKeypressWasTab); 13281cb0ef41Sopenharmony_ci break; 13291cb0ef41Sopenharmony_ci } 13301cb0ef41Sopenharmony_ci // falls through 13311cb0ef41Sopenharmony_ci default: 13321cb0ef41Sopenharmony_ci if (typeof s === 'string' && s) { 13331cb0ef41Sopenharmony_ci // Erase state of previous searches. 13341cb0ef41Sopenharmony_ci lineEnding.lastIndex = 0; 13351cb0ef41Sopenharmony_ci let nextMatch; 13361cb0ef41Sopenharmony_ci // Keep track of the end of the last match. 13371cb0ef41Sopenharmony_ci let lastIndex = 0; 13381cb0ef41Sopenharmony_ci while ((nextMatch = RegExpPrototypeExec(lineEnding, s)) !== null) { 13391cb0ef41Sopenharmony_ci this[kInsertString](StringPrototypeSlice(s, lastIndex, nextMatch.index)); 13401cb0ef41Sopenharmony_ci ({ lastIndex } = lineEnding); 13411cb0ef41Sopenharmony_ci this[kLine](); 13421cb0ef41Sopenharmony_ci // Restore lastIndex as the call to kLine could have mutated it. 13431cb0ef41Sopenharmony_ci lineEnding.lastIndex = lastIndex; 13441cb0ef41Sopenharmony_ci } 13451cb0ef41Sopenharmony_ci // This ensures that the last line is written if it doesn't end in a newline. 13461cb0ef41Sopenharmony_ci // Note that the last line may be the first line, in which case this still works. 13471cb0ef41Sopenharmony_ci this[kInsertString](StringPrototypeSlice(s, lastIndex)); 13481cb0ef41Sopenharmony_ci } 13491cb0ef41Sopenharmony_ci } 13501cb0ef41Sopenharmony_ci } 13511cb0ef41Sopenharmony_ci } 13521cb0ef41Sopenharmony_ci 13531cb0ef41Sopenharmony_ci /** 13541cb0ef41Sopenharmony_ci * Creates an `AsyncIterator` object that iterates through 13551cb0ef41Sopenharmony_ci * each line in the input stream as a string. 13561cb0ef41Sopenharmony_ci * @typedef {{ 13571cb0ef41Sopenharmony_ci * [Symbol.asyncIterator]: () => InterfaceAsyncIterator, 13581cb0ef41Sopenharmony_ci * next: () => Promise<string> 13591cb0ef41Sopenharmony_ci * }} InterfaceAsyncIterator 13601cb0ef41Sopenharmony_ci * @returns {InterfaceAsyncIterator} 13611cb0ef41Sopenharmony_ci */ 13621cb0ef41Sopenharmony_ci [SymbolAsyncIterator]() { 13631cb0ef41Sopenharmony_ci if (this[kLineObjectStream] === undefined) { 13641cb0ef41Sopenharmony_ci if (Readable === undefined) { 13651cb0ef41Sopenharmony_ci Readable = require('stream').Readable; 13661cb0ef41Sopenharmony_ci } 13671cb0ef41Sopenharmony_ci const readable = new Readable({ 13681cb0ef41Sopenharmony_ci objectMode: true, 13691cb0ef41Sopenharmony_ci read: () => { 13701cb0ef41Sopenharmony_ci this.resume(); 13711cb0ef41Sopenharmony_ci }, 13721cb0ef41Sopenharmony_ci destroy: (err, cb) => { 13731cb0ef41Sopenharmony_ci this.off('line', lineListener); 13741cb0ef41Sopenharmony_ci this.off('close', closeListener); 13751cb0ef41Sopenharmony_ci this.close(); 13761cb0ef41Sopenharmony_ci cb(err); 13771cb0ef41Sopenharmony_ci }, 13781cb0ef41Sopenharmony_ci }); 13791cb0ef41Sopenharmony_ci const lineListener = (input) => { 13801cb0ef41Sopenharmony_ci if (!readable.push(input)) { 13811cb0ef41Sopenharmony_ci // TODO(rexagod): drain to resume flow 13821cb0ef41Sopenharmony_ci this.pause(); 13831cb0ef41Sopenharmony_ci } 13841cb0ef41Sopenharmony_ci }; 13851cb0ef41Sopenharmony_ci const closeListener = () => { 13861cb0ef41Sopenharmony_ci readable.push(null); 13871cb0ef41Sopenharmony_ci }; 13881cb0ef41Sopenharmony_ci const errorListener = (err) => { 13891cb0ef41Sopenharmony_ci readable.destroy(err); 13901cb0ef41Sopenharmony_ci }; 13911cb0ef41Sopenharmony_ci this.on('error', errorListener); 13921cb0ef41Sopenharmony_ci this.on('line', lineListener); 13931cb0ef41Sopenharmony_ci this.on('close', closeListener); 13941cb0ef41Sopenharmony_ci this[kLineObjectStream] = readable; 13951cb0ef41Sopenharmony_ci } 13961cb0ef41Sopenharmony_ci 13971cb0ef41Sopenharmony_ci return this[kLineObjectStream][SymbolAsyncIterator](); 13981cb0ef41Sopenharmony_ci } 13991cb0ef41Sopenharmony_ci} 14001cb0ef41Sopenharmony_ci 14011cb0ef41Sopenharmony_cimodule.exports = { 14021cb0ef41Sopenharmony_ci Interface, 14031cb0ef41Sopenharmony_ci InterfaceConstructor, 14041cb0ef41Sopenharmony_ci kAddHistory, 14051cb0ef41Sopenharmony_ci kDecoder, 14061cb0ef41Sopenharmony_ci kDeleteLeft, 14071cb0ef41Sopenharmony_ci kDeleteLineLeft, 14081cb0ef41Sopenharmony_ci kDeleteLineRight, 14091cb0ef41Sopenharmony_ci kDeleteRight, 14101cb0ef41Sopenharmony_ci kDeleteWordLeft, 14111cb0ef41Sopenharmony_ci kDeleteWordRight, 14121cb0ef41Sopenharmony_ci kGetDisplayPos, 14131cb0ef41Sopenharmony_ci kHistoryNext, 14141cb0ef41Sopenharmony_ci kHistoryPrev, 14151cb0ef41Sopenharmony_ci kInsertString, 14161cb0ef41Sopenharmony_ci kLine, 14171cb0ef41Sopenharmony_ci kLine_buffer, 14181cb0ef41Sopenharmony_ci kMoveCursor, 14191cb0ef41Sopenharmony_ci kNormalWrite, 14201cb0ef41Sopenharmony_ci kOldPrompt, 14211cb0ef41Sopenharmony_ci kOnLine, 14221cb0ef41Sopenharmony_ci kPreviousKey, 14231cb0ef41Sopenharmony_ci kPrompt, 14241cb0ef41Sopenharmony_ci kQuestionCallback, 14251cb0ef41Sopenharmony_ci kQuestionCancel, 14261cb0ef41Sopenharmony_ci kRefreshLine, 14271cb0ef41Sopenharmony_ci kSawKeyPress, 14281cb0ef41Sopenharmony_ci kSawReturnAt, 14291cb0ef41Sopenharmony_ci kSetRawMode, 14301cb0ef41Sopenharmony_ci kTabComplete, 14311cb0ef41Sopenharmony_ci kTabCompleter, 14321cb0ef41Sopenharmony_ci kTtyWrite, 14331cb0ef41Sopenharmony_ci kWordLeft, 14341cb0ef41Sopenharmony_ci kWordRight, 14351cb0ef41Sopenharmony_ci kWriteToOutput, 14361cb0ef41Sopenharmony_ci}; 1437