UNPKG

kui-shell

Version:

This is the monorepo for Kui, the hybrid command-line/GUI electron-based Kubernetes tool

851 lines 36.5 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const debug_1 = require("debug"); const path = require("path"); const uuid_1 = require("uuid"); const xterm = require("xterm"); const strip_ansi_1 = require("strip-ansi"); const js_yaml_1 = require("js-yaml"); const webLinks_1 = require("xterm/lib/addons/webLinks/webLinks"); const core_1 = require("@kui-shell/core"); const sidecar_1 = require("@kui-shell/core/webapp/views/sidecar"); const cli_1 = require("@kui-shell/core/webapp/cli"); const ascii_to_usage_1 = require("@kui-shell/core/webapp/util/ascii-to-usage"); const ascii_to_table_1 = require("@kui-shell/core/webapp/util/ascii-to-table"); const ui = require("./ui"); const session = require("./session"); const util_1 = require("./util"); const channel_1 = require("./channel"); const debug = debug_1.default('plugins/bash-like/pty/client'); const enterApplicationModePattern = /\x1b\[\?1h/; const exitApplicationModePattern = /\x1b\[\?1l/; const enterAltBufferPattern = /\x1b\[\??(47|1047|1049)h/; const exitAltBufferPattern = /\x1b\[\??(47|1047|1049)l/; let resizeGeneration = 0; if (window) { window.addEventListener('resize', () => { resizeGeneration++; }); } function getCachedSize(tab) { const cachedSize = tab['_kui_pty_cachedSize']; if (cachedSize && cachedSize.sidecarState === sidecar_1.getSidecarState(tab) && cachedSize.resizeGeneration === resizeGeneration) { return cachedSize; } } function setCachedSize(tab, { rows, cols }) { tab['_kui_pty_cachedSize'] = { rows, cols, sidecarState: sidecar_1.getSidecarState(tab), resizeGeneration }; } class Resizer { constructor(terminal, tab, execOptions) { this.alt = false; this.wasAlt = false; this.app = false; this._frozen = false; this.tab = tab; this.execOptions = execOptions; this.terminal = terminal; this.resizeNow = this.resize.bind(this, true); window.addEventListener('resize', this.resizeNow); this.clearXtermSelectionNow = () => { terminal.clearSelection(); }; document.addEventListener('select', this.clearXtermSelectionNow); const ourTab = tab; core_1.eventBus.on('/sidecar/toggle', ({ tab }) => { if (cli_1.sameTab(tab, ourTab)) { this.resizeNow(); } else { debug('toggle event, but not for our sidecar'); } }); this.resize(); } get ws() { return this._ws; } set ws(ws) { this._ws = ws; } destroy() { this.exitAltBufferMode(); this.exitApplicationMode(); window.removeEventListener('resize', this.resizeNow); document.removeEventListener('select', this.clearXtermSelectionNow); } isEmptyCursorRow(row) { return row.children.length === 1 && row.children[0].classList.contains('xterm-cursor'); } reflowLineWraps(element = this.terminal.element) { const rows = element.querySelector('.xterm-rows').children; const nLines = this.terminal.buffer.length; for (let idx = 0; idx < nLines - 1; idx++) { const line = this.terminal.buffer.getLine(idx); const nextLine = this.terminal.buffer.getLine(idx + 1); if (nextLine.isWrapped) { if (rows[idx + 1]) { rows[idx + 1].classList.add('xterm-is-wrapped'); } if (!line.isWrapped) { if (rows[idx]) { rows[idx].classList.add('xterm-is-wrapped'); rows[idx].classList.add('xterm-is-wrapped-with-prefix-break'); } } } } } hideTrailingEmptyBlanks(remove = false, element = this.terminal.element, from = 0) { if (this.frozen) { return; } if (!remove) { const hidden = element.querySelectorAll('.xterm-rows > .xterm-hidden-row'); for (let idx = 0; idx < hidden.length; idx++) { hidden[idx].classList.remove('xterm-hidden-row'); } } else { this.frozen = true; } const rows = element.querySelector('.xterm-rows').children; for (let idx = rows.length - 1; idx >= from; idx--) { if (rows[idx].children.length === 0) { if (remove) { rows[idx].remove(); } else { rows[idx].classList.add('xterm-hidden-row'); } } else { break; } } } static hideCursorOnlyRow(element) { util_1.cleanupTerminalAfterTermination(element); } static paddingHorizontal(elt) { const style = window.getComputedStyle(elt); return (parseInt(style.getPropertyValue('padding-left') || '0', 10) + parseInt(style.getPropertyValue('padding-right') || '0', 10)); } static paddingVertical(elt) { const style = window.getComputedStyle(elt); return (parseInt(style.getPropertyValue('padding-top') || '0', 10) + parseInt(style.getPropertyValue('padding-bottom') || '0', 10)); } getSize(forceRecompute) { const cachedSize = getCachedSize(this.tab); if (!forceRecompute && cachedSize !== undefined) { return cachedSize; } const _core = this.terminal._core; const hack = _core.viewport; const dimensions = hack._dimensions; const scaledCharWidth = hack._terminal.charMeasure.width * window.devicePixelRatio; const ratio = scaledCharWidth / dimensions.scaledCharWidth; const selectorForSize = '.repl-inner'; const sizeElement = this.tab.querySelector(selectorForSize); const enclosingRect = sizeElement.getBoundingClientRect(); const selectorForWidthPad = '.repl-inner .repl-block .repl-output'; const widthPadElement = this.tab.querySelector(selectorForWidthPad); const heightPadElement = sizeElement; const width = enclosingRect.width - Resizer.paddingHorizontal(widthPadElement); const height = enclosingRect.height - Resizer.paddingVertical(heightPadElement); const cols = Math.floor(width / dimensions.actualCellWidth / ratio); const rows = Math.floor(height / dimensions.actualCellHeight); debug('getSize', cols, rows, width, height); const newSize = { rows, cols }; if (!isNaN(rows) && !isNaN(cols)) { setCachedSize(this.tab, newSize); } return newSize; } set frozen(val) { this._frozen = val; } get frozen() { return this._frozen; } resize(flush = false, force = false) { if (this.frozen) { return; } const { rows, cols } = this.getSize(flush); if (this.terminal.rows !== rows || this.terminal.cols !== cols || force) { debug('resize', cols, rows, this.terminal.cols, this.terminal.rows, this.inAltBufferMode()); try { if (!isNaN(rows) && !isNaN(cols)) { this.terminal.resize(cols, rows); if (this.ws && this.ws.readyState === WebSocket.OPEN) { this.ws.send(JSON.stringify({ type: 'resize', cols, rows })); } } } catch (err) { debug(err.message); } } } inApplicationMode() { return this.app; } inAltBufferMode() { return this.alt; } wasEverInAltBufferMode() { return this.wasAlt; } enterApplicationMode() { debug('switching to application mode'); this.app = true; this.tab.classList.add('xterm-application-mode'); } exitApplicationMode() { debug('switching from application mode'); this.app = false; this.tab.classList.remove('xterm-application-mode'); } enterAltBufferMode() { debug('switching to alt buffer mode'); this.alt = true; this.wasAlt = true; if (this.exitAlt) { clearTimeout(this.exitAlt); } if (this.execOptions['pty/force-resize']) { const { rows, cols } = this.getSize(false); if (this.ws && this.ws.readyState === WebSocket.OPEN) { this.ws.send(JSON.stringify({ type: 'resize', cols, rows: rows + 1 })); setTimeout(() => { this.ws.send(JSON.stringify({ type: 'resize', cols, rows: rows })); this.tab.classList.add('xterm-alt-buffer-mode'); }, 1); } } else { this.tab.classList.add('xterm-alt-buffer-mode'); } } exitAltBufferMode() { debug('switching from alt buffer mode'); this.alt = false; this.tab.classList.remove('xterm-alt-buffer-mode'); } } let cachedFontProperties; function getFontProperties(flush) { if (flush || !cachedFontProperties) { debug('computing font properties'); const fontTheme = getComputedStyle(document.querySelector('body .repl .repl-input input')); const val = (key, kind = 'color') => fontTheme.getPropertyValue(`--${kind}-${key}`).trim(); const fontSize = parseFloat(fontTheme.fontSize.replace(/px$/, '')); const fontFamily = val('monospace', 'font'); cachedFontProperties = { fontFamily, fontSize }; } return cachedFontProperties; } const injectFont = (terminal, flush = false) => { try { const { fontFamily, fontSize } = getFontProperties(flush); terminal.setOption('fontFamily', fontFamily); terminal.setOption('fontSize', fontSize); debug('fontSize', fontSize); terminal.setOption('fontWeight', 400); terminal.setOption('fontWeightBold', 600); } catch (err) { console.error('Error setting terminal font size', err); } }; const remoteChannelFactory = (tab) => __awaiter(void 0, void 0, void 0, function* () { try { const { url, uid, gid } = yield tab.REPL.qexec('bash websocket open', undefined, undefined, { rethrowErrors: true }); debug('websocket url', url, uid, gid); const WebSocketChannel = (yield Promise.resolve().then(() => require('./websocket-channel'))).default; return new WebSocketChannel(url, uid, gid); } catch (err) { const error = err; if (error.statusCode !== 503) { console.error('error opening websocket', err); } throw err; } }); const electronChannelFactory = () => __awaiter(void 0, void 0, void 0, function* () { const channel = new channel_1.InProcessChannel(); channel.init(); return channel; }); const webviewChannelFactory = () => __awaiter(void 0, void 0, void 0, function* () { console.log('webviewChannelFactory'); const channel = new channel_1.WebViewChannelRendererSide(); channel.init(); return channel; }); const focus = (terminal) => { if (!terminal._kuiAlreadyFocused) { setTimeout(() => { if (!terminal._kuiAlreadyFocused) { terminal._kuiAlreadyFocused = true; terminal.focus(); } }, 0); } }; const getOrCreateChannel = (cmdline, uuid, tab, execOptions, terminal) => __awaiter(void 0, void 0, void 0, function* () { const channelFactory = core_1.Capabilities.inBrowser() ? window['webview-proxy'] !== undefined ? webviewChannelFactory : remoteChannelFactory : electronChannelFactory; const env = Object.assign({}, process.env, execOptions.env || {}); const doExec = (ws) => { const msg = { type: 'exec', cmdline, uuid, rows: terminal.rows, cols: terminal.cols, cwd: process.env.PWD || (!core_1.Capabilities.inBrowser() && process.cwd()), env: Object.keys(env).length > 0 && env }; debug('exec after open', msg); ws.send(JSON.stringify(msg)); }; const cachedws = session.getChannelForTab(tab); if (!cachedws || cachedws.readyState === WebSocket.CLOSING || cachedws.readyState === WebSocket.CLOSED) { const ws = yield channelFactory(tab); tab['ws'] = ws; ws.on('open', () => doExec(ws)); ws.on('close', () => { debug('channel has closed'); if (!tab['state'].closed) { debug('attempting to reestablish connection, because the tab is still open '); ui.setOffline(); session.pollUntilOnline(tab); } }); return ws; } else { doExec(cachedws); focus(terminal); return cachedws; } }); function safeLoadWithCatch(raw) { try { return js_yaml_1.safeLoad(raw); } catch (err) { console.error(err); } } function squashRow(row) { if (row.children.length > 1) { let previous = row.children[0]; let current = row.children[1]; let runningSquash = previous.innerText; while (current) { const next = current.nextElementSibling; if (previous.className === current.className) { current.remove(); runningSquash += current.innerText; } else { if (runningSquash !== previous.innerText) { previous.innerText = runningSquash; } previous = current; runningSquash = previous.innerText; } current = next; } if (runningSquash !== previous.innerText) { previous.innerText = runningSquash; } } if (row.children.length === 1) { const singleton = row.firstElementChild; if (!singleton.className) { singleton.remove(); row.innerText = singleton.innerText; } } } function squash(elt) { const rows = elt.querySelectorAll('.xterm-rows > div'); for (let idx = 0; idx < rows.length; idx++) { squashRow(rows[idx]); } } let alreadyInjectedCSS; function injectXtermCSS() { if (!alreadyInjectedCSS) { if (core_1.Capabilities.inBrowser()) { core_1.UI.injectCSS({ css: require('xterm/lib/xterm.css'), key: 'xtermjs' }); core_1.UI.injectCSS({ css: require('@kui-shell/plugin-bash-like/web/css/xterm.css'), key: 'kui-xtermjs' }); } else { core_1.UI.injectCSS({ path: path.join(path.dirname(require.resolve('xterm/package.json')), 'lib/xterm.css'), key: 'xtermjs' }); core_1.UI.injectCSS({ path: path.join(path.dirname(require.resolve('@kui-shell/plugin-bash-like/package.json')), 'web/css/xterm.css'), key: 'kui-xtermjs' }); } alreadyInjectedCSS = true; return true; } else { return false; } } exports.doExec = (tab, block, cmdline, argvNoOptions, parsedOptions, execOptions) => new Promise((resolve, reject) => { const contentType = parsedOptions.o || parsedOptions.output || parsedOptions.out || (argvNoOptions[0] === 'cat' && /json$/.test(argvNoOptions[1]) && 'json') || (argvNoOptions[0] === 'cat' && (/yaml$/.test(argvNoOptions[1]) || /yml$/.test(argvNoOptions[1])) && 'yaml'); const expectingSemiStructuredOutput = /yaml|json/.test(contentType); const injectingCSS = injectXtermCSS(); const exec = () => __awaiter(void 0, void 0, void 0, function* () { try { const parent = block.querySelector('.repl-result'); const xtermContainer = document.createElement('xterm'); xtermContainer.classList.add('xterm-container'); xtermContainer.classList.add('repl-output-like'); parent.appendChild(xtermContainer); if (execOptions.replSilence) { debug('repl silence'); xtermContainer.style.display = 'none'; xtermContainer.classList.add('repl-temporary'); } cli_1.setCustomCaret(block); const cachedSize = getCachedSize(tab); const { fontFamily, fontSize } = getFontProperties(false); const terminal = new xterm.Terminal({ rendererType: 'dom', cols: cachedSize && cachedSize.cols, rows: cachedSize && cachedSize.rows, fontFamily, fontSize }); let cbAfterPendingWrites; let pendingWrites = 0; terminal.open(xtermContainer); webLinks_1.webLinksInit(terminal); const doInjectTheme = () => injectFont(terminal, true); core_1.eventBus.on('/theme/change', doInjectTheme); const resizer = new Resizer(terminal, tab, execOptions); const doZoom = () => { injectFont(terminal, true); resizer.resize(); }; core_1.eventBus.on('/zoom', doZoom); const cleanupEventHandlers = () => { core_1.eventBus.off('/zoom', doZoom); core_1.eventBus.off('/theme/change', doInjectTheme); }; terminal.element.classList.add('xterm-empty-row-heuristic'); setTimeout(() => terminal.element.classList.remove('xterm-empty-row-heuristic'), 100); const cleanUpTerminal = () => { cleanupEventHandlers(); resizer.destroy(); if (execOptions.type === core_1.Commands.ExecType.Nested && execOptions.quiet !== false) { xtermContainer.remove(); } else { xtermContainer.classList.add('xterm-terminated'); } }; const ourUUID = uuid_1.v4(); const ws = yield getOrCreateChannel(cmdline, ourUUID, tab, execOptions, terminal).catch((err) => { if (err.code !== 503) { console.error('error creating channel', err); } cleanUpTerminal(); throw err; }); resizer.ws = ws; let definitelyNotUsage = argvNoOptions[0] === 'git' || execOptions.rawResponse; let definitelyNotTable = expectingSemiStructuredOutput || argvNoOptions[0] === 'grep' || execOptions.rawResponse; let queuedInput = ''; let flushAsync; terminal.on('key', (key) => { if (ws.readyState === WebSocket.CLOSING || ws.readyState === WebSocket.CLOSED) { debug('queued input out back', key); queuedInput += key; } else { queuedInput += key; definitelyNotTable = true; definitelyNotUsage = true; if (flushAsync) { clearTimeout(flushAsync); } flushAsync = setTimeout(() => { if (queuedInput && ws.readyState === WebSocket.OPEN) { const data = queuedInput; queuedInput = ''; ws.send(JSON.stringify({ type: 'data', data, uid: ourUUID })); } }, 20); } }); const maybeClearSelection = () => { if (!terminal.hasSelection()) { cli_1.clearPendingTextSelection(); } }; terminal.on('focus', maybeClearSelection); terminal.on('blur', maybeClearSelection); terminal.on('paste', (data) => { ws.send(JSON.stringify({ type: 'data', data })); }); terminal.on('selection', () => { cli_1.clearTextSelection(); cli_1.setPendingTextSelection(terminal.getSelection()); }); const activeDiv = tab.querySelector('.repl-inner'); const doScroll = () => { if (!resizer.inAltBufferMode()) { activeDiv.scrollTop = activeDiv.scrollHeight; } }; const scrollPoll = setInterval(doScroll, 200); const notifyOfWriteCompletion = () => { if (pendingWrites > 0) { pendingWrites = 0; if (cbAfterPendingWrites) { cbAfterPendingWrites(); cbAfterPendingWrites = undefined; } } }; let first = true; const onRefresh = (evt) => __awaiter(void 0, void 0, void 0, function* () { if (evt.end > evt.start || first) { resizer.hideTrailingEmptyBlanks(); } notifyOfWriteCompletion(); first = false; }); terminal.on('refresh', onRefresh); let bytesWereWritten = false; let sawCode; let pendingUsage = false; let pendingTable; let raw = ''; let nLinesRaw = 0; const onFirstMessage = () => { const queuedInput = cli_1.disableInputQueueing(); if (queuedInput.length > 0) { debug('queued input up front', queuedInput); setTimeout(() => ws.send(JSON.stringify({ type: 'data', data: queuedInput })), 50); } focus(terminal); }; const onMessage = (data) => __awaiter(void 0, void 0, void 0, function* () { const msg = JSON.parse(data); if (msg.uuid !== ourUUID) { return; } if (msg.type === 'state' && msg.state === 'ready') { onFirstMessage(); } else if (msg.type === 'data') { if (!terminal._kuiAlreadyFocused) { onFirstMessage(); } const flush = () => { if (pendingTable) { pendingTable = undefined; definitelyNotTable = true; definitelyNotUsage = true; bytesWereWritten = true; sawCode = /File exists/i.test(raw) ? 409 : /no such/i.test(raw) || /not found/i.test(raw) ? 404 : sawCode; terminal.write(raw); raw = ''; } }; if (enterApplicationModePattern.test(msg.data)) { flush(); resizer.enterApplicationMode(); focus(terminal); } else if (exitApplicationModePattern.test(msg.data)) { resizer.exitApplicationMode(); } if (enterAltBufferPattern.test(msg.data)) { flush(); focus(terminal); resizer.enterAltBufferMode(); } else if (exitAltBufferPattern.test(msg.data)) { resizer.exitAltBufferMode(); } else if (!resizer.inAltBufferMode()) { raw += msg.data; } const maybeUsage = !resizer.wasEverInAltBufferMode() && !definitelyNotUsage && (pendingUsage || ascii_to_usage_1.formatUsage(cmdline, strip_ansi_1.default(raw), { drilldownWithPip: true })); if (!definitelyNotTable && raw.length > 0 && !resizer.wasEverInAltBufferMode()) { try { const tables = (yield ascii_to_table_1.preprocessTable(raw.split(/^(?=NAME|Name|ID|\n\*)/m))).filter(x => x); if (tables && tables.length > 0) { const tableRows = core_1.Util.flatten(tables.filter(_ => _.rows !== undefined).map(_ => _.rows)); if (tableRows && tableRows.length > 0) { const entityType = /\w+/.test(argvNoOptions[2]) && argvNoOptions[2]; const tableModel = ascii_to_table_1.formatTable(entityType, tableRows); debug('tableModel', tableModel); const trailingStrings = tables.map(_ => _.trailingString).filter(x => x); if (trailingStrings && trailingStrings.length > 0) { const trailers = yield core_1.UI.PrettyPrinters.ansi(trailingStrings); if (!trailers) { pendingTable = [tableModel]; } else { pendingTable = [tableModel, trailers]; } } else { pendingTable = [tableModel]; } } else if (raw.length > 1000) { definitelyNotTable = true; } } else { debug('definitelyNotTable'); definitelyNotTable = true; } } catch (err) { console.error('error parsing as table', err); definitelyNotTable = true; } } if (pendingTable || expectingSemiStructuredOutput) { } else if (maybeUsage) { debug('pending usage'); pendingUsage = true; } else { if (raw.length > 500) { definitelyNotUsage = true; } else if (raw.length > 1500) { definitelyNotTable = true; } if (execOptions.type !== core_1.Commands.ExecType.Nested || execOptions.quiet === false) { pendingWrites++; definitelyNotUsage = true; bytesWereWritten = true; sawCode = /File exists/i.test(raw) ? 409 : /no such/i.test(raw) || /not found/i.test(raw) ? 404 : sawCode; for (let idx = 0; idx < msg.data.length; idx++) { if (msg.data[idx] === '\n') { nLinesRaw++; } } terminal.write(msg.data); raw = ''; } } } else if (msg.type === 'exit') { if (pendingTable && !pendingTable.some(_ => core_1.Tables.isTable(_) && _.body.length > 0)) { if (execOptions.type !== core_1.Commands.ExecType.Nested || execOptions.quiet === false) { bytesWereWritten = true; sawCode = /File exists/i.test(raw) ? 409 : /no such/i.test(raw) || /not found/i.test(raw) ? 404 : sawCode; terminal.write(raw); raw = ''; } pendingTable = undefined; } const respondToRepl = () => { if (pendingUsage) { execOptions.stdout(ascii_to_usage_1.formatUsage(cmdline, strip_ansi_1.default(raw), { drilldownWithPip: true })); xtermContainer.classList.add('xterm-invisible'); } else if (pendingTable) { const response = pendingTable; execOptions.stdout(response.length === 1 ? response[0] : response); } else if (expectingSemiStructuredOutput) { try { const resource = contentType === 'yaml' ? safeLoadWithCatch(strip_ansi_1.default(raw)) : JSON.parse(strip_ansi_1.default(raw)); if (typeof resource === 'string') { execOptions.stdout(resource); } else { execOptions.stdout({ type: 'custom', isEntity: true, name: argvNoOptions[0] === 'cat' ? path.basename(argvNoOptions[1]) : argvNoOptions.slice(3).join(' '), packageName: argvNoOptions[0] === 'cat' && path.dirname(argvNoOptions[1]), prettyType: argvNoOptions[0] === 'cat' ? contentType : argvNoOptions[2], contentType, content: strip_ansi_1.default(raw), resource, modes: [{ mode: 'raw', direct: cmdline, defaultMode: true }] }); } } catch (err) { console.error('error parsing as semi structured output'); console.error(strip_ansi_1.default(raw)); execOptions.stdout(strip_ansi_1.default(raw)); } } if (msg.exitCode !== 0 && bytesWereWritten) { const error = new Error(''); if (sawCode === 409) error['code'] = 409; else if (msg.exitCode !== 127 && sawCode === 404) error['code'] = 404; else error['code'] = msg.exitCode; if (msg.exitCode === 127) { xtermContainer.classList.add('hide'); } else { error['hide'] = true; } reject(error); } else { if (queuedInput && queuedInput.length > 0) { cli_1.pasteQueuedInput(queuedInput); } resolve(true); } }; const finishUpAfterFinalResize = () => { clearInterval(scrollPoll); doScroll(); ws.removeEventListener('message', onMessage); cleanUpTerminal(); const copy = terminal.element.cloneNode(true); squash(copy); copy.querySelector('.xterm-viewport').remove(); copy.querySelector('.xterm-helpers').remove(); copy.querySelector('.xterm-selection').remove(); const styles = copy.querySelectorAll('style'); for (let idx = 0; idx < styles.length; idx++) { styles[idx].remove(); } copy.classList.remove('enable-mouse-events'); resizer.reflowLineWraps(copy); resizer.hideTrailingEmptyBlanks(true, copy); Resizer.hideCursorOnlyRow(copy); xtermContainer.removeChild(terminal.element); xtermContainer.appendChild(copy); respondToRepl(); }; const finishUp = () => { const nLines = terminal.buffer.length; if (resizer.wasEverInAltBufferMode() || (nLines <= terminal.rows && nLinesRaw < terminal.rows)) { setTimeout(finishUpAfterFinalResize, 50); } else { terminal.off('refresh', onRefresh); terminal.on('refresh', finishUpAfterFinalResize); terminal.resize(terminal.cols, nLines); } }; const nLines = terminal.buffer.length; doScroll(); if (pendingWrites > 0) { if (!resizer.wasEverInAltBufferMode() && nLines <= terminal.rows && nLinesRaw < terminal.rows) { cbAfterPendingWrites = finishUp; } else { cbAfterPendingWrites = () => setTimeout(finishUp, 50); } } else { if (nLines <= terminal.rows && nLinesRaw < terminal.rows) { setTimeout(finishUp, 100); } else { setTimeout(finishUp, 400); } } } }); ws.on('message', onMessage); } catch (error) { const err = error; if (err.code === 127 || err.code === 404) { err.code = 127; reject(err); } else { if (err.code !== 503) { debug('error in pty/client', err); } if (!err.message) { err.message = 'Internal Error'; } reject(err); } } }); if (injectingCSS) { setTimeout(exec, 0); } else { exec(); } }); //# sourceMappingURL=client.js.map