diff options
Diffstat (limited to 'node_modules/xterm/src')
103 files changed, 0 insertions, 22853 deletions
diff --git a/node_modules/xterm/src/browser/AccessibilityManager.ts b/node_modules/xterm/src/browser/AccessibilityManager.ts deleted file mode 100644 index c162abc..0000000 --- a/node_modules/xterm/src/browser/AccessibilityManager.ts +++ /dev/null @@ -1,301 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import * as Strings from 'browser/LocalizableStrings'; -import { ITerminal, IRenderDebouncer } from 'browser/Types'; -import { IBuffer } from 'common/buffer/Types'; -import { isMac } from 'common/Platform'; -import { TimeBasedDebouncer } from 'browser/TimeBasedDebouncer'; -import { addDisposableDomListener } from 'browser/Lifecycle'; -import { Disposable } from 'common/Lifecycle'; -import { ScreenDprMonitor } from 'browser/ScreenDprMonitor'; -import { IRenderService } from 'browser/services/Services'; -import { removeElementFromParent } from 'browser/Dom'; - -const MAX_ROWS_TO_READ = 20; - -const enum BoundaryPosition { - TOP, - BOTTOM -} - -export class AccessibilityManager extends Disposable { - private _accessibilityTreeRoot: HTMLElement; - private _rowContainer: HTMLElement; - private _rowElements: HTMLElement[]; - private _liveRegion: HTMLElement; - private _liveRegionLineCount: number = 0; - - private _renderRowsDebouncer: IRenderDebouncer; - private _screenDprMonitor: ScreenDprMonitor; - - private _topBoundaryFocusListener: (e: FocusEvent) => void; - private _bottomBoundaryFocusListener: (e: FocusEvent) => void; - - /** - * This queue has a character pushed to it for keys that are pressed, if the - * next character added to the terminal is equal to the key char then it is - * not announced (added to live region) because it has already been announced - * by the textarea event (which cannot be canceled). There are some race - * condition cases if there is typing while data is streaming, but this covers - * the main case of typing into the prompt and inputting the answer to a - * question (Y/N, etc.). - */ - private _charsToConsume: string[] = []; - - private _charsToAnnounce: string = ''; - - constructor( - private readonly _terminal: ITerminal, - private readonly _renderService: IRenderService - ) { - super(); - this._accessibilityTreeRoot = document.createElement('div'); - this._accessibilityTreeRoot.classList.add('xterm-accessibility'); - this._accessibilityTreeRoot.tabIndex = 0; - - this._rowContainer = document.createElement('div'); - this._rowContainer.setAttribute('role', 'list'); - this._rowContainer.classList.add('xterm-accessibility-tree'); - this._rowElements = []; - for (let i = 0; i < this._terminal.rows; i++) { - this._rowElements[i] = this._createAccessibilityTreeNode(); - this._rowContainer.appendChild(this._rowElements[i]); - } - - this._topBoundaryFocusListener = e => this._onBoundaryFocus(e, BoundaryPosition.TOP); - this._bottomBoundaryFocusListener = e => this._onBoundaryFocus(e, BoundaryPosition.BOTTOM); - this._rowElements[0].addEventListener('focus', this._topBoundaryFocusListener); - this._rowElements[this._rowElements.length - 1].addEventListener('focus', this._bottomBoundaryFocusListener); - - this._refreshRowsDimensions(); - this._accessibilityTreeRoot.appendChild(this._rowContainer); - - this._renderRowsDebouncer = new TimeBasedDebouncer(this._renderRows.bind(this)); - this._refreshRows(); - - this._liveRegion = document.createElement('div'); - this._liveRegion.classList.add('live-region'); - this._liveRegion.setAttribute('aria-live', 'assertive'); - this._accessibilityTreeRoot.appendChild(this._liveRegion); - - if (!this._terminal.element) { - throw new Error('Cannot enable accessibility before Terminal.open'); - } - this._terminal.element.insertAdjacentElement('afterbegin', this._accessibilityTreeRoot); - - this.register(this._renderRowsDebouncer); - this.register(this._terminal.onResize(e => this._onResize(e.rows))); - this.register(this._terminal.onRender(e => this._refreshRows(e.start, e.end))); - this.register(this._terminal.onScroll(() => this._refreshRows())); - // Line feed is an issue as the prompt won't be read out after a command is run - this.register(this._terminal.onA11yChar(char => this._onChar(char))); - this.register(this._terminal.onLineFeed(() => this._onChar('\n'))); - this.register(this._terminal.onA11yTab(spaceCount => this._onTab(spaceCount))); - this.register(this._terminal.onKey(e => this._onKey(e.key))); - this.register(this._terminal.onBlur(() => this._clearLiveRegion())); - this.register(this._renderService.onDimensionsChange(() => this._refreshRowsDimensions())); - - this._screenDprMonitor = new ScreenDprMonitor(); - this.register(this._screenDprMonitor); - this._screenDprMonitor.setListener(() => this._refreshRowsDimensions()); - // This shouldn't be needed on modern browsers but is present in case the - // media query that drives the ScreenDprMonitor isn't supported - this.register(addDisposableDomListener(window, 'resize', () => this._refreshRowsDimensions())); - } - - public dispose(): void { - super.dispose(); - removeElementFromParent(this._accessibilityTreeRoot); - this._rowElements.length = 0; - } - - private _onBoundaryFocus(e: FocusEvent, position: BoundaryPosition): void { - const boundaryElement = e.target as HTMLElement; - const beforeBoundaryElement = this._rowElements[position === BoundaryPosition.TOP ? 1 : this._rowElements.length - 2]; - - // Don't scroll if the buffer top has reached the end in that direction - const posInSet = boundaryElement.getAttribute('aria-posinset'); - const lastRowPos = position === BoundaryPosition.TOP ? '1' : `${this._terminal.buffer.lines.length}`; - if (posInSet === lastRowPos) { - return; - } - - // Don't scroll when the last focused item was not the second row (focus is going the other - // direction) - if (e.relatedTarget !== beforeBoundaryElement) { - return; - } - - // Remove old boundary element from array - let topBoundaryElement: HTMLElement; - let bottomBoundaryElement: HTMLElement; - if (position === BoundaryPosition.TOP) { - topBoundaryElement = boundaryElement; - bottomBoundaryElement = this._rowElements.pop()!; - this._rowContainer.removeChild(bottomBoundaryElement); - } else { - topBoundaryElement = this._rowElements.shift()!; - bottomBoundaryElement = boundaryElement; - this._rowContainer.removeChild(topBoundaryElement); - } - - // Remove listeners from old boundary elements - topBoundaryElement.removeEventListener('focus', this._topBoundaryFocusListener); - bottomBoundaryElement.removeEventListener('focus', this._bottomBoundaryFocusListener); - - // Add new element to array/DOM - if (position === BoundaryPosition.TOP) { - const newElement = this._createAccessibilityTreeNode(); - this._rowElements.unshift(newElement); - this._rowContainer.insertAdjacentElement('afterbegin', newElement); - } else { - const newElement = this._createAccessibilityTreeNode(); - this._rowElements.push(newElement); - this._rowContainer.appendChild(newElement); - } - - // Add listeners to new boundary elements - this._rowElements[0].addEventListener('focus', this._topBoundaryFocusListener); - this._rowElements[this._rowElements.length - 1].addEventListener('focus', this._bottomBoundaryFocusListener); - - // Scroll up - this._terminal.scrollLines(position === BoundaryPosition.TOP ? -1 : 1); - - // Focus new boundary before element - this._rowElements[position === BoundaryPosition.TOP ? 1 : this._rowElements.length - 2].focus(); - - // Prevent the standard behavior - e.preventDefault(); - e.stopImmediatePropagation(); - } - - private _onResize(rows: number): void { - // Remove bottom boundary listener - this._rowElements[this._rowElements.length - 1].removeEventListener('focus', this._bottomBoundaryFocusListener); - - // Grow rows as required - for (let i = this._rowContainer.children.length; i < this._terminal.rows; i++) { - this._rowElements[i] = this._createAccessibilityTreeNode(); - this._rowContainer.appendChild(this._rowElements[i]); - } - // Shrink rows as required - while (this._rowElements.length > rows) { - this._rowContainer.removeChild(this._rowElements.pop()!); - } - - // Add bottom boundary listener - this._rowElements[this._rowElements.length - 1].addEventListener('focus', this._bottomBoundaryFocusListener); - - this._refreshRowsDimensions(); - } - - private _createAccessibilityTreeNode(): HTMLElement { - const element = document.createElement('div'); - element.setAttribute('role', 'listitem'); - element.tabIndex = -1; - this._refreshRowDimensions(element); - return element; - } - - private _onTab(spaceCount: number): void { - for (let i = 0; i < spaceCount; i++) { - this._onChar(' '); - } - } - - private _onChar(char: string): void { - if (this._liveRegionLineCount < MAX_ROWS_TO_READ + 1) { - if (this._charsToConsume.length > 0) { - // Have the screen reader ignore the char if it was just input - const shiftedChar = this._charsToConsume.shift(); - if (shiftedChar !== char) { - this._charsToAnnounce += char; - } - } else { - this._charsToAnnounce += char; - } - - if (char === '\n') { - this._liveRegionLineCount++; - if (this._liveRegionLineCount === MAX_ROWS_TO_READ + 1) { - this._liveRegion.textContent += Strings.tooMuchOutput; - } - } - - // Only detach/attach on mac as otherwise messages can go unaccounced - if (isMac) { - if (this._liveRegion.textContent && this._liveRegion.textContent.length > 0 && !this._liveRegion.parentNode) { - setTimeout(() => { - this._accessibilityTreeRoot.appendChild(this._liveRegion); - }, 0); - } - } - } - } - - private _clearLiveRegion(): void { - this._liveRegion.textContent = ''; - this._liveRegionLineCount = 0; - - // Only detach/attach on mac as otherwise messages can go unaccounced - if (isMac) { - removeElementFromParent(this._liveRegion); - } - } - - private _onKey(keyChar: string): void { - this._clearLiveRegion(); - this._charsToConsume.push(keyChar); - } - - private _refreshRows(start?: number, end?: number): void { - this._renderRowsDebouncer.refresh(start, end, this._terminal.rows); - } - - private _renderRows(start: number, end: number): void { - const buffer: IBuffer = this._terminal.buffer; - const setSize = buffer.lines.length.toString(); - for (let i = start; i <= end; i++) { - const lineData = buffer.translateBufferLineToString(buffer.ydisp + i, true); - const posInSet = (buffer.ydisp + i + 1).toString(); - const element = this._rowElements[i]; - if (element) { - if (lineData.length === 0) { - element.innerText = '\u00a0'; - } else { - element.textContent = lineData; - } - element.setAttribute('aria-posinset', posInSet); - element.setAttribute('aria-setsize', setSize); - } - } - this._announceCharacters(); - } - - private _refreshRowsDimensions(): void { - if (!this._renderService.dimensions.actualCellHeight) { - return; - } - if (this._rowElements.length !== this._terminal.rows) { - this._onResize(this._terminal.rows); - } - for (let i = 0; i < this._terminal.rows; i++) { - this._refreshRowDimensions(this._rowElements[i]); - } - } - - private _refreshRowDimensions(element: HTMLElement): void { - element.style.height = `${this._renderService.dimensions.actualCellHeight}px`; - } - - private _announceCharacters(): void { - if (this._charsToAnnounce.length === 0) { - return; - } - this._liveRegion.textContent += this._charsToAnnounce; - this._charsToAnnounce = ''; - } -} diff --git a/node_modules/xterm/src/browser/Clipboard.ts b/node_modules/xterm/src/browser/Clipboard.ts deleted file mode 100644 index 29e865c..0000000 --- a/node_modules/xterm/src/browser/Clipboard.ts +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Copyright (c) 2016 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { ISelectionService } from 'browser/services/Services'; -import { ICoreService } from 'common/services/Services'; - -/** - * Prepares text to be pasted into the terminal by normalizing the line endings - * @param text The pasted text that needs processing before inserting into the terminal - */ -export function prepareTextForTerminal(text: string): string { - return text.replace(/\r?\n/g, '\r'); -} - -/** - * Bracket text for paste, if necessary, as per https://cirw.in/blog/bracketed-paste - * @param text The pasted text to bracket - */ -export function bracketTextForPaste(text: string, bracketedPasteMode: boolean): string { - if (bracketedPasteMode) { - return '\x1b[200~' + text + '\x1b[201~'; - } - return text; -} - -/** - * Binds copy functionality to the given terminal. - * @param ev The original copy event to be handled - */ -export function copyHandler(ev: ClipboardEvent, selectionService: ISelectionService): void { - if (ev.clipboardData) { - ev.clipboardData.setData('text/plain', selectionService.selectionText); - } - // Prevent or the original text will be copied. - ev.preventDefault(); -} - -/** - * Redirect the clipboard's data to the terminal's input handler. - * @param ev The original paste event to be handled - * @param term The terminal on which to apply the handled paste event - */ -export function handlePasteEvent(ev: ClipboardEvent, textarea: HTMLTextAreaElement, coreService: ICoreService): void { - ev.stopPropagation(); - if (ev.clipboardData) { - const text = ev.clipboardData.getData('text/plain'); - paste(text, textarea, coreService); - } -} - -export function paste(text: string, textarea: HTMLTextAreaElement, coreService: ICoreService): void { - text = prepareTextForTerminal(text); - text = bracketTextForPaste(text, coreService.decPrivateModes.bracketedPasteMode); - coreService.triggerDataEvent(text, true); - textarea.value = ''; -} - -/** - * Moves the textarea under the mouse cursor and focuses it. - * @param ev The original right click event to be handled. - * @param textarea The terminal's textarea. - */ -export function moveTextAreaUnderMouseCursor(ev: MouseEvent, textarea: HTMLTextAreaElement, screenElement: HTMLElement): void { - - // Calculate textarea position relative to the screen element - const pos = screenElement.getBoundingClientRect(); - const left = ev.clientX - pos.left - 10; - const top = ev.clientY - pos.top - 10; - - // Bring textarea at the cursor position - textarea.style.width = '20px'; - textarea.style.height = '20px'; - textarea.style.left = `${left}px`; - textarea.style.top = `${top}px`; - textarea.style.zIndex = '1000'; - - textarea.focus(); -} - -/** - * Bind to right-click event and allow right-click copy and paste. - * @param ev The original right click event to be handled. - * @param textarea The terminal's textarea. - * @param selectionService The terminal's selection manager. - * @param shouldSelectWord If true and there is no selection the current word will be selected - */ -export function rightClickHandler(ev: MouseEvent, textarea: HTMLTextAreaElement, screenElement: HTMLElement, selectionService: ISelectionService, shouldSelectWord: boolean): void { - moveTextAreaUnderMouseCursor(ev, textarea, screenElement); - - if (shouldSelectWord) { - selectionService.rightClickSelect(ev); - } - - // Get textarea ready to copy from the context menu - textarea.value = selectionService.selectionText; - textarea.select(); -} diff --git a/node_modules/xterm/src/browser/Color.ts b/node_modules/xterm/src/browser/Color.ts deleted file mode 100644 index 32e311d..0000000 --- a/node_modules/xterm/src/browser/Color.ts +++ /dev/null @@ -1,236 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IColor } from 'browser/Types'; -import { IColorRGB } from 'common/Types'; - -/** - * Helper functions where the source type is "channels" (individual color channels as numbers). - */ -export namespace channels { - export function toCss(r: number, g: number, b: number, a?: number): string { - if (a !== undefined) { - return `#${toPaddedHex(r)}${toPaddedHex(g)}${toPaddedHex(b)}${toPaddedHex(a)}`; - } - return `#${toPaddedHex(r)}${toPaddedHex(g)}${toPaddedHex(b)}`; - } - - export function toRgba(r: number, g: number, b: number, a: number = 0xFF): number { - // Note: The aggregated number is RGBA32 (BE), thus needs to be converted to ABGR32 - // on LE systems, before it can be used for direct 32-bit buffer writes. - // >>> 0 forces an unsigned int - return (r << 24 | g << 16 | b << 8 | a) >>> 0; - } -} - -/** - * Helper functions where the source type is `IColor`. - */ -export namespace color { - export function blend(bg: IColor, fg: IColor): IColor { - const a = (fg.rgba & 0xFF) / 255; - if (a === 1) { - return { - css: fg.css, - rgba: fg.rgba - }; - } - const fgR = (fg.rgba >> 24) & 0xFF; - const fgG = (fg.rgba >> 16) & 0xFF; - const fgB = (fg.rgba >> 8) & 0xFF; - const bgR = (bg.rgba >> 24) & 0xFF; - const bgG = (bg.rgba >> 16) & 0xFF; - const bgB = (bg.rgba >> 8) & 0xFF; - const r = bgR + Math.round((fgR - bgR) * a); - const g = bgG + Math.round((fgG - bgG) * a); - const b = bgB + Math.round((fgB - bgB) * a); - const css = channels.toCss(r, g, b); - const rgba = channels.toRgba(r, g, b); - return { css, rgba }; - } - - export function isOpaque(color: IColor): boolean { - return (color.rgba & 0xFF) === 0xFF; - } - - export function ensureContrastRatio(bg: IColor, fg: IColor, ratio: number): IColor | undefined { - const result = rgba.ensureContrastRatio(bg.rgba, fg.rgba, ratio); - if (!result) { - return undefined; - } - return rgba.toColor( - (result >> 24 & 0xFF), - (result >> 16 & 0xFF), - (result >> 8 & 0xFF) - ); - } - - export function opaque(color: IColor): IColor { - const rgbaColor = (color.rgba | 0xFF) >>> 0; - const [r, g, b] = rgba.toChannels(rgbaColor); - return { - css: channels.toCss(r, g, b), - rgba: rgbaColor - }; - } - - export function opacity(color: IColor, opacity: number): IColor { - const a = Math.round(opacity * 0xFF); - const [r, g, b] = rgba.toChannels(color.rgba); - return { - css: channels.toCss(r, g, b, a), - rgba: channels.toRgba(r, g, b, a) - }; - } - - export function toColorRGB(color: IColor): IColorRGB { - return [(color.rgba >> 24) & 0xFF, (color.rgba >> 16) & 0xFF, (color.rgba >> 8) & 0xFF]; - } -} - -/** - * Helper functions where the source type is "css" (string: '#rgb', '#rgba', '#rrggbb', '#rrggbbaa'). - */ -export namespace css { - export function toColor(css: string): IColor { - switch (css.length) { - case 7: // #rrggbb - return { - css, - rgba: (parseInt(css.slice(1), 16) << 8 | 0xFF) >>> 0 - }; - case 9: // #rrggbbaa - return { - css, - rgba: parseInt(css.slice(1), 16) >>> 0 - }; - } - throw new Error('css.toColor: Unsupported css format'); - } -} - -/** - * Helper functions where the source type is "rgb" (number: 0xrrggbb). - */ -export namespace rgb { - /** - * Gets the relative luminance of an RGB color, this is useful in determining the contrast ratio - * between two colors. - * @param rgb The color to use. - * @see https://www.w3.org/TR/WCAG20/#relativeluminancedef - */ - export function relativeLuminance(rgb: number): number { - return relativeLuminance2( - (rgb >> 16) & 0xFF, - (rgb >> 8 ) & 0xFF, - (rgb ) & 0xFF); - } - - /** - * Gets the relative luminance of an RGB color, this is useful in determining the contrast ratio - * between two colors. - * @param r The red channel (0x00 to 0xFF). - * @param g The green channel (0x00 to 0xFF). - * @param b The blue channel (0x00 to 0xFF). - * @see https://www.w3.org/TR/WCAG20/#relativeluminancedef - */ - export function relativeLuminance2(r: number, g: number, b: number): number { - const rs = r / 255; - const gs = g / 255; - const bs = b / 255; - const rr = rs <= 0.03928 ? rs / 12.92 : Math.pow((rs + 0.055) / 1.055, 2.4); - const rg = gs <= 0.03928 ? gs / 12.92 : Math.pow((gs + 0.055) / 1.055, 2.4); - const rb = bs <= 0.03928 ? bs / 12.92 : Math.pow((bs + 0.055) / 1.055, 2.4); - return rr * 0.2126 + rg * 0.7152 + rb * 0.0722; - } -} - -/** - * Helper functions where the source type is "rgba" (number: 0xrrggbbaa). - */ -export namespace rgba { - export function ensureContrastRatio(bgRgba: number, fgRgba: number, ratio: number): number | undefined { - const bgL = rgb.relativeLuminance(bgRgba >> 8); - const fgL = rgb.relativeLuminance(fgRgba >> 8); - const cr = contrastRatio(bgL, fgL); - if (cr < ratio) { - if (fgL < bgL) { - return reduceLuminance(bgRgba, fgRgba, ratio); - } - return increaseLuminance(bgRgba, fgRgba, ratio); - } - return undefined; - } - - export function reduceLuminance(bgRgba: number, fgRgba: number, ratio: number): number { - // This is a naive but fast approach to reducing luminance as converting to - // HSL and back is expensive - const bgR = (bgRgba >> 24) & 0xFF; - const bgG = (bgRgba >> 16) & 0xFF; - const bgB = (bgRgba >> 8) & 0xFF; - let fgR = (fgRgba >> 24) & 0xFF; - let fgG = (fgRgba >> 16) & 0xFF; - let fgB = (fgRgba >> 8) & 0xFF; - let cr = contrastRatio(rgb.relativeLuminance2(fgR, fgB, fgG), rgb.relativeLuminance2(bgR, bgG, bgB)); - while (cr < ratio && (fgR > 0 || fgG > 0 || fgB > 0)) { - // Reduce by 10% until the ratio is hit - fgR -= Math.max(0, Math.ceil(fgR * 0.1)); - fgG -= Math.max(0, Math.ceil(fgG * 0.1)); - fgB -= Math.max(0, Math.ceil(fgB * 0.1)); - cr = contrastRatio(rgb.relativeLuminance2(fgR, fgB, fgG), rgb.relativeLuminance2(bgR, bgG, bgB)); - } - return (fgR << 24 | fgG << 16 | fgB << 8 | 0xFF) >>> 0; - } - - export function increaseLuminance(bgRgba: number, fgRgba: number, ratio: number): number { - // This is a naive but fast approach to increasing luminance as converting to - // HSL and back is expensive - const bgR = (bgRgba >> 24) & 0xFF; - const bgG = (bgRgba >> 16) & 0xFF; - const bgB = (bgRgba >> 8) & 0xFF; - let fgR = (fgRgba >> 24) & 0xFF; - let fgG = (fgRgba >> 16) & 0xFF; - let fgB = (fgRgba >> 8) & 0xFF; - let cr = contrastRatio(rgb.relativeLuminance2(fgR, fgB, fgG), rgb.relativeLuminance2(bgR, bgG, bgB)); - while (cr < ratio && (fgR < 0xFF || fgG < 0xFF || fgB < 0xFF)) { - // Increase by 10% until the ratio is hit - fgR = Math.min(0xFF, fgR + Math.ceil((255 - fgR) * 0.1)); - fgG = Math.min(0xFF, fgG + Math.ceil((255 - fgG) * 0.1)); - fgB = Math.min(0xFF, fgB + Math.ceil((255 - fgB) * 0.1)); - cr = contrastRatio(rgb.relativeLuminance2(fgR, fgB, fgG), rgb.relativeLuminance2(bgR, bgG, bgB)); - } - return (fgR << 24 | fgG << 16 | fgB << 8 | 0xFF) >>> 0; - } - - // FIXME: Move this to channels NS? - export function toChannels(value: number): [number, number, number, number] { - return [(value >> 24) & 0xFF, (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF]; - } - - export function toColor(r: number, g: number, b: number): IColor { - return { - css: channels.toCss(r, g, b), - rgba: channels.toRgba(r, g, b) - }; - } -} - -export function toPaddedHex(c: number): string { - const s = c.toString(16); - return s.length < 2 ? '0' + s : s; -} - -/** - * Gets the contrast ratio between two relative luminance values. - * @param l1 The first relative luminance. - * @param l2 The first relative luminance. - * @see https://www.w3.org/TR/WCAG20/#contrast-ratiodef - */ -export function contrastRatio(l1: number, l2: number): number { - if (l1 < l2) { - return (l2 + 0.05) / (l1 + 0.05); - } - return (l1 + 0.05) / (l2 + 0.05); -} diff --git a/node_modules/xterm/src/browser/ColorContrastCache.ts b/node_modules/xterm/src/browser/ColorContrastCache.ts deleted file mode 100644 index b96b66c..0000000 --- a/node_modules/xterm/src/browser/ColorContrastCache.ts +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IColor, IColorContrastCache } from 'browser/Types'; - -export class ColorContrastCache implements IColorContrastCache { - private _color: { [bg: number]: { [fg: number]: IColor | null | undefined } | undefined } = {}; - private _rgba: { [bg: number]: { [fg: number]: string | null | undefined } | undefined } = {}; - - public clear(): void { - this._color = {}; - this._rgba = {}; - } - - public setCss(bg: number, fg: number, value: string | null): void { - if (!this._rgba[bg]) { - this._rgba[bg] = {}; - } - this._rgba[bg]![fg] = value; - } - - public getCss(bg: number, fg: number): string | null | undefined { - return this._rgba[bg] ? this._rgba[bg]![fg] : undefined; - } - - public setColor(bg: number, fg: number, value: IColor | null): void { - if (!this._color[bg]) { - this._color[bg] = {}; - } - this._color[bg]![fg] = value; - } - - public getColor(bg: number, fg: number): IColor | null | undefined { - return this._color[bg] ? this._color[bg]![fg] : undefined; - } -} diff --git a/node_modules/xterm/src/browser/ColorManager.ts b/node_modules/xterm/src/browser/ColorManager.ts deleted file mode 100644 index b4b57c6..0000000 --- a/node_modules/xterm/src/browser/ColorManager.ts +++ /dev/null @@ -1,258 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IColorManager, IColor, IColorSet, IColorContrastCache } from 'browser/Types'; -import { ITheme } from 'common/services/Services'; -import { channels, color, css } from 'browser/Color'; -import { ColorContrastCache } from 'browser/ColorContrastCache'; -import { ColorIndex } from 'common/Types'; - - -interface IRestoreColorSet { - foreground: IColor; - background: IColor; - cursor: IColor; - ansi: IColor[]; -} - - -const DEFAULT_FOREGROUND = css.toColor('#ffffff'); -const DEFAULT_BACKGROUND = css.toColor('#000000'); -const DEFAULT_CURSOR = css.toColor('#ffffff'); -const DEFAULT_CURSOR_ACCENT = css.toColor('#000000'); -const DEFAULT_SELECTION = { - css: 'rgba(255, 255, 255, 0.3)', - rgba: 0xFFFFFF4D -}; - -// An IIFE to generate DEFAULT_ANSI_COLORS. -export const DEFAULT_ANSI_COLORS = Object.freeze((() => { - const colors = [ - // dark: - css.toColor('#2e3436'), - css.toColor('#cc0000'), - css.toColor('#4e9a06'), - css.toColor('#c4a000'), - css.toColor('#3465a4'), - css.toColor('#75507b'), - css.toColor('#06989a'), - css.toColor('#d3d7cf'), - // bright: - css.toColor('#555753'), - css.toColor('#ef2929'), - css.toColor('#8ae234'), - css.toColor('#fce94f'), - css.toColor('#729fcf'), - css.toColor('#ad7fa8'), - css.toColor('#34e2e2'), - css.toColor('#eeeeec') - ]; - - // Fill in the remaining 240 ANSI colors. - // Generate colors (16-231) - const v = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff]; - for (let i = 0; i < 216; i++) { - const r = v[(i / 36) % 6 | 0]; - const g = v[(i / 6) % 6 | 0]; - const b = v[i % 6]; - colors.push({ - css: channels.toCss(r, g, b), - rgba: channels.toRgba(r, g, b) - }); - } - - // Generate greys (232-255) - for (let i = 0; i < 24; i++) { - const c = 8 + i * 10; - colors.push({ - css: channels.toCss(c, c, c), - rgba: channels.toRgba(c, c, c) - }); - } - - return colors; -})()); - -/** - * Manages the source of truth for a terminal's colors. - */ -export class ColorManager implements IColorManager { - public colors: IColorSet; - private _ctx: CanvasRenderingContext2D; - private _litmusColor: CanvasGradient; - private _contrastCache: IColorContrastCache; - private _restoreColors!: IRestoreColorSet; - - constructor(document: Document, public allowTransparency: boolean) { - const canvas = document.createElement('canvas'); - canvas.width = 1; - canvas.height = 1; - const ctx = canvas.getContext('2d'); - if (!ctx) { - throw new Error('Could not get rendering context'); - } - this._ctx = ctx; - this._ctx.globalCompositeOperation = 'copy'; - this._litmusColor = this._ctx.createLinearGradient(0, 0, 1, 1); - this._contrastCache = new ColorContrastCache(); - this.colors = { - foreground: DEFAULT_FOREGROUND, - background: DEFAULT_BACKGROUND, - cursor: DEFAULT_CURSOR, - cursorAccent: DEFAULT_CURSOR_ACCENT, - selectionTransparent: DEFAULT_SELECTION, - selectionOpaque: color.blend(DEFAULT_BACKGROUND, DEFAULT_SELECTION), - ansi: DEFAULT_ANSI_COLORS.slice(), - contrastCache: this._contrastCache - }; - this._updateRestoreColors(); - } - - public onOptionsChange(key: string): void { - if (key === 'minimumContrastRatio') { - this._contrastCache.clear(); - } - } - - /** - * Sets the terminal's theme. - * @param theme The theme to use. If a partial theme is provided then default - * colors will be used where colors are not defined. - */ - public setTheme(theme: ITheme = {}): void { - this.colors.foreground = this._parseColor(theme.foreground, DEFAULT_FOREGROUND); - this.colors.background = this._parseColor(theme.background, DEFAULT_BACKGROUND); - this.colors.cursor = this._parseColor(theme.cursor, DEFAULT_CURSOR, true); - this.colors.cursorAccent = this._parseColor(theme.cursorAccent, DEFAULT_CURSOR_ACCENT, true); - this.colors.selectionTransparent = this._parseColor(theme.selection, DEFAULT_SELECTION, true); - this.colors.selectionOpaque = color.blend(this.colors.background, this.colors.selectionTransparent); - /** - * If selection color is opaque, blend it with background with 0.3 opacity - * Issue #2737 - */ - if (color.isOpaque(this.colors.selectionTransparent)) { - const opacity = 0.3; - this.colors.selectionTransparent = color.opacity(this.colors.selectionTransparent, opacity); - } - this.colors.ansi[0] = this._parseColor(theme.black, DEFAULT_ANSI_COLORS[0]); - this.colors.ansi[1] = this._parseColor(theme.red, DEFAULT_ANSI_COLORS[1]); - this.colors.ansi[2] = this._parseColor(theme.green, DEFAULT_ANSI_COLORS[2]); - this.colors.ansi[3] = this._parseColor(theme.yellow, DEFAULT_ANSI_COLORS[3]); - this.colors.ansi[4] = this._parseColor(theme.blue, DEFAULT_ANSI_COLORS[4]); - this.colors.ansi[5] = this._parseColor(theme.magenta, DEFAULT_ANSI_COLORS[5]); - this.colors.ansi[6] = this._parseColor(theme.cyan, DEFAULT_ANSI_COLORS[6]); - this.colors.ansi[7] = this._parseColor(theme.white, DEFAULT_ANSI_COLORS[7]); - this.colors.ansi[8] = this._parseColor(theme.brightBlack, DEFAULT_ANSI_COLORS[8]); - this.colors.ansi[9] = this._parseColor(theme.brightRed, DEFAULT_ANSI_COLORS[9]); - this.colors.ansi[10] = this._parseColor(theme.brightGreen, DEFAULT_ANSI_COLORS[10]); - this.colors.ansi[11] = this._parseColor(theme.brightYellow, DEFAULT_ANSI_COLORS[11]); - this.colors.ansi[12] = this._parseColor(theme.brightBlue, DEFAULT_ANSI_COLORS[12]); - this.colors.ansi[13] = this._parseColor(theme.brightMagenta, DEFAULT_ANSI_COLORS[13]); - this.colors.ansi[14] = this._parseColor(theme.brightCyan, DEFAULT_ANSI_COLORS[14]); - this.colors.ansi[15] = this._parseColor(theme.brightWhite, DEFAULT_ANSI_COLORS[15]); - // Clear our the cache - this._contrastCache.clear(); - this._updateRestoreColors(); - } - - public restoreColor(slot?: ColorIndex): void { - // unset slot restores all ansi colors - if (slot === undefined) { - for (let i = 0; i < this._restoreColors.ansi.length; ++i) { - this.colors.ansi[i] = this._restoreColors.ansi[i]; - } - return; - } - switch (slot) { - case ColorIndex.FOREGROUND: - this.colors.foreground = this._restoreColors.foreground; - break; - case ColorIndex.BACKGROUND: - this.colors.background = this._restoreColors.background; - break; - case ColorIndex.CURSOR: - this.colors.cursor = this._restoreColors.cursor; - break; - default: - this.colors.ansi[slot] = this._restoreColors.ansi[slot]; - } - } - - private _updateRestoreColors(): void { - this._restoreColors = { - foreground: this.colors.foreground, - background: this.colors.background, - cursor: this.colors.cursor, - ansi: [...this.colors.ansi] - }; - } - - private _parseColor( - css: string | undefined, - fallback: IColor, - allowTransparency: boolean = this.allowTransparency - ): IColor { - if (css === undefined) { - return fallback; - } - - // If parsing the value results in failure, then it must be ignored, and the attribute must - // retain its previous value. - // -- https://html.spec.whatwg.org/multipage/canvas.html#fill-and-stroke-styles - this._ctx.fillStyle = this._litmusColor; - this._ctx.fillStyle = css; - if (typeof this._ctx.fillStyle !== 'string') { - console.warn(`Color: ${css} is invalid using fallback ${fallback.css}`); - return fallback; - } - - this._ctx.fillRect(0, 0, 1, 1); - const data = this._ctx.getImageData(0, 0, 1, 1).data; - - // Check if the printed color was transparent - if (data[3] !== 0xFF) { - if (!allowTransparency) { - // Ideally we'd just ignore the alpha channel, but... - // - // Browsers may not give back exactly the same RGB values we put in, because most/all - // convert the color to a pre-multiplied representation. getImageData converts that back to - // a un-premultipled representation, but the precision loss may make the RGB channels unuable - // on their own. - // - // E.g. In Chrome #12345610 turns into #10305010, and in the extreme case, 0xFFFFFF00 turns - // into 0x00000000. - // - // "Note: Due to the lossy nature of converting to and from premultiplied alpha color values, - // pixels that have just been set using putImageData() might be returned to an equivalent - // getImageData() as different values." - // -- https://html.spec.whatwg.org/multipage/canvas.html#pixel-manipulation - // - // So let's just use the fallback color in this case instead. - console.warn( - `Color: ${css} is using transparency, but allowTransparency is false. ` + - `Using fallback ${fallback.css}.` - ); - return fallback; - } - - // https://html.spec.whatwg.org/multipage/canvas.html#serialisation-of-a-color - // the color value has alpha less than 1.0, and the string is the color value in the CSS rgba() - const [r, g, b, a] = this._ctx.fillStyle.substring(5, this._ctx.fillStyle.length - 1).split(',').map(component => Number(component)); - const alpha = Math.round(a * 255); - const rgba: number = channels.toRgba(r, g, b, alpha); - return { - rgba, - css - }; - } - - return { - // https://html.spec.whatwg.org/multipage/canvas.html#serialisation-of-a-color - // if it has alpha equal to 1.0, then the string is a lowercase six-digit hex value, prefixed with a "#" character - css: this._ctx.fillStyle, - rgba: channels.toRgba(data[0], data[1], data[2], data[3]) - }; - } -} diff --git a/node_modules/xterm/src/browser/Dom.ts b/node_modules/xterm/src/browser/Dom.ts deleted file mode 100644 index c558a8b..0000000 --- a/node_modules/xterm/src/browser/Dom.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Copyright (c) 2020 The xterm.js authors. All rights reserved. - * @license MIT - */ - -export function removeElementFromParent(...elements: (HTMLElement | undefined)[]): void { - for (const e of elements) { - e?.parentElement?.removeChild(e); - } -} diff --git a/node_modules/xterm/src/browser/Lifecycle.ts b/node_modules/xterm/src/browser/Lifecycle.ts deleted file mode 100644 index 6e84179..0000000 --- a/node_modules/xterm/src/browser/Lifecycle.ts +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2018 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IDisposable } from 'common/Types'; - -/** - * Adds a disposable listener to a node in the DOM, returning the disposable. - * @param type The event type. - * @param handler The handler for the listener. - */ -export function addDisposableDomListener( - node: Element | Window | Document, - type: string, - handler: (e: any) => void, - options?: boolean | AddEventListenerOptions -): IDisposable { - node.addEventListener(type, handler, options); - let disposed = false; - return { - dispose: () => { - if (disposed) { - return; - } - disposed = true; - node.removeEventListener(type, handler, options); - } - }; -} diff --git a/node_modules/xterm/src/browser/Linkifier.ts b/node_modules/xterm/src/browser/Linkifier.ts deleted file mode 100644 index b17d66a..0000000 --- a/node_modules/xterm/src/browser/Linkifier.ts +++ /dev/null @@ -1,356 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { ILinkifierEvent, ILinkMatcher, LinkMatcherHandler, ILinkMatcherOptions, ILinkifier, IMouseZoneManager, IMouseZone, IRegisteredLinkMatcher } from 'browser/Types'; -import { IBufferStringIteratorResult } from 'common/buffer/Types'; -import { EventEmitter, IEvent } from 'common/EventEmitter'; -import { ILogService, IBufferService, IOptionsService, IUnicodeService } from 'common/services/Services'; - -/** - * Limit of the unwrapping line expansion (overscan) at the top and bottom - * of the actual viewport in ASCII characters. - * A limit of 2000 should match most sane urls. - */ -const OVERSCAN_CHAR_LIMIT = 2000; - -/** - * The Linkifier applies links to rows shortly after they have been refreshed. - */ -export class Linkifier implements ILinkifier { - /** - * The time to wait after a row is changed before it is linkified. This prevents - * the costly operation of searching every row multiple times, potentially a - * huge amount of times. - */ - protected static _timeBeforeLatency = 200; - - protected _linkMatchers: IRegisteredLinkMatcher[] = []; - - private _mouseZoneManager: IMouseZoneManager | undefined; - private _element: HTMLElement | undefined; - - private _rowsTimeoutId: number | undefined; - private _nextLinkMatcherId = 0; - private _rowsToLinkify: { start: number | undefined, end: number | undefined }; - - private _onShowLinkUnderline = new EventEmitter<ILinkifierEvent>(); - public get onShowLinkUnderline(): IEvent<ILinkifierEvent> { return this._onShowLinkUnderline.event; } - private _onHideLinkUnderline = new EventEmitter<ILinkifierEvent>(); - public get onHideLinkUnderline(): IEvent<ILinkifierEvent> { return this._onHideLinkUnderline.event; } - private _onLinkTooltip = new EventEmitter<ILinkifierEvent>(); - public get onLinkTooltip(): IEvent<ILinkifierEvent> { return this._onLinkTooltip.event; } - - constructor( - @IBufferService protected readonly _bufferService: IBufferService, - @ILogService private readonly _logService: ILogService, - @IUnicodeService private readonly _unicodeService: IUnicodeService - ) { - this._rowsToLinkify = { - start: undefined, - end: undefined - }; - } - - /** - * Attaches the linkifier to the DOM, enabling linkification. - * @param mouseZoneManager The mouse zone manager to register link zones with. - */ - public attachToDom(element: HTMLElement, mouseZoneManager: IMouseZoneManager): void { - this._element = element; - this._mouseZoneManager = mouseZoneManager; - } - - /** - * Queue linkification on a set of rows. - * @param start The row to linkify from (inclusive). - * @param end The row to linkify to (inclusive). - */ - public linkifyRows(start: number, end: number): void { - // Don't attempt linkify if not yet attached to DOM - if (!this._mouseZoneManager) { - return; - } - - // Increase range to linkify - if (this._rowsToLinkify.start === undefined || this._rowsToLinkify.end === undefined) { - this._rowsToLinkify.start = start; - this._rowsToLinkify.end = end; - } else { - this._rowsToLinkify.start = Math.min(this._rowsToLinkify.start, start); - this._rowsToLinkify.end = Math.max(this._rowsToLinkify.end, end); - } - - // Clear out any existing links on this row range - this._mouseZoneManager.clearAll(start, end); - - // Restart timer - if (this._rowsTimeoutId) { - clearTimeout(this._rowsTimeoutId); - } - - // Cannot use window.setTimeout since tests need to run in node - this._rowsTimeoutId = setTimeout(() => this._linkifyRows(), Linkifier._timeBeforeLatency) as any as number; - } - - /** - * Linkifies the rows requested. - */ - private _linkifyRows(): void { - this._rowsTimeoutId = undefined; - const buffer = this._bufferService.buffer; - - if (this._rowsToLinkify.start === undefined || this._rowsToLinkify.end === undefined) { - this._logService.debug('_rowToLinkify was unset before _linkifyRows was called'); - return; - } - - // Ensure the start row exists - const absoluteRowIndexStart = buffer.ydisp + this._rowsToLinkify.start; - if (absoluteRowIndexStart >= buffer.lines.length) { - return; - } - - // Invalidate bad end row values (if a resize happened) - const absoluteRowIndexEnd = buffer.ydisp + Math.min(this._rowsToLinkify.end, this._bufferService.rows) + 1; - - // Iterate over the range of unwrapped content strings within start..end - // (excluding). - // _doLinkifyRow gets full unwrapped lines with the start row as buffer offset - // for every matcher. - // The unwrapping is needed to also match content that got wrapped across - // several buffer lines. To avoid a worst case scenario where the whole buffer - // contains just a single unwrapped string we limit this line expansion beyond - // the viewport to +OVERSCAN_CHAR_LIMIT chars (overscan) at top and bottom. - // This comes with the tradeoff that matches longer than OVERSCAN_CHAR_LIMIT - // chars will not match anymore at the viewport borders. - const overscanLineLimit = Math.ceil(OVERSCAN_CHAR_LIMIT / this._bufferService.cols); - const iterator = this._bufferService.buffer.iterator( - false, absoluteRowIndexStart, absoluteRowIndexEnd, overscanLineLimit, overscanLineLimit); - while (iterator.hasNext()) { - const lineData: IBufferStringIteratorResult = iterator.next(); - for (let i = 0; i < this._linkMatchers.length; i++) { - this._doLinkifyRow(lineData.range.first, lineData.content, this._linkMatchers[i]); - } - } - - this._rowsToLinkify.start = undefined; - this._rowsToLinkify.end = undefined; - } - - /** - * Registers a link matcher, allowing custom link patterns to be matched and - * handled. - * @param regex The regular expression to search for. Specifically, this - * searches the textContent of the rows. You will want to use \s to match a - * space ' ' character for example. - * @param handler The callback when the link is called. - * @param options Options for the link matcher. - * @return The ID of the new matcher, this can be used to deregister. - */ - public registerLinkMatcher(regex: RegExp, handler: LinkMatcherHandler, options: ILinkMatcherOptions = {}): number { - if (!handler) { - throw new Error('handler must be defined'); - } - const matcher: IRegisteredLinkMatcher = { - id: this._nextLinkMatcherId++, - regex, - handler, - matchIndex: options.matchIndex, - validationCallback: options.validationCallback, - hoverTooltipCallback: options.tooltipCallback, - hoverLeaveCallback: options.leaveCallback, - willLinkActivate: options.willLinkActivate, - priority: options.priority || 0 - }; - this._addLinkMatcherToList(matcher); - return matcher.id; - } - - /** - * Inserts a link matcher to the list in the correct position based on the - * priority of each link matcher. New link matchers of equal priority are - * considered after older link matchers. - * @param matcher The link matcher to be added. - */ - private _addLinkMatcherToList(matcher: IRegisteredLinkMatcher): void { - if (this._linkMatchers.length === 0) { - this._linkMatchers.push(matcher); - return; - } - - for (let i = this._linkMatchers.length - 1; i >= 0; i--) { - if (matcher.priority <= this._linkMatchers[i].priority) { - this._linkMatchers.splice(i + 1, 0, matcher); - return; - } - } - - this._linkMatchers.splice(0, 0, matcher); - } - - /** - * Deregisters a link matcher if it has been registered. - * @param matcherId The link matcher's ID (returned after register) - * @return Whether a link matcher was found and deregistered. - */ - public deregisterLinkMatcher(matcherId: number): boolean { - for (let i = 0; i < this._linkMatchers.length; i++) { - if (this._linkMatchers[i].id === matcherId) { - this._linkMatchers.splice(i, 1); - return true; - } - } - return false; - } - - /** - * Linkifies a row given a specific handler. - * @param rowIndex The row index to linkify (absolute index). - * @param text string content of the unwrapped row. - * @param matcher The link matcher for this line. - */ - private _doLinkifyRow(rowIndex: number, text: string, matcher: ILinkMatcher): void { - // clone regex to do a global search on text - const rex = new RegExp(matcher.regex.source, (matcher.regex.flags || '') + 'g'); - let match; - let stringIndex = -1; - while ((match = rex.exec(text)) !== null) { - const uri = match[typeof matcher.matchIndex !== 'number' ? 0 : matcher.matchIndex]; - if (!uri) { - // something matched but does not comply with the given matchIndex - // since this is most likely a bug the regex itself we simply do nothing here - this._logService.debug('match found without corresponding matchIndex', match, matcher); - break; - } - - // Get index, match.index is for the outer match which includes negated chars - // therefore we cannot use match.index directly, instead we search the position - // of the match group in text again - // also correct regex and string search offsets for the next loop run - stringIndex = text.indexOf(uri, stringIndex + 1); - rex.lastIndex = stringIndex + uri.length; - if (stringIndex < 0) { - // invalid stringIndex (should not have happened) - break; - } - - // get the buffer index as [absolute row, col] for the match - const bufferIndex = this._bufferService.buffer.stringIndexToBufferIndex(rowIndex, stringIndex); - if (bufferIndex[0] < 0) { - // invalid bufferIndex (should not have happened) - break; - } - - const line = this._bufferService.buffer.lines.get(bufferIndex[0]); - if (!line) { - break; - } - - const attr = line.getFg(bufferIndex[1]); - const fg = attr ? (attr >> 9) & 0x1ff : undefined; - - if (matcher.validationCallback) { - matcher.validationCallback(uri, isValid => { - // Discard link if the line has already changed - if (this._rowsTimeoutId) { - return; - } - if (isValid) { - this._addLink(bufferIndex[1], bufferIndex[0] - this._bufferService.buffer.ydisp, uri, matcher, fg); - } - }); - } else { - this._addLink(bufferIndex[1], bufferIndex[0] - this._bufferService.buffer.ydisp, uri, matcher, fg); - } - } - } - - /** - * Registers a link to the mouse zone manager. - * @param x The column the link starts. - * @param y The row the link is on. - * @param uri The URI of the link. - * @param matcher The link matcher for the link. - * @param fg The link color for hover event. - */ - private _addLink(x: number, y: number, uri: string, matcher: ILinkMatcher, fg: number | undefined): void { - if (!this._mouseZoneManager || !this._element) { - return; - } - // FIXME: get cell length from buffer to avoid mismatch after Unicode version change - const width = this._unicodeService.getStringCellWidth(uri); - const x1 = x % this._bufferService.cols; - const y1 = y + Math.floor(x / this._bufferService.cols); - let x2 = (x1 + width) % this._bufferService.cols; - let y2 = y1 + Math.floor((x1 + width) / this._bufferService.cols); - if (x2 === 0) { - x2 = this._bufferService.cols; - y2--; - } - - this._mouseZoneManager.add(new MouseZone( - x1 + 1, - y1 + 1, - x2 + 1, - y2 + 1, - e => { - if (matcher.handler) { - return matcher.handler(e, uri); - } - const newWindow = window.open(); - if (newWindow) { - newWindow.opener = null; - newWindow.location.href = uri; - } else { - console.warn('Opening link blocked as opener could not be cleared'); - } - }, - () => { - this._onShowLinkUnderline.fire(this._createLinkHoverEvent(x1, y1, x2, y2, fg)); - this._element!.classList.add('xterm-cursor-pointer'); - }, - e => { - this._onLinkTooltip.fire(this._createLinkHoverEvent(x1, y1, x2, y2, fg)); - if (matcher.hoverTooltipCallback) { - // Note that IViewportRange use 1-based coordinates to align with escape sequences such - // as CUP which use 1,1 as the default for row/col - matcher.hoverTooltipCallback(e, uri, { start: { x: x1, y: y1 }, end: { x: x2, y: y2 } }); - } - }, - () => { - this._onHideLinkUnderline.fire(this._createLinkHoverEvent(x1, y1, x2, y2, fg)); - this._element!.classList.remove('xterm-cursor-pointer'); - if (matcher.hoverLeaveCallback) { - matcher.hoverLeaveCallback(); - } - }, - e => { - if (matcher.willLinkActivate) { - return matcher.willLinkActivate(e, uri); - } - return true; - } - )); - } - - private _createLinkHoverEvent(x1: number, y1: number, x2: number, y2: number, fg: number | undefined): ILinkifierEvent { - return { x1, y1, x2, y2, cols: this._bufferService.cols, fg }; - } -} - -export class MouseZone implements IMouseZone { - constructor( - public x1: number, - public y1: number, - public x2: number, - public y2: number, - public clickCallback: (e: MouseEvent) => any, - public hoverCallback: (e: MouseEvent) => any, - public tooltipCallback: (e: MouseEvent) => any, - public leaveCallback: () => void, - public willLinkActivate: (e: MouseEvent) => boolean - ) { - } -} diff --git a/node_modules/xterm/src/browser/Linkifier2.ts b/node_modules/xterm/src/browser/Linkifier2.ts deleted file mode 100644 index 8954293..0000000 --- a/node_modules/xterm/src/browser/Linkifier2.ts +++ /dev/null @@ -1,392 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { ILinkifier2, ILinkProvider, IBufferCellPosition, ILink, ILinkifierEvent, ILinkDecorations, ILinkWithState } from 'browser/Types'; -import { IDisposable } from 'common/Types'; -import { IMouseService, IRenderService } from './services/Services'; -import { IBufferService } from 'common/services/Services'; -import { EventEmitter, IEvent } from 'common/EventEmitter'; -import { Disposable, getDisposeArrayDisposable, disposeArray } from 'common/Lifecycle'; -import { addDisposableDomListener } from 'browser/Lifecycle'; - -export class Linkifier2 extends Disposable implements ILinkifier2 { - private _element: HTMLElement | undefined; - private _mouseService: IMouseService | undefined; - private _renderService: IRenderService | undefined; - private _linkProviders: ILinkProvider[] = []; - public get currentLink(): ILinkWithState | undefined { return this._currentLink; } - protected _currentLink: ILinkWithState | undefined; - private _lastMouseEvent: MouseEvent | undefined; - private _linkCacheDisposables: IDisposable[] = []; - private _lastBufferCell: IBufferCellPosition | undefined; - private _isMouseOut: boolean = true; - private _activeProviderReplies: Map<Number, ILinkWithState[] | undefined> | undefined; - private _activeLine: number = -1; - - private _onShowLinkUnderline = this.register(new EventEmitter<ILinkifierEvent>()); - public get onShowLinkUnderline(): IEvent<ILinkifierEvent> { return this._onShowLinkUnderline.event; } - private _onHideLinkUnderline = this.register(new EventEmitter<ILinkifierEvent>()); - public get onHideLinkUnderline(): IEvent<ILinkifierEvent> { return this._onHideLinkUnderline.event; } - - constructor( - @IBufferService private readonly _bufferService: IBufferService - ) { - super(); - this.register(getDisposeArrayDisposable(this._linkCacheDisposables)); - } - - public registerLinkProvider(linkProvider: ILinkProvider): IDisposable { - this._linkProviders.push(linkProvider); - return { - dispose: () => { - // Remove the link provider from the list - const providerIndex = this._linkProviders.indexOf(linkProvider); - - if (providerIndex !== -1) { - this._linkProviders.splice(providerIndex, 1); - } - } - }; - } - - public attachToDom(element: HTMLElement, mouseService: IMouseService, renderService: IRenderService): void { - this._element = element; - this._mouseService = mouseService; - this._renderService = renderService; - - this.register(addDisposableDomListener(this._element, 'mouseleave', () => { - this._isMouseOut = true; - this._clearCurrentLink(); - })); - this.register(addDisposableDomListener(this._element, 'mousemove', this._onMouseMove.bind(this))); - this.register(addDisposableDomListener(this._element, 'click', this._onClick.bind(this))); - } - - private _onMouseMove(event: MouseEvent): void { - this._lastMouseEvent = event; - - if (!this._element || !this._mouseService) { - return; - } - - const position = this._positionFromMouseEvent(event, this._element, this._mouseService); - if (!position) { - return; - } - this._isMouseOut = false; - - // Ignore the event if it's an embedder created hover widget - const composedPath = event.composedPath() as HTMLElement[]; - for (let i = 0; i < composedPath.length; i++) { - const target = composedPath[i]; - // Hit Terminal.element, break and continue - if (target.classList.contains('xterm')) { - break; - } - // It's a hover, don't respect hover event - if (target.classList.contains('xterm-hover')) { - return; - } - } - - if (!this._lastBufferCell || (position.x !== this._lastBufferCell.x || position.y !== this._lastBufferCell.y)) { - this._onHover(position); - this._lastBufferCell = position; - } - } - - private _onHover(position: IBufferCellPosition): void { - // TODO: This currently does not cache link provider results across wrapped lines, activeLine should be something like `activeRange: {startY, endY}` - // Check if we need to clear the link - if (this._activeLine !== position.y) { - this._clearCurrentLink(); - this._askForLink(position, false); - return; - } - - // Check the if the link is in the mouse position - const isCurrentLinkInPosition = this._currentLink && this._linkAtPosition(this._currentLink.link, position); - if (!isCurrentLinkInPosition) { - this._clearCurrentLink(); - this._askForLink(position, true); - } - } - - private _askForLink(position: IBufferCellPosition, useLineCache: boolean): void { - if (!this._activeProviderReplies || !useLineCache) { - this._activeProviderReplies?.forEach(reply => { - reply?.forEach(linkWithState => { - if (linkWithState.link.dispose) { - linkWithState.link.dispose(); - } - }); - }); - this._activeProviderReplies = new Map(); - this._activeLine = position.y; - } - let linkProvided = false; - - // There is no link cached, so ask for one - this._linkProviders.forEach((linkProvider, i) => { - if (useLineCache) { - const existingReply = this._activeProviderReplies?.get(i); - // If there isn't a reply, the provider hasn't responded yet. - - // TODO: If there isn't a reply yet it means that the provider is still resolving. Ensuring - // provideLinks isn't triggered again saves ILink.hover firing twice though. This probably - // needs promises to get fixed - if (existingReply) { - linkProvided = this._checkLinkProviderResult(i, position, linkProvided); - } - } else { - linkProvider.provideLinks(position.y, (links: ILink[] | undefined) => { - if (this._isMouseOut) { - return; - } - const linksWithState: ILinkWithState[] | undefined = links?.map(link => ({ link })); - this._activeProviderReplies?.set(i, linksWithState); - linkProvided = this._checkLinkProviderResult(i, position, linkProvided); - - // If all providers have responded, remove lower priority links that intersect ranges of - // higher priority links - if (this._activeProviderReplies?.size === this._linkProviders.length) { - this._removeIntersectingLinks(position.y, this._activeProviderReplies); - } - }); - } - }); - } - - private _removeIntersectingLinks(y: number, replies: Map<Number, ILinkWithState[] | undefined>): void { - const occupiedCells = new Set<number>(); - for (let i = 0; i < replies.size; i++) { - const providerReply = replies.get(i); - if (!providerReply) { - continue; - } - for (let i = 0; i < providerReply.length; i++) { - const linkWithState = providerReply[i]; - const startX = linkWithState.link.range.start.y < y ? 0 : linkWithState.link.range.start.x; - const endX = linkWithState.link.range.end.y > y ? this._bufferService.cols : linkWithState.link.range.end.x; - for (let x = startX; x <= endX; x++) { - if (occupiedCells.has(x)) { - providerReply.splice(i--, 1); - break; - } - occupiedCells.add(x); - } - } - } - } - - private _checkLinkProviderResult(index: number, position: IBufferCellPosition, linkProvided: boolean): boolean { - if (!this._activeProviderReplies) { - return linkProvided; - } - - const links = this._activeProviderReplies.get(index); - - // Check if every provider before this one has come back undefined - let hasLinkBefore = false; - for (let j = 0; j < index; j++) { - if (!this._activeProviderReplies.has(j) || this._activeProviderReplies.get(j)) { - hasLinkBefore = true; - } - } - - // If all providers with higher priority came back undefined, then this provider's link for - // the position should be used - if (!hasLinkBefore && links) { - const linkAtPosition = links.find(link => this._linkAtPosition(link.link, position)); - if (linkAtPosition) { - linkProvided = true; - this._handleNewLink(linkAtPosition); - } - } - - // Check if all the providers have responded - if (this._activeProviderReplies.size === this._linkProviders.length && !linkProvided) { - // Respect the order of the link providers - for (let j = 0; j < this._activeProviderReplies.size; j++) { - const currentLink = this._activeProviderReplies.get(j)?.find(link => this._linkAtPosition(link.link, position)); - if (currentLink) { - linkProvided = true; - this._handleNewLink(currentLink); - break; - } - } - } - - return linkProvided; - } - - private _onClick(event: MouseEvent): void { - if (!this._element || !this._mouseService || !this._currentLink) { - return; - } - - const position = this._positionFromMouseEvent(event, this._element, this._mouseService); - - if (!position) { - return; - } - - if (this._linkAtPosition(this._currentLink.link, position)) { - this._currentLink.link.activate(event, this._currentLink.link.text); - } - } - - private _clearCurrentLink(startRow?: number, endRow?: number): void { - if (!this._element || !this._currentLink || !this._lastMouseEvent) { - return; - } - - // If we have a start and end row, check that the link is within it - if (!startRow || !endRow || (this._currentLink.link.range.start.y >= startRow && this._currentLink.link.range.end.y <= endRow)) { - this._linkLeave(this._element, this._currentLink.link, this._lastMouseEvent); - this._currentLink = undefined; - disposeArray(this._linkCacheDisposables); - } - } - - private _handleNewLink(linkWithState: ILinkWithState): void { - if (!this._element || !this._lastMouseEvent || !this._mouseService) { - return; - } - - const position = this._positionFromMouseEvent(this._lastMouseEvent, this._element, this._mouseService); - - if (!position) { - return; - } - - // Trigger hover if the we have a link at the position - if (this._linkAtPosition(linkWithState.link, position)) { - this._currentLink = linkWithState; - this._currentLink.state = { - decorations: { - underline: linkWithState.link.decorations === undefined ? true : linkWithState.link.decorations.underline, - pointerCursor: linkWithState.link.decorations === undefined ? true : linkWithState.link.decorations.pointerCursor - }, - isHovered: true - }; - this._linkHover(this._element, linkWithState.link, this._lastMouseEvent); - - // Add listener for tracking decorations changes - linkWithState.link.decorations = {} as ILinkDecorations; - Object.defineProperties(linkWithState.link.decorations, { - pointerCursor: { - get: () => this._currentLink?.state?.decorations.pointerCursor, - set: v => { - if (this._currentLink?.state && this._currentLink.state.decorations.pointerCursor !== v) { - this._currentLink.state.decorations.pointerCursor = v; - if (this._currentLink.state.isHovered) { - this._element?.classList.toggle('xterm-cursor-pointer', v); - } - } - } - }, - underline: { - get: () => this._currentLink?.state?.decorations.underline, - set: v => { - if (this._currentLink?.state && this._currentLink?.state?.decorations.underline !== v) { - this._currentLink.state.decorations.underline = v; - if (this._currentLink.state.isHovered) { - this._fireUnderlineEvent(linkWithState.link, v); - } - } - } - } - }); - - // Add listener for rerendering - if (this._renderService) { - this._linkCacheDisposables.push(this._renderService.onRenderedBufferChange(e => { - // When start is 0 a scroll most likely occurred, make sure links above the fold also get - // cleared. - const start = e.start === 0 ? 0 : e.start + 1 + this._bufferService.buffer.ydisp; - this._clearCurrentLink(start, e.end + 1 + this._bufferService.buffer.ydisp); - })); - } - } - } - - protected _linkHover(element: HTMLElement, link: ILink, event: MouseEvent): void { - if (this._currentLink?.state) { - this._currentLink.state.isHovered = true; - if (this._currentLink.state.decorations.underline) { - this._fireUnderlineEvent(link, true); - } - if (this._currentLink.state.decorations.pointerCursor) { - element.classList.add('xterm-cursor-pointer'); - } - } - - if (link.hover) { - link.hover(event, link.text); - } - } - - private _fireUnderlineEvent(link: ILink, showEvent: boolean): void { - const range = link.range; - const scrollOffset = this._bufferService.buffer.ydisp; - const event = this._createLinkUnderlineEvent(range.start.x - 1, range.start.y - scrollOffset - 1, range.end.x, range.end.y - scrollOffset - 1, undefined); - const emitter = showEvent ? this._onShowLinkUnderline : this._onHideLinkUnderline; - emitter.fire(event); - } - - protected _linkLeave(element: HTMLElement, link: ILink, event: MouseEvent): void { - if (this._currentLink?.state) { - this._currentLink.state.isHovered = false; - if (this._currentLink.state.decorations.underline) { - this._fireUnderlineEvent(link, false); - } - if (this._currentLink.state.decorations.pointerCursor) { - element.classList.remove('xterm-cursor-pointer'); - } - } - - if (link.leave) { - link.leave(event, link.text); - } - } - - /** - * Check if the buffer position is within the link - * @param link - * @param position - */ - private _linkAtPosition(link: ILink, position: IBufferCellPosition): boolean { - const sameLine = link.range.start.y === link.range.end.y; - const wrappedFromLeft = link.range.start.y < position.y; - const wrappedToRight = link.range.end.y > position.y; - - // If the start and end have the same y, then the position must be between start and end x - // If not, then handle each case seperately, depending on which way it wraps - return ((sameLine && link.range.start.x <= position.x && link.range.end.x >= position.x) || - (wrappedFromLeft && link.range.end.x >= position.x) || - (wrappedToRight && link.range.start.x <= position.x) || - (wrappedFromLeft && wrappedToRight)) && - link.range.start.y <= position.y && - link.range.end.y >= position.y; - } - - /** - * Get the buffer position from a mouse event - * @param event - */ - private _positionFromMouseEvent(event: MouseEvent, element: HTMLElement, mouseService: IMouseService): IBufferCellPosition | undefined { - const coords = mouseService.getCoords(event, element, this._bufferService.cols, this._bufferService.rows); - if (!coords) { - return; - } - - return { x: coords[0], y: coords[1] + this._bufferService.buffer.ydisp }; - } - - private _createLinkUnderlineEvent(x1: number, y1: number, x2: number, y2: number, fg: number | undefined): ILinkifierEvent { - return { x1, y1, x2, y2, cols: this._bufferService.cols, fg }; - } -} diff --git a/node_modules/xterm/src/browser/LocalizableStrings.ts b/node_modules/xterm/src/browser/LocalizableStrings.ts deleted file mode 100644 index c0a904c..0000000 --- a/node_modules/xterm/src/browser/LocalizableStrings.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Copyright (c) 2018 The xterm.js authors. All rights reserved. - * @license MIT - */ - -// eslint-disable-next-line prefer-const -export let promptLabel = 'Terminal input'; - -// eslint-disable-next-line prefer-const -export let tooMuchOutput = 'Too much output to announce, navigate to rows manually to read'; diff --git a/node_modules/xterm/src/browser/MouseZoneManager.ts b/node_modules/xterm/src/browser/MouseZoneManager.ts deleted file mode 100644 index 71ffe7c..0000000 --- a/node_modules/xterm/src/browser/MouseZoneManager.ts +++ /dev/null @@ -1,236 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { Disposable } from 'common/Lifecycle'; -import { addDisposableDomListener } from 'browser/Lifecycle'; -import { IMouseService, ISelectionService } from 'browser/services/Services'; -import { IMouseZoneManager, IMouseZone } from 'browser/Types'; -import { IBufferService, IOptionsService } from 'common/services/Services'; - -/** - * The MouseZoneManager allows components to register zones within the terminal - * that trigger hover and click callbacks. - * - * This class was intentionally made not so robust initially as the only case it - * needed to support was single-line links which never overlap. Improvements can - * be made in the future. - */ -export class MouseZoneManager extends Disposable implements IMouseZoneManager { - private _zones: IMouseZone[] = []; - - private _areZonesActive: boolean = false; - private _mouseMoveListener: (e: MouseEvent) => any; - private _mouseLeaveListener: (e: MouseEvent) => any; - private _clickListener: (e: MouseEvent) => any; - - private _tooltipTimeout: number | undefined; - private _currentZone: IMouseZone | undefined; - private _lastHoverCoords: [number | undefined, number | undefined] = [undefined, undefined]; - private _initialSelectionLength: number = 0; - - constructor( - private readonly _element: HTMLElement, - private readonly _screenElement: HTMLElement, - @IBufferService private readonly _bufferService: IBufferService, - @IMouseService private readonly _mouseService: IMouseService, - @ISelectionService private readonly _selectionService: ISelectionService, - @IOptionsService private readonly _optionsService: IOptionsService - ) { - super(); - - this.register(addDisposableDomListener(this._element, 'mousedown', e => this._onMouseDown(e))); - - // These events are expensive, only listen to it when mouse zones are active - this._mouseMoveListener = e => this._onMouseMove(e); - this._mouseLeaveListener = e => this._onMouseLeave(e); - this._clickListener = e => this._onClick(e); - } - - public dispose(): void { - super.dispose(); - this._deactivate(); - } - - public add(zone: IMouseZone): void { - this._zones.push(zone); - if (this._zones.length === 1) { - this._activate(); - } - } - - public clearAll(start?: number, end?: number): void { - // Exit if there's nothing to clear - if (this._zones.length === 0) { - return; - } - - // Clear all if start/end weren't set - if (!start || !end) { - start = 0; - end = this._bufferService.rows - 1; - } - - // Iterate through zones and clear them out if they're within the range - for (let i = 0; i < this._zones.length; i++) { - const zone = this._zones[i]; - if ((zone.y1 > start && zone.y1 <= end + 1) || - (zone.y2 > start && zone.y2 <= end + 1) || - (zone.y1 < start && zone.y2 > end + 1)) { - if (this._currentZone && this._currentZone === zone) { - this._currentZone.leaveCallback(); - this._currentZone = undefined; - } - this._zones.splice(i--, 1); - } - } - - // Deactivate the mouse zone manager if all the zones have been removed - if (this._zones.length === 0) { - this._deactivate(); - } - } - - private _activate(): void { - if (!this._areZonesActive) { - this._areZonesActive = true; - this._element.addEventListener('mousemove', this._mouseMoveListener); - this._element.addEventListener('mouseleave', this._mouseLeaveListener); - this._element.addEventListener('click', this._clickListener); - } - } - - private _deactivate(): void { - if (this._areZonesActive) { - this._areZonesActive = false; - this._element.removeEventListener('mousemove', this._mouseMoveListener); - this._element.removeEventListener('mouseleave', this._mouseLeaveListener); - this._element.removeEventListener('click', this._clickListener); - } - } - - private _onMouseMove(e: MouseEvent): void { - // TODO: Ideally this would only clear the hover state when the mouse moves - // outside of the mouse zone - if (this._lastHoverCoords[0] !== e.pageX || this._lastHoverCoords[1] !== e.pageY) { - this._onHover(e); - // Record the current coordinates - this._lastHoverCoords = [e.pageX, e.pageY]; - } - } - - private _onHover(e: MouseEvent): void { - const zone = this._findZoneEventAt(e); - - // Do nothing if the zone is the same - if (zone === this._currentZone) { - return; - } - - // Fire the hover end callback and cancel any existing timer if a new zone - // is being hovered - if (this._currentZone) { - this._currentZone.leaveCallback(); - this._currentZone = undefined; - if (this._tooltipTimeout) { - clearTimeout(this._tooltipTimeout); - } - } - - // Exit if there is not zone - if (!zone) { - return; - } - this._currentZone = zone; - - // Trigger the hover callback - if (zone.hoverCallback) { - zone.hoverCallback(e); - } - - // Restart the tooltip timeout - this._tooltipTimeout = window.setTimeout(() => this._onTooltip(e), this._optionsService.rawOptions.linkTooltipHoverDuration); - } - - private _onTooltip(e: MouseEvent): void { - this._tooltipTimeout = undefined; - const zone = this._findZoneEventAt(e); - zone?.tooltipCallback(e); - } - - private _onMouseDown(e: MouseEvent): void { - // Store current terminal selection length, to check if we're performing - // a selection operation - this._initialSelectionLength = this._getSelectionLength(); - - // Ignore the event if there are no zones active - if (!this._areZonesActive) { - return; - } - - // Find the active zone, prevent event propagation if found to prevent other - // components from handling the mouse event. - const zone = this._findZoneEventAt(e); - if (zone?.willLinkActivate(e)) { - e.preventDefault(); - e.stopImmediatePropagation(); - } - } - - private _onMouseLeave(e: MouseEvent): void { - // Fire the hover end callback and cancel any existing timer if the mouse - // leaves the terminal element - if (this._currentZone) { - this._currentZone.leaveCallback(); - this._currentZone = undefined; - if (this._tooltipTimeout) { - clearTimeout(this._tooltipTimeout); - } - } - } - - private _onClick(e: MouseEvent): void { - // Find the active zone and click it if found and no selection was - // being performed - const zone = this._findZoneEventAt(e); - const currentSelectionLength = this._getSelectionLength(); - - if (zone && currentSelectionLength === this._initialSelectionLength) { - zone.clickCallback(e); - e.preventDefault(); - e.stopImmediatePropagation(); - } - } - - private _getSelectionLength(): number { - const selectionText = this._selectionService.selectionText; - return selectionText ? selectionText.length : 0; - } - - private _findZoneEventAt(e: MouseEvent): IMouseZone | undefined { - const coords = this._mouseService.getCoords(e, this._screenElement, this._bufferService.cols, this._bufferService.rows); - if (!coords) { - return undefined; - } - const x = coords[0]; - const y = coords[1]; - for (let i = 0; i < this._zones.length; i++) { - const zone = this._zones[i]; - if (zone.y1 === zone.y2) { - // Single line link - if (y === zone.y1 && x >= zone.x1 && x < zone.x2) { - return zone; - } - } else { - // Multi-line link - if ((y === zone.y1 && x >= zone.x1) || - (y === zone.y2 && x < zone.x2) || - (y > zone.y1 && y < zone.y2)) { - return zone; - } - } - } - return undefined; - } -} diff --git a/node_modules/xterm/src/browser/RenderDebouncer.ts b/node_modules/xterm/src/browser/RenderDebouncer.ts deleted file mode 100644 index 0252107..0000000 --- a/node_modules/xterm/src/browser/RenderDebouncer.ts +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (c) 2018 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IRenderDebouncer } from 'browser/Types'; - -/** - * Debounces calls to render terminal rows using animation frames. - */ -export class RenderDebouncer implements IRenderDebouncer { - private _rowStart: number | undefined; - private _rowEnd: number | undefined; - private _rowCount: number | undefined; - private _animationFrame: number | undefined; - - constructor( - private _renderCallback: (start: number, end: number) => void - ) { - } - - public dispose(): void { - if (this._animationFrame) { - window.cancelAnimationFrame(this._animationFrame); - this._animationFrame = undefined; - } - } - - public refresh(rowStart: number | undefined, rowEnd: number | undefined, rowCount: number): void { - this._rowCount = rowCount; - // Get the min/max row start/end for the arg values - rowStart = rowStart !== undefined ? rowStart : 0; - rowEnd = rowEnd !== undefined ? rowEnd : this._rowCount - 1; - // Set the properties to the updated values - this._rowStart = this._rowStart !== undefined ? Math.min(this._rowStart, rowStart) : rowStart; - this._rowEnd = this._rowEnd !== undefined ? Math.max(this._rowEnd, rowEnd) : rowEnd; - - if (this._animationFrame) { - return; - } - - this._animationFrame = window.requestAnimationFrame(() => this._innerRefresh()); - } - - private _innerRefresh(): void { - // Make sure values are set - if (this._rowStart === undefined || this._rowEnd === undefined || this._rowCount === undefined) { - return; - } - - // Clamp values - const start = Math.max(this._rowStart, 0); - const end = Math.min(this._rowEnd, this._rowCount - 1); - - // Reset debouncer (this happens before render callback as the render could trigger it again) - this._rowStart = undefined; - this._rowEnd = undefined; - this._animationFrame = undefined; - - // Run render callback - this._renderCallback(start, end); - } -} diff --git a/node_modules/xterm/src/browser/ScreenDprMonitor.ts b/node_modules/xterm/src/browser/ScreenDprMonitor.ts deleted file mode 100644 index 27ae231..0000000 --- a/node_modules/xterm/src/browser/ScreenDprMonitor.ts +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { Disposable } from 'common/Lifecycle'; - -export type ScreenDprListener = (newDevicePixelRatio?: number, oldDevicePixelRatio?: number) => void; - -/** - * The screen device pixel ratio monitor allows listening for when the - * window.devicePixelRatio value changes. This is done not with polling but with - * the use of window.matchMedia to watch media queries. When the event fires, - * the listener will be reattached using a different media query to ensure that - * any further changes will register. - * - * The listener should fire on both window zoom changes and switching to a - * monitor with a different DPI. - */ -export class ScreenDprMonitor extends Disposable { - private _currentDevicePixelRatio: number = window.devicePixelRatio; - private _outerListener: ((this: MediaQueryList, ev: MediaQueryListEvent) => any) | undefined; - private _listener: ScreenDprListener | undefined; - private _resolutionMediaMatchList: MediaQueryList | undefined; - - public setListener(listener: ScreenDprListener): void { - if (this._listener) { - this.clearListener(); - } - this._listener = listener; - this._outerListener = () => { - if (!this._listener) { - return; - } - this._listener(window.devicePixelRatio, this._currentDevicePixelRatio); - this._updateDpr(); - }; - this._updateDpr(); - } - - public dispose(): void { - super.dispose(); - this.clearListener(); - } - - private _updateDpr(): void { - if (!this._outerListener) { - return; - } - - // Clear listeners for old DPR - this._resolutionMediaMatchList?.removeListener(this._outerListener); - - // Add listeners for new DPR - this._currentDevicePixelRatio = window.devicePixelRatio; - this._resolutionMediaMatchList = window.matchMedia(`screen and (resolution: ${window.devicePixelRatio}dppx)`); - this._resolutionMediaMatchList.addListener(this._outerListener); - } - - public clearListener(): void { - if (!this._resolutionMediaMatchList || !this._listener || !this._outerListener) { - return; - } - this._resolutionMediaMatchList.removeListener(this._outerListener); - this._resolutionMediaMatchList = undefined; - this._listener = undefined; - this._outerListener = undefined; - } -} diff --git a/node_modules/xterm/src/browser/Terminal.ts b/node_modules/xterm/src/browser/Terminal.ts deleted file mode 100644 index 703c995..0000000 --- a/node_modules/xterm/src/browser/Terminal.ts +++ /dev/null @@ -1,1408 +0,0 @@ -/** - * Copyright (c) 2014 The xterm.js authors. All rights reserved. - * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License) - * @license MIT - * - * Originally forked from (with the author's permission): - * Fabrice Bellard's javascript vt100 for jslinux: - * http://bellard.org/jslinux/ - * Copyright (c) 2011 Fabrice Bellard - * The original design remains. The terminal itself - * has been extended to include xterm CSI codes, among - * other features. - * - * Terminal Emulation References: - * http://vt100.net/ - * http://invisible-island.net/xterm/ctlseqs/ctlseqs.txt - * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html - * http://invisible-island.net/vttest/ - * http://www.inwap.com/pdp10/ansicode.txt - * http://linux.die.net/man/4/console_codes - * http://linux.die.net/man/7/urxvt - */ - -import { ICompositionHelper, ITerminal, IBrowser, CustomKeyEventHandler, ILinkifier, IMouseZoneManager, LinkMatcherHandler, ILinkMatcherOptions, IViewport, ILinkifier2, CharacterJoinerHandler } from 'browser/Types'; -import { IRenderer } from 'browser/renderer/Types'; -import { CompositionHelper } from 'browser/input/CompositionHelper'; -import { Viewport } from 'browser/Viewport'; -import { rightClickHandler, moveTextAreaUnderMouseCursor, handlePasteEvent, copyHandler, paste } from 'browser/Clipboard'; -import { C0 } from 'common/data/EscapeSequences'; -import { WindowsOptionsReportType } from '../common/InputHandler'; -import { Renderer } from 'browser/renderer/Renderer'; -import { Linkifier } from 'browser/Linkifier'; -import { SelectionService } from 'browser/services/SelectionService'; -import * as Browser from 'common/Platform'; -import { addDisposableDomListener } from 'browser/Lifecycle'; -import * as Strings from 'browser/LocalizableStrings'; -import { SoundService } from 'browser/services/SoundService'; -import { MouseZoneManager } from 'browser/MouseZoneManager'; -import { AccessibilityManager } from './AccessibilityManager'; -import { ITheme, IMarker, IDisposable, ISelectionPosition, ILinkProvider, IDecorationOptions, IDecoration } from 'xterm'; -import { DomRenderer } from 'browser/renderer/dom/DomRenderer'; -import { KeyboardResultType, CoreMouseEventType, CoreMouseButton, CoreMouseAction, ITerminalOptions, ScrollSource, IColorEvent, ColorIndex, ColorRequestType } from 'common/Types'; -import { evaluateKeyboardEvent } from 'common/input/Keyboard'; -import { EventEmitter, IEvent, forwardEvent } from 'common/EventEmitter'; -import { DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; -import { ColorManager } from 'browser/ColorManager'; -import { RenderService } from 'browser/services/RenderService'; -import { ICharSizeService, IRenderService, IMouseService, ISelectionService, ISoundService, ICoreBrowserService, ICharacterJoinerService, IDecorationService } from 'browser/services/Services'; -import { CharSizeService } from 'browser/services/CharSizeService'; -import { IBuffer } from 'common/buffer/Types'; -import { MouseService } from 'browser/services/MouseService'; -import { Linkifier2 } from 'browser/Linkifier2'; -import { CoreBrowserService } from 'browser/services/CoreBrowserService'; -import { CoreTerminal } from 'common/CoreTerminal'; -import { color, rgba } from 'browser/Color'; -import { CharacterJoinerService } from 'browser/services/CharacterJoinerService'; -import { toRgbString } from 'common/input/XParseColor'; -import { DecorationService } from 'browser/services/DecorationService'; - -// Let it work inside Node.js for automated testing purposes. -const document: Document = (typeof window !== 'undefined') ? window.document : null as any; - -export class Terminal extends CoreTerminal implements ITerminal { - public textarea: HTMLTextAreaElement | undefined; - public element: HTMLElement | undefined; - public screenElement: HTMLElement | undefined; - - private _document: Document | undefined; - private _viewportScrollArea: HTMLElement | undefined; - private _viewportElement: HTMLElement | undefined; - private _helperContainer: HTMLElement | undefined; - private _compositionView: HTMLElement | undefined; - - // private _visualBellTimer: number; - - public browser: IBrowser = Browser as any; - - private _customKeyEventHandler: CustomKeyEventHandler | undefined; - - // browser services - private _charSizeService: ICharSizeService | undefined; - private _mouseService: IMouseService | undefined; - private _renderService: IRenderService | undefined; - private _characterJoinerService: ICharacterJoinerService | undefined; - private _selectionService: ISelectionService | undefined; - private _soundService: ISoundService | undefined; - - /** - * Records whether the keydown event has already been handled and triggered a data event, if so - * the keypress event should not trigger a data event but should still print to the textarea so - * screen readers will announce it. - */ - private _keyDownHandled: boolean = false; - - /** - * Records whether the keypress event has already been handled and triggered a data event, if so - * the input event should not trigger a data event but should still print to the textarea so - * screen readers will announce it. - */ - private _keyPressHandled: boolean = false; - - /** - * Records whether there has been a keydown event for a dead key without a corresponding keydown - * event for the composed/alternative character. If we cancel the keydown event for the dead key, - * no events will be emitted for the final character. - */ - private _unprocessedDeadKey: boolean = false; - - public linkifier: ILinkifier; - public linkifier2: ILinkifier2; - public viewport: IViewport | undefined; - public decorationService: IDecorationService; - private _compositionHelper: ICompositionHelper | undefined; - private _mouseZoneManager: IMouseZoneManager | undefined; - private _accessibilityManager: AccessibilityManager | undefined; - private _colorManager: ColorManager | undefined; - private _theme: ITheme | undefined; - - private _onCursorMove = new EventEmitter<void>(); - public get onCursorMove(): IEvent<void> { return this._onCursorMove.event; } - private _onKey = new EventEmitter<{ key: string, domEvent: KeyboardEvent }>(); - public get onKey(): IEvent<{ key: string, domEvent: KeyboardEvent }> { return this._onKey.event; } - private _onRender = new EventEmitter<{ start: number, end: number }>(); - public get onRender(): IEvent<{ start: number, end: number }> { return this._onRender.event; } - private _onSelectionChange = new EventEmitter<void>(); - public get onSelectionChange(): IEvent<void> { return this._onSelectionChange.event; } - private _onTitleChange = new EventEmitter<string>(); - public get onTitleChange(): IEvent<string> { return this._onTitleChange.event; } - private _onBell = new EventEmitter<void>(); - public get onBell(): IEvent<void> { return this._onBell.event; } - - private _onFocus = new EventEmitter<void>(); - public get onFocus(): IEvent<void> { return this._onFocus.event; } - private _onBlur = new EventEmitter<void>(); - public get onBlur(): IEvent<void> { return this._onBlur.event; } - private _onA11yCharEmitter = new EventEmitter<string>(); - public get onA11yChar(): IEvent<string> { return this._onA11yCharEmitter.event; } - private _onA11yTabEmitter = new EventEmitter<number>(); - public get onA11yTab(): IEvent<number> { return this._onA11yTabEmitter.event; } - - /** - * Creates a new `Terminal` object. - * - * @param options An object containing a set of options, the available options are: - * - `cursorBlink` (boolean): Whether the terminal cursor blinks - * - `cols` (number): The number of columns of the terminal (horizontal size) - * - `rows` (number): The number of rows of the terminal (vertical size) - * - * @public - * @class Xterm Xterm - * @alias module:xterm/src/xterm - */ - constructor( - options: Partial<ITerminalOptions> = {} - ) { - super(options); - - this._setup(); - - this.linkifier = this._instantiationService.createInstance(Linkifier); - this.linkifier2 = this.register(this._instantiationService.createInstance(Linkifier2)); - this.decorationService = this.register(this._instantiationService.createInstance(DecorationService)); - - // Setup InputHandler listeners - this.register(this._inputHandler.onRequestBell(() => this.bell())); - this.register(this._inputHandler.onRequestRefreshRows((start, end) => this.refresh(start, end))); - this.register(this._inputHandler.onRequestSendFocus(() => this._reportFocus())); - this.register(this._inputHandler.onRequestReset(() => this.reset())); - this.register(this._inputHandler.onRequestWindowsOptionsReport(type => this._reportWindowsOptions(type))); - this.register(this._inputHandler.onColor((event) => this._handleColorEvent(event))); - this.register(forwardEvent(this._inputHandler.onCursorMove, this._onCursorMove)); - this.register(forwardEvent(this._inputHandler.onTitleChange, this._onTitleChange)); - this.register(forwardEvent(this._inputHandler.onA11yChar, this._onA11yCharEmitter)); - this.register(forwardEvent(this._inputHandler.onA11yTab, this._onA11yTabEmitter)); - - // Setup listeners - this.register(this._bufferService.onResize(e => this._afterResize(e.cols, e.rows))); - } - - /** - * Handle color event from inputhandler for OSC 4|104 | 10|110 | 11|111 | 12|112. - * An event from OSC 4|104 may contain multiple set or report requests, and multiple - * or none restore requests (resetting all), - * while an event from OSC 10|110 | 11|111 | 12|112 always contains a single request. - */ - private _handleColorEvent(event: IColorEvent): void { - if (!this._colorManager) return; - for (const req of event) { - let acc: 'foreground' | 'background' | 'cursor' | 'ansi' | undefined = undefined; - let ident = ''; - switch (req.index) { - case ColorIndex.FOREGROUND: // OSC 10 | 110 - acc = 'foreground'; - ident = '10'; - break; - case ColorIndex.BACKGROUND: // OSC 11 | 111 - acc = 'background'; - ident = '11'; - break; - case ColorIndex.CURSOR: // OSC 12 | 112 - acc = 'cursor'; - ident = '12'; - break; - default: // OSC 4 | 104 - // we can skip the [0..255] range check here (already done in inputhandler) - acc = 'ansi'; - ident = '4;' + req.index; - } - if (acc) { - switch (req.type) { - case ColorRequestType.REPORT: - const channels = color.toColorRGB(acc === 'ansi' - ? this._colorManager.colors.ansi[req.index] - : this._colorManager.colors[acc]); - this.coreService.triggerDataEvent(`${C0.ESC}]${ident};${toRgbString(channels)}${C0.BEL}`); - break; - case ColorRequestType.SET: - if (acc === 'ansi') this._colorManager.colors.ansi[req.index] = rgba.toColor(...req.color); - else this._colorManager.colors[acc] = rgba.toColor(...req.color); - break; - case ColorRequestType.RESTORE: - this._colorManager.restoreColor(req.index); - break; - } - } - } - this._renderService?.setColors(this._colorManager.colors); - this.viewport?.onThemeChange(this._colorManager.colors); - } - - public dispose(): void { - if (this._isDisposed) { - return; - } - super.dispose(); - this._renderService?.dispose(); - this._customKeyEventHandler = undefined; - this.write = () => { }; - this.element?.parentNode?.removeChild(this.element); - } - - protected _setup(): void { - super._setup(); - - this._customKeyEventHandler = undefined; - } - - /** - * Convenience property to active buffer. - */ - public get buffer(): IBuffer { - return this.buffers.active; - } - - /** - * Focus the terminal. Delegates focus handling to the terminal's DOM element. - */ - public focus(): void { - if (this.textarea) { - this.textarea.focus({ preventScroll: true }); - } - } - - protected _updateOptions(key: string): void { - super._updateOptions(key); - - // TODO: These listeners should be owned by individual components - switch (key) { - case 'fontFamily': - case 'fontSize': - // When the font changes the size of the cells may change which requires a renderer clear - this._renderService?.clear(); - this._charSizeService?.measure(); - break; - case 'cursorBlink': - case 'cursorStyle': - // The DOM renderer needs a row refresh to update the cursor styles - this.refresh(this.buffer.y, this.buffer.y); - break; - case 'customGlyphs': - case 'drawBoldTextInBrightColors': - case 'letterSpacing': - case 'lineHeight': - case 'fontWeight': - case 'fontWeightBold': - case 'minimumContrastRatio': - // When the font changes the size of the cells may change which requires a renderer clear - if (this._renderService) { - this._renderService.clear(); - this._renderService.onResize(this.cols, this.rows); - this.refresh(0, this.rows - 1); - } - break; - case 'rendererType': - if (this._renderService) { - this._renderService.setRenderer(this._createRenderer()); - this._renderService.onResize(this.cols, this.rows); - } - break; - case 'scrollback': - this.viewport?.syncScrollArea(); - break; - case 'screenReaderMode': - if (this.optionsService.rawOptions.screenReaderMode) { - if (!this._accessibilityManager && this._renderService) { - this._accessibilityManager = new AccessibilityManager(this, this._renderService); - } - } else { - this._accessibilityManager?.dispose(); - this._accessibilityManager = undefined; - } - break; - case 'tabStopWidth': this.buffers.setupTabStops(); break; - case 'theme': - this._setTheme(this.optionsService.rawOptions.theme); - break; - } - } - - /** - * Binds the desired focus behavior on a given terminal object. - */ - private _onTextAreaFocus(ev: KeyboardEvent): void { - if (this.coreService.decPrivateModes.sendFocus) { - this.coreService.triggerDataEvent(C0.ESC + '[I'); - } - this.updateCursorStyle(ev); - this.element!.classList.add('focus'); - this._showCursor(); - this._onFocus.fire(); - } - - /** - * Blur the terminal, calling the blur function on the terminal's underlying - * textarea. - */ - public blur(): void { - return this.textarea?.blur(); - } - - /** - * Binds the desired blur behavior on a given terminal object. - */ - private _onTextAreaBlur(): void { - // Text can safely be removed on blur. Doing it earlier could interfere with - // screen readers reading it out. - this.textarea!.value = ''; - this.refresh(this.buffer.y, this.buffer.y); - if (this.coreService.decPrivateModes.sendFocus) { - this.coreService.triggerDataEvent(C0.ESC + '[O'); - } - this.element!.classList.remove('focus'); - this._onBlur.fire(); - } - - private _syncTextArea(): void { - if (!this.textarea || !this.buffer.isCursorInViewport || this._compositionHelper!.isComposing || !this._renderService) { - return; - } - const cursorY = this.buffer.ybase + this.buffer.y; - const bufferLine = this.buffer.lines.get(cursorY); - if (!bufferLine) { - return; - } - const cursorX = Math.min(this.buffer.x, this.cols - 1); - const cellHeight = this._renderService.dimensions.actualCellHeight; - const width = bufferLine.getWidth(cursorX); - const cellWidth = this._renderService.dimensions.actualCellWidth * width; - const cursorTop = this.buffer.y * this._renderService.dimensions.actualCellHeight; - const cursorLeft = cursorX * this._renderService.dimensions.actualCellWidth; - - // Sync the textarea to the exact position of the composition view so the IME knows where the - // text is. - this.textarea.style.left = cursorLeft + 'px'; - this.textarea.style.top = cursorTop + 'px'; - this.textarea.style.width = cellWidth + 'px'; - this.textarea.style.height = cellHeight + 'px'; - this.textarea.style.lineHeight = cellHeight + 'px'; - this.textarea.style.zIndex = '-5'; - } - - /** - * Initialize default behavior - */ - private _initGlobal(): void { - this._bindKeys(); - - // Bind clipboard functionality - this.register(addDisposableDomListener(this.element!, 'copy', (event: ClipboardEvent) => { - // If mouse events are active it means the selection manager is disabled and - // copy should be handled by the host program. - if (!this.hasSelection()) { - return; - } - copyHandler(event, this._selectionService!); - })); - const pasteHandlerWrapper = (event: ClipboardEvent): void => handlePasteEvent(event, this.textarea!, this.coreService); - this.register(addDisposableDomListener(this.textarea!, 'paste', pasteHandlerWrapper)); - this.register(addDisposableDomListener(this.element!, 'paste', pasteHandlerWrapper)); - - // Handle right click context menus - if (Browser.isFirefox) { - // Firefox doesn't appear to fire the contextmenu event on right click - this.register(addDisposableDomListener(this.element!, 'mousedown', (event: MouseEvent) => { - if (event.button === 2) { - rightClickHandler(event, this.textarea!, this.screenElement!, this._selectionService!, this.options.rightClickSelectsWord); - } - })); - } else { - this.register(addDisposableDomListener(this.element!, 'contextmenu', (event: MouseEvent) => { - rightClickHandler(event, this.textarea!, this.screenElement!, this._selectionService!, this.options.rightClickSelectsWord); - })); - } - - // Move the textarea under the cursor when middle clicking on Linux to ensure - // middle click to paste selection works. This only appears to work in Chrome - // at the time is writing. - if (Browser.isLinux) { - // Use auxclick event over mousedown the latter doesn't seem to work. Note - // that the regular click event doesn't fire for the middle mouse button. - this.register(addDisposableDomListener(this.element!, 'auxclick', (event: MouseEvent) => { - if (event.button === 1) { - moveTextAreaUnderMouseCursor(event, this.textarea!, this.screenElement!); - } - })); - } - } - - /** - * Apply key handling to the terminal - */ - private _bindKeys(): void { - this.register(addDisposableDomListener(this.textarea!, 'keyup', (ev: KeyboardEvent) => this._keyUp(ev), true)); - this.register(addDisposableDomListener(this.textarea!, 'keydown', (ev: KeyboardEvent) => this._keyDown(ev), true)); - this.register(addDisposableDomListener(this.textarea!, 'keypress', (ev: KeyboardEvent) => this._keyPress(ev), true)); - this.register(addDisposableDomListener(this.textarea!, 'compositionstart', () => this._compositionHelper!.compositionstart())); - this.register(addDisposableDomListener(this.textarea!, 'compositionupdate', (e: CompositionEvent) => this._compositionHelper!.compositionupdate(e))); - this.register(addDisposableDomListener(this.textarea!, 'compositionend', () => this._compositionHelper!.compositionend())); - this.register(addDisposableDomListener(this.textarea!, 'input', (ev: InputEvent) => this._inputEvent(ev), true)); - this.register(this.onRender(() => this._compositionHelper!.updateCompositionElements())); - this.register(this.onRender(e => this._queueLinkification(e.start, e.end))); - } - - /** - * Opens the terminal within an element. - * - * @param parent The element to create the terminal within. - */ - public open(parent: HTMLElement): void { - if (!parent) { - throw new Error('Terminal requires a parent element.'); - } - - if (!parent.isConnected) { - this._logService.debug('Terminal.open was called on an element that was not attached to the DOM'); - } - - this._document = parent.ownerDocument!; - - // Create main element container - this.element = this._document.createElement('div'); - this.element.dir = 'ltr'; // xterm.css assumes LTR - this.element.classList.add('terminal'); - this.element.classList.add('xterm'); - this.element.setAttribute('tabindex', '0'); - parent.appendChild(this.element); - - // Performance: Use a document fragment to build the terminal - // viewport and helper elements detached from the DOM - const fragment = document.createDocumentFragment(); - this._viewportElement = document.createElement('div'); - this._viewportElement.classList.add('xterm-viewport'); - fragment.appendChild(this._viewportElement); - this._viewportScrollArea = document.createElement('div'); - this._viewportScrollArea.classList.add('xterm-scroll-area'); - this._viewportElement.appendChild(this._viewportScrollArea); - - this.screenElement = document.createElement('div'); - this.screenElement.classList.add('xterm-screen'); - // Create the container that will hold helpers like the textarea for - // capturing DOM Events. Then produce the helpers. - this._helperContainer = document.createElement('div'); - this._helperContainer.classList.add('xterm-helpers'); - this.screenElement.appendChild(this._helperContainer); - fragment.appendChild(this.screenElement); - - this.textarea = document.createElement('textarea'); - this.textarea.classList.add('xterm-helper-textarea'); - this.textarea.setAttribute('aria-label', Strings.promptLabel); - this.textarea.setAttribute('aria-multiline', 'false'); - this.textarea.setAttribute('autocorrect', 'off'); - this.textarea.setAttribute('autocapitalize', 'off'); - this.textarea.setAttribute('spellcheck', 'false'); - this.textarea.tabIndex = 0; - this.register(addDisposableDomListener(this.textarea, 'focus', (ev: KeyboardEvent) => this._onTextAreaFocus(ev))); - this.register(addDisposableDomListener(this.textarea, 'blur', () => this._onTextAreaBlur())); - this._helperContainer.appendChild(this.textarea); - - const coreBrowserService = this._instantiationService.createInstance(CoreBrowserService, this.textarea); - this._instantiationService.setService(ICoreBrowserService, coreBrowserService); - - this._charSizeService = this._instantiationService.createInstance(CharSizeService, this._document, this._helperContainer); - this._instantiationService.setService(ICharSizeService, this._charSizeService); - - this._theme = this.options.theme || this._theme; - this._colorManager = new ColorManager(document, this.options.allowTransparency); - this.register(this.optionsService.onOptionChange(e => this._colorManager!.onOptionsChange(e))); - this._colorManager.setTheme(this._theme); - - this._characterJoinerService = this._instantiationService.createInstance(CharacterJoinerService); - this._instantiationService.setService(ICharacterJoinerService, this._characterJoinerService); - - const renderer = this._createRenderer(); - this._renderService = this.register(this._instantiationService.createInstance(RenderService, renderer, this.rows, this.screenElement)); - this._instantiationService.setService(IRenderService, this._renderService); - this.register(this._renderService.onRenderedBufferChange(e => this._onRender.fire(e))); - this.onResize(e => this._renderService!.resize(e.cols, e.rows)); - - this._compositionView = document.createElement('div'); - this._compositionView.classList.add('composition-view'); - this._compositionHelper = this._instantiationService.createInstance(CompositionHelper, this.textarea, this._compositionView); - this._helperContainer.appendChild(this._compositionView); - - // Performance: Add viewport and helper elements from the fragment - this.element.appendChild(fragment); - - this._soundService = this._instantiationService.createInstance(SoundService); - this._instantiationService.setService(ISoundService, this._soundService); - this._mouseService = this._instantiationService.createInstance(MouseService); - this._instantiationService.setService(IMouseService, this._mouseService); - - this.viewport = this._instantiationService.createInstance(Viewport, - (amount: number) => this.scrollLines(amount, true, ScrollSource.VIEWPORT), - this._viewportElement, - this._viewportScrollArea, - this.element - ); - this.viewport.onThemeChange(this._colorManager.colors); - this.register(this._inputHandler.onRequestSyncScrollBar(() => this.viewport!.syncScrollArea())); - this.register(this.viewport); - - this.register(this.onCursorMove(() => { - this._renderService!.onCursorMove(); - this._syncTextArea(); - })); - this.register(this.onResize(() => this._renderService!.onResize(this.cols, this.rows))); - this.register(this.onBlur(() => this._renderService!.onBlur())); - this.register(this.onFocus(() => this._renderService!.onFocus())); - this.register(this._renderService.onDimensionsChange(() => this.viewport!.syncScrollArea())); - - this._selectionService = this.register(this._instantiationService.createInstance(SelectionService, - this.element, - this.screenElement, - this.linkifier2 - )); - this._instantiationService.setService(ISelectionService, this._selectionService); - this.register(this._selectionService.onRequestScrollLines(e => this.scrollLines(e.amount, e.suppressScrollEvent))); - this.register(this._selectionService.onSelectionChange(() => this._onSelectionChange.fire())); - this.register(this._selectionService.onRequestRedraw(e => this._renderService!.onSelectionChanged(e.start, e.end, e.columnSelectMode))); - this.register(this._selectionService.onLinuxMouseSelection(text => { - // If there's a new selection, put it into the textarea, focus and select it - // in order to register it as a selection on the OS. This event is fired - // only on Linux to enable middle click to paste selection. - this.textarea!.value = text; - this.textarea!.focus(); - this.textarea!.select(); - })); - this.register(this._onScroll.event(ev => { - this.viewport!.syncScrollArea(); - this._selectionService!.refresh(); - })); - this.register(addDisposableDomListener(this._viewportElement, 'scroll', () => this._selectionService!.refresh())); - - this._mouseZoneManager = this._instantiationService.createInstance(MouseZoneManager, this.element, this.screenElement); - this.register(this._mouseZoneManager); - this.register(this.onScroll(() => this._mouseZoneManager!.clearAll())); - this.linkifier.attachToDom(this.element, this._mouseZoneManager); - this.linkifier2.attachToDom(this.screenElement, this._mouseService, this._renderService); - - this.decorationService.attachToDom(this.screenElement, this._renderService, this._bufferService); - // This event listener must be registered aftre MouseZoneManager is created - this.register(addDisposableDomListener(this.element, 'mousedown', (e: MouseEvent) => this._selectionService!.onMouseDown(e))); - - // apply mouse event classes set by escape codes before terminal was attached - if (this.coreMouseService.areMouseEventsActive) { - this._selectionService.disable(); - this.element.classList.add('enable-mouse-events'); - } else { - this._selectionService.enable(); - } - - if (this.options.screenReaderMode) { - // Note that this must be done *after* the renderer is created in order to - // ensure the correct order of the dprchange event - this._accessibilityManager = new AccessibilityManager(this, this._renderService); - } - - // Measure the character size - this._charSizeService.measure(); - - // Setup loop that draws to screen - this.refresh(0, this.rows - 1); - - // Initialize global actions that need to be taken on the document. - this._initGlobal(); - - // Listen for mouse events and translate - // them into terminal mouse protocols. - this.bindMouse(); - } - - private _createRenderer(): IRenderer { - switch (this.options.rendererType) { - case 'canvas': return this._instantiationService.createInstance(Renderer, this._colorManager!.colors, this.screenElement!, this.linkifier, this.linkifier2); - case 'dom': return this._instantiationService.createInstance(DomRenderer, this._colorManager!.colors, this.element!, this.screenElement!, this._viewportElement!, this.linkifier, this.linkifier2); - default: throw new Error(`Unrecognized rendererType "${this.options.rendererType}"`); - } - } - - /** - * Sets the theme on the renderer. The renderer must have been initialized. - * @param theme The theme to set. - */ - private _setTheme(theme: ITheme): void { - this._theme = theme; - this._colorManager?.setTheme(theme); - this._renderService?.setColors(this._colorManager!.colors); - this.viewport?.onThemeChange(this._colorManager!.colors); - } - - /** - * Bind certain mouse events to the terminal. - * By default only 3 button + wheel up/down is ativated. For higher buttons - * no mouse report will be created. Typically the standard actions will be active. - * - * There are several reasons not to enable support for higher buttons/wheel: - * - Button 4 and 5 are typically used for history back and forward navigation, - * there is no straight forward way to supress/intercept those standard actions. - * - Support for higher buttons does not work in some platform/browser combinations. - * - Left/right wheel was not tested. - * - Emulators vary in mouse button support, typically only 3 buttons and - * wheel up/down work reliable. - * - * TODO: Move mouse event code into its own file. - */ - public bindMouse(): void { - const self = this; - const el = this.element!; - - // send event to CoreMouseService - function sendEvent(ev: MouseEvent | WheelEvent): boolean { - // get mouse coordinates - const pos = self._mouseService!.getRawByteCoords(ev, self.screenElement!, self.cols, self.rows); - if (!pos) { - return false; - } - - let but: CoreMouseButton; - let action: CoreMouseAction | undefined; - switch ((ev as any).overrideType || ev.type) { - case 'mousemove': - action = CoreMouseAction.MOVE; - if (ev.buttons === undefined) { - // buttons is not supported on macOS, try to get a value from button instead - but = CoreMouseButton.NONE; - if (ev.button !== undefined) { - but = ev.button < 3 ? ev.button : CoreMouseButton.NONE; - } - } else { - // according to MDN buttons only reports up to button 5 (AUX2) - but = ev.buttons & 1 ? CoreMouseButton.LEFT : - ev.buttons & 4 ? CoreMouseButton.MIDDLE : - ev.buttons & 2 ? CoreMouseButton.RIGHT : - CoreMouseButton.NONE; // fallback to NONE - } - break; - case 'mouseup': - action = CoreMouseAction.UP; - but = ev.button < 3 ? ev.button : CoreMouseButton.NONE; - break; - case 'mousedown': - action = CoreMouseAction.DOWN; - but = ev.button < 3 ? ev.button : CoreMouseButton.NONE; - break; - case 'wheel': - // only UP/DOWN wheel events are respected - if ((ev as WheelEvent).deltaY !== 0) { - action = (ev as WheelEvent).deltaY < 0 ? CoreMouseAction.UP : CoreMouseAction.DOWN; - } - but = CoreMouseButton.WHEEL; - break; - default: - // dont handle other event types by accident - return false; - } - - // exit if we cannot determine valid button/action values - // do nothing for higher buttons than wheel - if (action === undefined || but === undefined || but > CoreMouseButton.WHEEL) { - return false; - } - - return self.coreMouseService.triggerMouseEvent({ - col: pos.x - 33, // FIXME: why -33 here? - row: pos.y - 33, - button: but, - action, - ctrl: ev.ctrlKey, - alt: ev.altKey, - shift: ev.shiftKey - }); - } - - /** - * Event listener state handling. - * We listen to the onProtocolChange event of CoreMouseService and put - * requested listeners in `requestedEvents`. With this the listeners - * have all bits to do the event listener juggling. - * Note: 'mousedown' currently is "always on" and not managed - * by onProtocolChange. - */ - const requestedEvents: { [key: string]: ((ev: Event) => void) | null } = { - mouseup: null, - wheel: null, - mousedrag: null, - mousemove: null - }; - const eventListeners: { [key: string]: (ev: any) => void | boolean } = { - mouseup: (ev: MouseEvent) => { - sendEvent(ev); - if (!ev.buttons) { - // if no other button is held remove global handlers - this._document!.removeEventListener('mouseup', requestedEvents.mouseup!); - if (requestedEvents.mousedrag) { - this._document!.removeEventListener('mousemove', requestedEvents.mousedrag); - } - } - return this.cancel(ev); - }, - wheel: (ev: WheelEvent) => { - sendEvent(ev); - return this.cancel(ev, true); - }, - mousedrag: (ev: MouseEvent) => { - // deal only with move while a button is held - if (ev.buttons) { - sendEvent(ev); - } - }, - mousemove: (ev: MouseEvent) => { - // deal only with move without any button - if (!ev.buttons) { - sendEvent(ev); - } - } - }; - this.register(this.coreMouseService.onProtocolChange(events => { - // apply global changes on events - if (events) { - if (this.optionsService.rawOptions.logLevel === 'debug') { - this._logService.debug('Binding to mouse events:', this.coreMouseService.explainEvents(events)); - } - this.element!.classList.add('enable-mouse-events'); - this._selectionService!.disable(); - } else { - this._logService.debug('Unbinding from mouse events.'); - this.element!.classList.remove('enable-mouse-events'); - this._selectionService!.enable(); - } - - // add/remove handlers from requestedEvents - - if (!(events & CoreMouseEventType.MOVE)) { - el.removeEventListener('mousemove', requestedEvents.mousemove!); - requestedEvents.mousemove = null; - } else if (!requestedEvents.mousemove) { - el.addEventListener('mousemove', eventListeners.mousemove); - requestedEvents.mousemove = eventListeners.mousemove; - } - - if (!(events & CoreMouseEventType.WHEEL)) { - el.removeEventListener('wheel', requestedEvents.wheel!); - requestedEvents.wheel = null; - } else if (!requestedEvents.wheel) { - el.addEventListener('wheel', eventListeners.wheel, { passive: false }); - requestedEvents.wheel = eventListeners.wheel; - } - - if (!(events & CoreMouseEventType.UP)) { - this._document!.removeEventListener('mouseup', requestedEvents.mouseup!); - requestedEvents.mouseup = null; - } else if (!requestedEvents.mouseup) { - requestedEvents.mouseup = eventListeners.mouseup; - } - - if (!(events & CoreMouseEventType.DRAG)) { - this._document!.removeEventListener('mousemove', requestedEvents.mousedrag!); - requestedEvents.mousedrag = null; - } else if (!requestedEvents.mousedrag) { - requestedEvents.mousedrag = eventListeners.mousedrag; - } - })); - // force initial onProtocolChange so we dont miss early mouse requests - this.coreMouseService.activeProtocol = this.coreMouseService.activeProtocol; - - /** - * "Always on" event listeners. - */ - this.register(addDisposableDomListener(el, 'mousedown', (ev: MouseEvent) => { - ev.preventDefault(); - this.focus(); - - // Don't send the mouse button to the pty if mouse events are disabled or - // if the selection manager is having selection forced (ie. a modifier is - // held). - if (!this.coreMouseService.areMouseEventsActive || this._selectionService!.shouldForceSelection(ev)) { - return; - } - - sendEvent(ev); - - // Register additional global handlers which should keep reporting outside - // of the terminal element. - // Note: Other emulators also do this for 'mousedown' while a button - // is held, we currently limit 'mousedown' to the terminal only. - if (requestedEvents.mouseup) { - this._document!.addEventListener('mouseup', requestedEvents.mouseup); - } - if (requestedEvents.mousedrag) { - this._document!.addEventListener('mousemove', requestedEvents.mousedrag); - } - - return this.cancel(ev); - })); - - this.register(addDisposableDomListener(el, 'wheel', (ev: WheelEvent) => { - // do nothing, if app side handles wheel itself - if (requestedEvents.wheel) return; - - if (!this.buffer.hasScrollback) { - // Convert wheel events into up/down events when the buffer does not have scrollback, this - // enables scrolling in apps hosted in the alt buffer such as vim or tmux. - const amount = this.viewport!.getLinesScrolled(ev); - - // Do nothing if there's no vertical scroll - if (amount === 0) { - return; - } - - // Construct and send sequences - const sequence = C0.ESC + (this.coreService.decPrivateModes.applicationCursorKeys ? 'O' : '[') + (ev.deltaY < 0 ? 'A' : 'B'); - let data = ''; - for (let i = 0; i < Math.abs(amount); i++) { - data += sequence; - } - this.coreService.triggerDataEvent(data, true); - return this.cancel(ev, true); - } - - // normal viewport scrolling - // conditionally stop event, if the viewport still had rows to scroll within - if (this.viewport!.onWheel(ev)) { - return this.cancel(ev); - } - }, { passive: false })); - - this.register(addDisposableDomListener(el, 'touchstart', (ev: TouchEvent) => { - if (this.coreMouseService.areMouseEventsActive) return; - this.viewport!.onTouchStart(ev); - return this.cancel(ev); - }, { passive: true })); - - this.register(addDisposableDomListener(el, 'touchmove', (ev: TouchEvent) => { - if (this.coreMouseService.areMouseEventsActive) return; - if (!this.viewport!.onTouchMove(ev)) { - return this.cancel(ev); - } - }, { passive: false })); - } - - - /** - * Tells the renderer to refresh terminal content between two rows (inclusive) at the next - * opportunity. - * @param start The row to start from (between 0 and this.rows - 1). - * @param end The row to end at (between start and this.rows - 1). - */ - public refresh(start: number, end: number): void { - this._renderService?.refreshRows(start, end); - } - - /** - * Queues linkification for the specified rows. - * @param start The row to start from (between 0 and this.rows - 1). - * @param end The row to end at (between start and this.rows - 1). - */ - private _queueLinkification(start: number, end: number): void { - this.linkifier?.linkifyRows(start, end); - } - - /** - * Change the cursor style for different selection modes - */ - public updateCursorStyle(ev: KeyboardEvent): void { - if (this._selectionService?.shouldColumnSelect(ev)) { - this.element!.classList.add('column-select'); - } else { - this.element!.classList.remove('column-select'); - } - } - - /** - * Display the cursor element - */ - private _showCursor(): void { - if (!this.coreService.isCursorInitialized) { - this.coreService.isCursorInitialized = true; - this.refresh(this.buffer.y, this.buffer.y); - } - } - - public scrollLines(disp: number, suppressScrollEvent?: boolean, source = ScrollSource.TERMINAL): void { - super.scrollLines(disp, suppressScrollEvent, source); - this.refresh(0, this.rows - 1); - } - - public paste(data: string): void { - paste(data, this.textarea!, this.coreService); - } - - /** - * Attaches a custom key event handler which is run before keys are processed, - * giving consumers of xterm.js ultimate control as to what keys should be - * processed by the terminal and what keys should not. - * @param customKeyEventHandler The custom KeyboardEvent handler to attach. - * This is a function that takes a KeyboardEvent, allowing consumers to stop - * propagation and/or prevent the default action. The function returns whether - * the event should be processed by xterm.js. - */ - public attachCustomKeyEventHandler(customKeyEventHandler: CustomKeyEventHandler): void { - this._customKeyEventHandler = customKeyEventHandler; - } - - /** - * Registers a link matcher, allowing custom link patterns to be matched and - * handled. - * @param regex The regular expression to search for, specifically - * this searches the textContent of the rows. You will want to use \s to match - * a space ' ' character for example. - * @param handler The callback when the link is called. - * @param options Options for the link matcher. - * @return The ID of the new matcher, this can be used to deregister. - */ - public registerLinkMatcher(regex: RegExp, handler: LinkMatcherHandler, options?: ILinkMatcherOptions): number { - const matcherId = this.linkifier.registerLinkMatcher(regex, handler, options); - this.refresh(0, this.rows - 1); - return matcherId; - } - - /** - * Deregisters a link matcher if it has been registered. - * @param matcherId The link matcher's ID (returned after register) - */ - public deregisterLinkMatcher(matcherId: number): void { - if (this.linkifier.deregisterLinkMatcher(matcherId)) { - this.refresh(0, this.rows - 1); - } - } - - public registerLinkProvider(linkProvider: ILinkProvider): IDisposable { - return this.linkifier2.registerLinkProvider(linkProvider); - } - - public registerCharacterJoiner(handler: CharacterJoinerHandler): number { - if (!this._characterJoinerService) { - throw new Error('Terminal must be opened first'); - } - const joinerId = this._characterJoinerService.register(handler); - this.refresh(0, this.rows - 1); - return joinerId; - } - - public deregisterCharacterJoiner(joinerId: number): void { - if (!this._characterJoinerService) { - throw new Error('Terminal must be opened first'); - } - if (this._characterJoinerService.deregister(joinerId)) { - this.refresh(0, this.rows - 1); - } - } - - public get markers(): IMarker[] { - return this.buffer.markers; - } - - public addMarker(cursorYOffset: number): IMarker | undefined { - // Disallow markers on the alt buffer - if (this.buffer !== this.buffers.normal) { - return; - } - - return this.buffer.addMarker(this.buffer.ybase + this.buffer.y + cursorYOffset); - } - - public registerDecoration(decorationOptions: IDecorationOptions): IDecoration | undefined { - return this.decorationService!.registerDecoration(decorationOptions); - } - - /** - * Gets whether the terminal has an active selection. - */ - public hasSelection(): boolean { - return this._selectionService ? this._selectionService.hasSelection : false; - } - - /** - * Selects text within the terminal. - * @param column The column the selection starts at.. - * @param row The row the selection starts at. - * @param length The length of the selection. - */ - public select(column: number, row: number, length: number): void { - this._selectionService!.setSelection(column, row, length); - } - - /** - * Gets the terminal's current selection, this is useful for implementing copy - * behavior outside of xterm.js. - */ - public getSelection(): string { - return this._selectionService ? this._selectionService.selectionText : ''; - } - - public getSelectionPosition(): ISelectionPosition | undefined { - if (!this._selectionService || !this._selectionService.hasSelection) { - return undefined; - } - - return { - startColumn: this._selectionService.selectionStart![0], - startRow: this._selectionService.selectionStart![1], - endColumn: this._selectionService.selectionEnd![0], - endRow: this._selectionService.selectionEnd![1] - }; - } - - /** - * Clears the current terminal selection. - */ - public clearSelection(): void { - this._selectionService?.clearSelection(); - } - - /** - * Selects all text within the terminal. - */ - public selectAll(): void { - this._selectionService?.selectAll(); - } - - public selectLines(start: number, end: number): void { - this._selectionService?.selectLines(start, end); - } - - /** - * Handle a keydown event - * Key Resources: - * - https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent - * @param ev The keydown event to be handled. - */ - protected _keyDown(event: KeyboardEvent): boolean | undefined { - this._keyDownHandled = false; - - if (this._customKeyEventHandler && this._customKeyEventHandler(event) === false) { - return false; - } - - if (!this._compositionHelper!.keydown(event)) { - if (this.buffer.ybase !== this.buffer.ydisp) { - this._bufferService.scrollToBottom(); - } - return false; - } - - if (event.key === 'Dead' || event.key === 'AltGraph') { - this._unprocessedDeadKey = true; - } - - const result = evaluateKeyboardEvent(event, this.coreService.decPrivateModes.applicationCursorKeys, this.browser.isMac, this.options.macOptionIsMeta); - - this.updateCursorStyle(event); - - if (result.type === KeyboardResultType.PAGE_DOWN || result.type === KeyboardResultType.PAGE_UP) { - const scrollCount = this.rows - 1; - this.scrollLines(result.type === KeyboardResultType.PAGE_UP ? -scrollCount : scrollCount); - return this.cancel(event, true); - } - - if (result.type === KeyboardResultType.SELECT_ALL) { - this.selectAll(); - } - - if (this._isThirdLevelShift(this.browser, event)) { - return true; - } - - if (result.cancel) { - // The event is canceled at the end already, is this necessary? - this.cancel(event, true); - } - - if (!result.key) { - return true; - } - - if (this._unprocessedDeadKey) { - this._unprocessedDeadKey = false; - return true; - } - - // If ctrl+c or enter is being sent, clear out the textarea. This is done so that screen readers - // will announce deleted characters. This will not work 100% of the time but it should cover - // most scenarios. - if (result.key === C0.ETX || result.key === C0.CR) { - this.textarea!.value = ''; - } - - this._onKey.fire({ key: result.key, domEvent: event }); - this._showCursor(); - this.coreService.triggerDataEvent(result.key, true); - - // Cancel events when not in screen reader mode so events don't get bubbled up and handled by - // other listeners. When screen reader mode is enabled, this could cause issues if the event - // is handled at a higher level, this is a compromise in order to echo keys to the screen - // reader. - if (!this.optionsService.rawOptions.screenReaderMode) { - return this.cancel(event, true); - } - - this._keyDownHandled = true; - } - - private _isThirdLevelShift(browser: IBrowser, ev: KeyboardEvent): boolean { - const thirdLevelKey = - (browser.isMac && !this.options.macOptionIsMeta && ev.altKey && !ev.ctrlKey && !ev.metaKey) || - (browser.isWindows && ev.altKey && ev.ctrlKey && !ev.metaKey) || - (browser.isWindows && ev.getModifierState('AltGraph')); - - if (ev.type === 'keypress') { - return thirdLevelKey; - } - - // Don't invoke for arrows, pageDown, home, backspace, etc. (on non-keypress events) - return thirdLevelKey && (!ev.keyCode || ev.keyCode > 47); - } - - protected _keyUp(ev: KeyboardEvent): void { - if (this._customKeyEventHandler && this._customKeyEventHandler(ev) === false) { - return; - } - - if (!wasModifierKeyOnlyEvent(ev)) { - this.focus(); - } - - this.updateCursorStyle(ev); - this._keyPressHandled = false; - } - - /** - * Handle a keypress event. - * Key Resources: - * - https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent - * @param ev The keypress event to be handled. - */ - protected _keyPress(ev: KeyboardEvent): boolean { - let key; - - this._keyPressHandled = false; - - if (this._keyDownHandled) { - return false; - } - - if (this._customKeyEventHandler && this._customKeyEventHandler(ev) === false) { - return false; - } - - this.cancel(ev); - - if (ev.charCode) { - key = ev.charCode; - } else if (ev.which === null || ev.which === undefined) { - key = ev.keyCode; - } else if (ev.which !== 0 && ev.charCode !== 0) { - key = ev.which; - } else { - return false; - } - - if (!key || ( - (ev.altKey || ev.ctrlKey || ev.metaKey) && !this._isThirdLevelShift(this.browser, ev) - )) { - return false; - } - - key = String.fromCharCode(key); - - this._onKey.fire({ key, domEvent: ev }); - this._showCursor(); - this.coreService.triggerDataEvent(key, true); - - this._keyPressHandled = true; - - // The key was handled so clear the dead key state, otherwise certain keystrokes like arrow - // keys could be ignored - this._unprocessedDeadKey = false; - - return true; - } - - /** - * Handle an input event. - * Key Resources: - * - https://developer.mozilla.org/en-US/docs/Web/API/InputEvent - * @param ev The input event to be handled. - */ - protected _inputEvent(ev: InputEvent): boolean { - // Only support emoji IMEs when screen reader mode is disabled as the event must bubble up to - // support reading out character input which can doubling up input characters - if (ev.data && ev.inputType === 'insertText' && !ev.composed && !this.optionsService.rawOptions.screenReaderMode) { - if (this._keyPressHandled) { - return false; - } - - // The key was handled so clear the dead key state, otherwise certain keystrokes like arrow - // keys could be ignored - this._unprocessedDeadKey = false; - - const text = ev.data; - this.coreService.triggerDataEvent(text, true); - - this.cancel(ev); - return true; - } - - return false; - } - - /** - * Ring the bell. - * Note: We could do sweet things with webaudio here - */ - public bell(): void { - if (this._soundBell()) { - this._soundService?.playBellSound(); - } - - this._onBell.fire(); - - // if (this._visualBell()) { - // this.element.classList.add('visual-bell-active'); - // clearTimeout(this._visualBellTimer); - // this._visualBellTimer = window.setTimeout(() => { - // this.element.classList.remove('visual-bell-active'); - // }, 200); - // } - } - - /** - * Resizes the terminal. - * - * @param x The number of columns to resize to. - * @param y The number of rows to resize to. - */ - public resize(x: number, y: number): void { - if (x === this.cols && y === this.rows) { - // Check if we still need to measure the char size (fixes #785). - if (this._charSizeService && !this._charSizeService.hasValidSize) { - this._charSizeService.measure(); - } - return; - } - - super.resize(x, y); - } - - private _afterResize(x: number, y: number): void { - this._charSizeService?.measure(); - - // Sync the scroll area to make sure scroll events don't fire and scroll the viewport to an - // invalid location - this.viewport?.syncScrollArea(true); - } - - /** - * Clear the entire buffer, making the prompt line the new first line. - */ - public clear(): void { - if (this.buffer.ybase === 0 && this.buffer.y === 0) { - // Don't clear if it's already clear - return; - } - this.buffer.clearMarkers(); - this.buffer.lines.set(0, this.buffer.lines.get(this.buffer.ybase + this.buffer.y)!); - this.buffer.lines.length = 1; - this.buffer.ydisp = 0; - this.buffer.ybase = 0; - this.buffer.y = 0; - for (let i = 1; i < this.rows; i++) { - this.buffer.lines.push(this.buffer.getBlankLine(DEFAULT_ATTR_DATA)); - } - this.refresh(0, this.rows - 1); - this._onScroll.fire({ position: this.buffer.ydisp, source: ScrollSource.TERMINAL }); - } - - /** - * Reset terminal. - * Note: Calling this directly from JS is synchronous but does not clear - * input buffers and does not reset the parser, thus the terminal will - * continue to apply pending input data. - * If you need in band reset (synchronous with input data) consider - * using DECSTR (soft reset, CSI ! p) or RIS instead (hard reset, ESC c). - */ - public reset(): void { - /** - * Since _setup handles a full terminal creation, we have to carry forward - * a few things that should not reset. - */ - this.options.rows = this.rows; - this.options.cols = this.cols; - const customKeyEventHandler = this._customKeyEventHandler; - - this._setup(); - super.reset(); - this._selectionService?.reset(); - - // reattach - this._customKeyEventHandler = customKeyEventHandler; - - // do a full screen refresh - this.refresh(0, this.rows - 1); - this.viewport?.syncScrollArea(); - } - - public clearTextureAtlas(): void { - this._renderService?.clearTextureAtlas(); - } - - private _reportFocus(): void { - if (this.element?.classList.contains('focus')) { - this.coreService.triggerDataEvent(C0.ESC + '[I'); - } else { - this.coreService.triggerDataEvent(C0.ESC + '[O'); - } - } - - private _reportWindowsOptions(type: WindowsOptionsReportType): void { - if (!this._renderService) { - return; - } - - switch (type) { - case WindowsOptionsReportType.GET_WIN_SIZE_PIXELS: - const canvasWidth = this._renderService.dimensions.scaledCanvasWidth.toFixed(0); - const canvasHeight = this._renderService.dimensions.scaledCanvasHeight.toFixed(0); - this.coreService.triggerDataEvent(`${C0.ESC}[4;${canvasHeight};${canvasWidth}t`); - break; - case WindowsOptionsReportType.GET_CELL_SIZE_PIXELS: - const cellWidth = this._renderService.dimensions.scaledCellWidth.toFixed(0); - const cellHeight = this._renderService.dimensions.scaledCellHeight.toFixed(0); - this.coreService.triggerDataEvent(`${C0.ESC}[6;${cellHeight};${cellWidth}t`); - break; - } - } - - // TODO: Remove cancel function and cancelEvents option - public cancel(ev: Event, force?: boolean): boolean | undefined { - if (!this.options.cancelEvents && !force) { - return; - } - ev.preventDefault(); - ev.stopPropagation(); - return false; - } - - private _visualBell(): boolean { - return false; - // return this.options.bellStyle === 'visual' || - // this.options.bellStyle === 'both'; - } - - private _soundBell(): boolean { - return this.options.bellStyle === 'sound'; - // return this.options.bellStyle === 'sound' || - // this.options.bellStyle === 'both'; - } -} - -/** - * Helpers - */ - -function wasModifierKeyOnlyEvent(ev: KeyboardEvent): boolean { - return ev.keyCode === 16 || // Shift - ev.keyCode === 17 || // Ctrl - ev.keyCode === 18; // Alt -} diff --git a/node_modules/xterm/src/browser/TimeBasedDebouncer.ts b/node_modules/xterm/src/browser/TimeBasedDebouncer.ts deleted file mode 100644 index 707e25c..0000000 --- a/node_modules/xterm/src/browser/TimeBasedDebouncer.ts +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (c) 2018 The xterm.js authors. All rights reserved. - * @license MIT - */ - -const RENDER_DEBOUNCE_THRESHOLD_MS = 1000; // 1 Second - -import { IRenderDebouncer } from 'browser/Types'; - -/** - * Debounces calls to update screen readers to update at most once configurable interval of time. - */ -export class TimeBasedDebouncer implements IRenderDebouncer { - private _rowStart: number | undefined; - private _rowEnd: number | undefined; - private _rowCount: number | undefined; - - // The last moment that the Terminal was refreshed at - private _lastRefreshMs = 0; - // Whether a trailing refresh should be triggered due to a refresh request that was throttled - private _additionalRefreshRequested = false; - - private _refreshTimeoutID: number | undefined; - - constructor( - private _renderCallback: (start: number, end: number) => void, - private readonly _debounceThresholdMS = RENDER_DEBOUNCE_THRESHOLD_MS - ) { - } - - public dispose(): void { - if (this._refreshTimeoutID) { - clearTimeout(this._refreshTimeoutID); - } - } - - public refresh(rowStart: number | undefined, rowEnd: number | undefined, rowCount: number): void { - this._rowCount = rowCount; - // Get the min/max row start/end for the arg values - rowStart = rowStart !== undefined ? rowStart : 0; - rowEnd = rowEnd !== undefined ? rowEnd : this._rowCount - 1; - // Set the properties to the updated values - this._rowStart = this._rowStart !== undefined ? Math.min(this._rowStart, rowStart) : rowStart; - this._rowEnd = this._rowEnd !== undefined ? Math.max(this._rowEnd, rowEnd) : rowEnd; - - // Only refresh if the time since last refresh is above a threshold, otherwise wait for - // enough time to pass before refreshing again. - const refreshRequestTime: number = Date.now(); - if (refreshRequestTime - this._lastRefreshMs >= this._debounceThresholdMS) { - // Enough time has lapsed since the last refresh; refresh immediately - this._lastRefreshMs = refreshRequestTime; - this._innerRefresh(); - } else if (!this._additionalRefreshRequested) { - // This is the first additional request throttled; set up trailing refresh - const elapsed = refreshRequestTime - this._lastRefreshMs; - const waitPeriodBeforeTrailingRefresh = this._debounceThresholdMS - elapsed; - this._additionalRefreshRequested = true; - - this._refreshTimeoutID = window.setTimeout(() => { - this._lastRefreshMs = Date.now(); - this._innerRefresh(); - this._additionalRefreshRequested = false; - this._refreshTimeoutID = undefined; // No longer need to clear the timeout - }, waitPeriodBeforeTrailingRefresh); - } - } - - private _innerRefresh(): void { - // Make sure values are set - if (this._rowStart === undefined || this._rowEnd === undefined || this._rowCount === undefined) { - return; - } - - // Clamp values - const start = Math.max(this._rowStart, 0); - const end = Math.min(this._rowEnd, this._rowCount - 1); - - // Reset debouncer (this happens before render callback as the render could trigger it again) - this._rowStart = undefined; - this._rowEnd = undefined; - - // Run render callback - this._renderCallback(start, end); - } -} - diff --git a/node_modules/xterm/src/browser/Types.d.ts b/node_modules/xterm/src/browser/Types.d.ts deleted file mode 100644 index 35b52d6..0000000 --- a/node_modules/xterm/src/browser/Types.d.ts +++ /dev/null @@ -1,316 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IDecorationOptions, IDecoration, IDisposable, IMarker, ISelectionPosition } from 'xterm'; -import { IEvent } from 'common/EventEmitter'; -import { ICoreTerminal, CharData, ITerminalOptions } from 'common/Types'; -import { IMouseService, IRenderService } from './services/Services'; -import { IBuffer } from 'common/buffer/Types'; -import { IFunctionIdentifier, IParams } from 'common/parser/Types'; - -export interface ITerminal extends IPublicTerminal, ICoreTerminal { - element: HTMLElement | undefined; - screenElement: HTMLElement | undefined; - browser: IBrowser; - buffer: IBuffer; - viewport: IViewport | undefined; - options: ITerminalOptions; - linkifier: ILinkifier; - linkifier2: ILinkifier2; - - onBlur: IEvent<void>; - onFocus: IEvent<void>; - onA11yChar: IEvent<string>; - onA11yTab: IEvent<number>; - - cancel(ev: Event, force?: boolean): boolean | void; -} - -// Portions of the public API that are required by the internal Terminal -export interface IPublicTerminal extends IDisposable { - textarea: HTMLTextAreaElement | undefined; - rows: number; - cols: number; - buffer: IBuffer; - markers: IMarker[]; - onCursorMove: IEvent<void>; - onData: IEvent<string>; - onBinary: IEvent<string>; - onKey: IEvent<{ key: string, domEvent: KeyboardEvent }>; - onLineFeed: IEvent<void>; - onScroll: IEvent<number>; - onSelectionChange: IEvent<void>; - onRender: IEvent<{ start: number, end: number }>; - onResize: IEvent<{ cols: number, rows: number }>; - onTitleChange: IEvent<string>; - onBell: IEvent<void>; - blur(): void; - focus(): void; - resize(columns: number, rows: number): void; - open(parent: HTMLElement): void; - attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void; - registerCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean | Promise<boolean>): IDisposable; - registerDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean | Promise<boolean>): IDisposable; - registerEscHandler(id: IFunctionIdentifier, callback: () => boolean | Promise<boolean>): IDisposable; - registerOscHandler(ident: number, callback: (data: string) => boolean | Promise<boolean>): IDisposable; - registerLinkMatcher(regex: RegExp, handler: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions): number; - deregisterLinkMatcher(matcherId: number): void; - registerLinkProvider(linkProvider: ILinkProvider): IDisposable; - registerCharacterJoiner(handler: (text: string) => [number, number][]): number; - deregisterCharacterJoiner(joinerId: number): void; - addMarker(cursorYOffset: number): IMarker | undefined; - registerDecoration(decorationOptions: IDecorationOptions): IDecoration | undefined; - hasSelection(): boolean; - getSelection(): string; - getSelectionPosition(): ISelectionPosition | undefined; - clearSelection(): void; - select(column: number, row: number, length: number): void; - selectAll(): void; - selectLines(start: number, end: number): void; - dispose(): void; - scrollLines(amount: number): void; - scrollPages(pageCount: number): void; - scrollToTop(): void; - scrollToBottom(): void; - scrollToLine(line: number): void; - clear(): void; - write(data: string | Uint8Array, callback?: () => void): void; - paste(data: string): void; - refresh(start: number, end: number): void; - clearTextureAtlas(): void; - reset(): void; -} - -export type CustomKeyEventHandler = (event: KeyboardEvent) => boolean; - -export type LineData = CharData[]; - -export interface ICompositionHelper { - readonly isComposing: boolean; - compositionstart(): void; - compositionupdate(ev: CompositionEvent): void; - compositionend(): void; - updateCompositionElements(dontRecurse?: boolean): void; - keydown(ev: KeyboardEvent): boolean; -} - -export interface IBrowser { - isNode: boolean; - userAgent: string; - platform: string; - isFirefox: boolean; - isMac: boolean; - isIpad: boolean; - isIphone: boolean; - isWindows: boolean; -} - -export interface IColorManager { - colors: IColorSet; - onOptionsChange(key: string): void; -} - -export interface IColor { - css: string; - rgba: number; // 32-bit int with rgba in each byte -} - -export interface IColorSet { - foreground: IColor; - background: IColor; - cursor: IColor; - cursorAccent: IColor; - selectionTransparent: IColor; - /** The selection blended on top of background. */ - selectionOpaque: IColor; - ansi: IColor[]; - contrastCache: IColorContrastCache; -} - -export interface IColorContrastCache { - clear(): void; - setCss(bg: number, fg: number, value: string | null): void; - getCss(bg: number, fg: number): string | null | undefined; - setColor(bg: number, fg: number, value: IColor | null): void; - getColor(bg: number, fg: number): IColor | null | undefined; -} - -export interface IPartialColorSet { - foreground: IColor; - background: IColor; - cursor?: IColor; - cursorAccent?: IColor; - selection?: IColor; - ansi: IColor[]; -} - -export interface IViewport extends IDisposable { - scrollBarWidth: number; - syncScrollArea(immediate?: boolean): void; - getLinesScrolled(ev: WheelEvent): number; - onWheel(ev: WheelEvent): boolean; - onTouchStart(ev: TouchEvent): void; - onTouchMove(ev: TouchEvent): boolean; - onThemeChange(colors: IColorSet): void; -} - -export interface IViewportRange { - start: IViewportRangePosition; - end: IViewportRangePosition; -} - -export interface IViewportRangePosition { - x: number; - y: number; -} - -export type LinkMatcherHandler = (event: MouseEvent, uri: string) => void; -export type LinkMatcherHoverTooltipCallback = (event: MouseEvent, uri: string, position: IViewportRange) => void; -export type LinkMatcherValidationCallback = (uri: string, callback: (isValid: boolean) => void) => void; - -export interface ILinkMatcher { - id: number; - regex: RegExp; - handler: LinkMatcherHandler; - hoverTooltipCallback?: LinkMatcherHoverTooltipCallback; - hoverLeaveCallback?: () => void; - matchIndex?: number; - validationCallback?: LinkMatcherValidationCallback; - priority?: number; - willLinkActivate?: (event: MouseEvent, uri: string) => boolean; -} - -export interface IRegisteredLinkMatcher extends ILinkMatcher { - priority: number; -} - -export interface ILinkifierEvent { - x1: number; - y1: number; - x2: number; - y2: number; - cols: number; - fg: number | undefined; -} - -export interface ILinkifier { - onShowLinkUnderline: IEvent<ILinkifierEvent>; - onHideLinkUnderline: IEvent<ILinkifierEvent>; - onLinkTooltip: IEvent<ILinkifierEvent>; - - attachToDom(element: HTMLElement, mouseZoneManager: IMouseZoneManager): void; - linkifyRows(start: number, end: number): void; - registerLinkMatcher(regex: RegExp, handler: LinkMatcherHandler, options?: ILinkMatcherOptions): number; - deregisterLinkMatcher(matcherId: number): boolean; -} - -interface ILinkState { - decorations: ILinkDecorations; - isHovered: boolean; -} -export interface ILinkWithState { - link: ILink; - state?: ILinkState; -} - -export interface ILinkifier2 { - onShowLinkUnderline: IEvent<ILinkifierEvent>; - onHideLinkUnderline: IEvent<ILinkifierEvent>; - readonly currentLink: ILinkWithState | undefined; - - attachToDom(element: HTMLElement, mouseService: IMouseService, renderService: IRenderService): void; - registerLinkProvider(linkProvider: ILinkProvider): IDisposable; -} - -export interface ILinkMatcherOptions { - /** - * The index of the link from the regex.match(text) call. This defaults to 0 - * (for regular expressions without capture groups). - */ - matchIndex?: number; - /** - * A callback that validates an individual link, returning true if valid and - * false if invalid. - */ - validationCallback?: LinkMatcherValidationCallback; - /** - * A callback that fires when the mouse hovers over a link. - */ - tooltipCallback?: LinkMatcherHoverTooltipCallback; - /** - * A callback that fires when the mouse leaves a link that was hovered. - */ - leaveCallback?: () => void; - /** - * The priority of the link matcher, this defines the order in which the link - * matcher is evaluated relative to others, from highest to lowest. The - * default value is 0. - */ - priority?: number; - /** - * A callback that fires when the mousedown and click events occur that - * determines whether a link will be activated upon click. This enables - * only activating a link when a certain modifier is held down, if not the - * mouse event will continue propagation (eg. double click to select word). - */ - willLinkActivate?: (event: MouseEvent, uri: string) => boolean; -} - -export interface IMouseZoneManager extends IDisposable { - add(zone: IMouseZone): void; - clearAll(start?: number, end?: number): void; -} - -export interface IMouseZone { - x1: number; - x2: number; - y1: number; - y2: number; - clickCallback: (e: MouseEvent) => any; - hoverCallback: (e: MouseEvent) => any | undefined; - tooltipCallback: (e: MouseEvent) => any | undefined; - leaveCallback: () => any | undefined; - willLinkActivate: (e: MouseEvent) => boolean; -} - -interface ILinkProvider { - provideLinks(y: number, callback: (links: ILink[] | undefined) => void): void; -} - -interface ILink { - range: IBufferRange; - text: string; - decorations?: ILinkDecorations; - activate(event: MouseEvent, text: string): void; - hover?(event: MouseEvent, text: string): void; - leave?(event: MouseEvent, text: string): void; - dispose?(): void; -} - -interface ILinkDecorations { - pointerCursor: boolean; - underline: boolean; -} - -interface IBufferRange { - start: IBufferCellPosition; - end: IBufferCellPosition; -} - -interface IBufferCellPosition { - x: number; - y: number; -} - -export type CharacterJoinerHandler = (text: string) => [number, number][]; - -export interface ICharacterJoiner { - id: number; - handler: CharacterJoinerHandler; -} - -export interface IRenderDebouncer extends IDisposable { - refresh(rowStart: number | undefined, rowEnd: number | undefined, rowCount: number): void; -} diff --git a/node_modules/xterm/src/browser/Viewport.ts b/node_modules/xterm/src/browser/Viewport.ts deleted file mode 100644 index 14fab89..0000000 --- a/node_modules/xterm/src/browser/Viewport.ts +++ /dev/null @@ -1,294 +0,0 @@ -/** - * Copyright (c) 2016 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { Disposable } from 'common/Lifecycle'; -import { addDisposableDomListener } from 'browser/Lifecycle'; -import { IColorSet, IViewport } from 'browser/Types'; -import { ICharSizeService, IRenderService } from 'browser/services/Services'; -import { IBufferService, IOptionsService } from 'common/services/Services'; -import { IBuffer } from 'common/buffer/Types'; -import { IRenderDimensions } from 'browser/renderer/Types'; - -const FALLBACK_SCROLL_BAR_WIDTH = 15; - -/** - * Represents the viewport of a terminal, the visible area within the larger buffer of output. - * Logic for the virtual scroll bar is included in this object. - */ -export class Viewport extends Disposable implements IViewport { - public scrollBarWidth: number = 0; - private _currentRowHeight: number = 0; - private _currentScaledCellHeight: number = 0; - private _lastRecordedBufferLength: number = 0; - private _lastRecordedViewportHeight: number = 0; - private _lastRecordedBufferHeight: number = 0; - private _lastTouchY: number = 0; - private _lastScrollTop: number = 0; - private _lastHadScrollBar: boolean = false; - private _activeBuffer: IBuffer; - private _renderDimensions: IRenderDimensions; - - // Stores a partial line amount when scrolling, this is used to keep track of how much of a line - // is scrolled so we can "scroll" over partial lines and feel natural on touchpads. This is a - // quick fix and could have a more robust solution in place that reset the value when needed. - private _wheelPartialScroll: number = 0; - - private _refreshAnimationFrame: number | null = null; - private _ignoreNextScrollEvent: boolean = false; - - constructor( - private readonly _scrollLines: (amount: number) => void, - private readonly _viewportElement: HTMLElement, - private readonly _scrollArea: HTMLElement, - private readonly _element: HTMLElement, - @IBufferService private readonly _bufferService: IBufferService, - @IOptionsService private readonly _optionsService: IOptionsService, - @ICharSizeService private readonly _charSizeService: ICharSizeService, - @IRenderService private readonly _renderService: IRenderService - ) { - super(); - - // Measure the width of the scrollbar. If it is 0 we can assume it's an OSX overlay scrollbar. - // Unfortunately the overlay scrollbar would be hidden underneath the screen element in that case, - // therefore we account for a standard amount to make it visible - this.scrollBarWidth = (this._viewportElement.offsetWidth - this._scrollArea.offsetWidth) || FALLBACK_SCROLL_BAR_WIDTH; - this._lastHadScrollBar = true; - this.register(addDisposableDomListener(this._viewportElement, 'scroll', this._onScroll.bind(this))); - - // Track properties used in performance critical code manually to avoid using slow getters - this._activeBuffer = this._bufferService.buffer; - this.register(this._bufferService.buffers.onBufferActivate(e => this._activeBuffer = e.activeBuffer)); - this._renderDimensions = this._renderService.dimensions; - this.register(this._renderService.onDimensionsChange(e => this._renderDimensions = e)); - - // Perform this async to ensure the ICharSizeService is ready. - setTimeout(() => this.syncScrollArea(), 0); - } - - public onThemeChange(colors: IColorSet): void { - this._viewportElement.style.backgroundColor = colors.background.css; - } - - /** - * Refreshes row height, setting line-height, viewport height and scroll area height if - * necessary. - */ - private _refresh(immediate: boolean): void { - if (immediate) { - this._innerRefresh(); - if (this._refreshAnimationFrame !== null) { - cancelAnimationFrame(this._refreshAnimationFrame); - } - return; - } - if (this._refreshAnimationFrame === null) { - this._refreshAnimationFrame = requestAnimationFrame(() => this._innerRefresh()); - } - } - - private _innerRefresh(): void { - if (this._charSizeService.height > 0) { - this._currentRowHeight = this._renderService.dimensions.scaledCellHeight / window.devicePixelRatio; - this._currentScaledCellHeight = this._renderService.dimensions.scaledCellHeight; - this._lastRecordedViewportHeight = this._viewportElement.offsetHeight; - const newBufferHeight = Math.round(this._currentRowHeight * this._lastRecordedBufferLength) + (this._lastRecordedViewportHeight - this._renderService.dimensions.canvasHeight); - if (this._lastRecordedBufferHeight !== newBufferHeight) { - this._lastRecordedBufferHeight = newBufferHeight; - this._scrollArea.style.height = this._lastRecordedBufferHeight + 'px'; - } - } - - // Sync scrollTop - const scrollTop = this._bufferService.buffer.ydisp * this._currentRowHeight; - if (this._viewportElement.scrollTop !== scrollTop) { - // Ignore the next scroll event which will be triggered by setting the scrollTop as we do not - // want this event to scroll the terminal - this._ignoreNextScrollEvent = true; - this._viewportElement.scrollTop = scrollTop; - } - - // Update scroll bar width - if (this._optionsService.rawOptions.scrollback === 0) { - this.scrollBarWidth = 0; - } else { - this.scrollBarWidth = (this._viewportElement.offsetWidth - this._scrollArea.offsetWidth) || FALLBACK_SCROLL_BAR_WIDTH; - } - this._lastHadScrollBar = this.scrollBarWidth > 0; - - const elementStyle = window.getComputedStyle(this._element); - const elementPadding = parseInt(elementStyle.paddingLeft) + parseInt(elementStyle.paddingRight); - this._viewportElement.style.width = (this._renderService.dimensions.actualCellWidth * (this._bufferService.cols) + this.scrollBarWidth + (this._lastHadScrollBar ? elementPadding : 0)).toString() + 'px'; - this._refreshAnimationFrame = null; - } - - /** - * Updates dimensions and synchronizes the scroll area if necessary. - */ - public syncScrollArea(immediate: boolean = false): void { - // If buffer height changed - if (this._lastRecordedBufferLength !== this._bufferService.buffer.lines.length) { - this._lastRecordedBufferLength = this._bufferService.buffer.lines.length; - this._refresh(immediate); - return; - } - - // If viewport height changed - if (this._lastRecordedViewportHeight !== this._renderService.dimensions.canvasHeight) { - this._refresh(immediate); - return; - } - - // If the buffer position doesn't match last scroll top - if (this._lastScrollTop !== this._activeBuffer.ydisp * this._currentRowHeight) { - this._refresh(immediate); - return; - } - - // If row height changed - if (this._renderDimensions.scaledCellHeight !== this._currentScaledCellHeight) { - this._refresh(immediate); - return; - } - - // If the scroll bar visibility changed - if (this._lastHadScrollBar !== (this._optionsService.rawOptions.scrollback > 0)) { - this._refresh(immediate); - } - } - - /** - * Handles scroll events on the viewport, calculating the new viewport and requesting the - * terminal to scroll to it. - * @param ev The scroll event. - */ - private _onScroll(ev: Event): void { - // Record current scroll top position - this._lastScrollTop = this._viewportElement.scrollTop; - - // Don't attempt to scroll if the element is not visible, otherwise scrollTop will be corrupt - // which causes the terminal to scroll the buffer to the top - if (!this._viewportElement.offsetParent) { - return; - } - - // Ignore the event if it was flagged to ignore (when the source of the event is from Viewport) - if (this._ignoreNextScrollEvent) { - this._ignoreNextScrollEvent = false; - // Still trigger the scroll so lines get refreshed - this._scrollLines(0); - return; - } - - const newRow = Math.round(this._lastScrollTop / this._currentRowHeight); - const diff = newRow - this._bufferService.buffer.ydisp; - this._scrollLines(diff); - } - - /** - * Handles bubbling of scroll event in case the viewport has reached top or bottom - * @param ev The scroll event. - * @param amount The amount scrolled - */ - private _bubbleScroll(ev: Event, amount: number): boolean { - const scrollPosFromTop = this._viewportElement.scrollTop + this._lastRecordedViewportHeight; - if ((amount < 0 && this._viewportElement.scrollTop !== 0) || - (amount > 0 && scrollPosFromTop < this._lastRecordedBufferHeight)) { - if (ev.cancelable) { - ev.preventDefault(); - } - return false; - } - return true; - } - - /** - * Handles mouse wheel events by adjusting the viewport's scrollTop and delegating the actual - * scrolling to `onScroll`, this event needs to be attached manually by the consumer of - * `Viewport`. - * @param ev The mouse wheel event. - */ - public onWheel(ev: WheelEvent): boolean { - const amount = this._getPixelsScrolled(ev); - if (amount === 0) { - return false; - } - this._viewportElement.scrollTop += amount; - return this._bubbleScroll(ev, amount); - } - - private _getPixelsScrolled(ev: WheelEvent): number { - // Do nothing if it's not a vertical scroll event - if (ev.deltaY === 0 || ev.shiftKey) { - return 0; - } - - // Fallback to WheelEvent.DOM_DELTA_PIXEL - let amount = this._applyScrollModifier(ev.deltaY, ev); - if (ev.deltaMode === WheelEvent.DOM_DELTA_LINE) { - amount *= this._currentRowHeight; - } else if (ev.deltaMode === WheelEvent.DOM_DELTA_PAGE) { - amount *= this._currentRowHeight * this._bufferService.rows; - } - return amount; - } - - /** - * Gets the number of pixels scrolled by the mouse event taking into account what type of delta - * is being used. - * @param ev The mouse wheel event. - */ - public getLinesScrolled(ev: WheelEvent): number { - // Do nothing if it's not a vertical scroll event - if (ev.deltaY === 0 || ev.shiftKey) { - return 0; - } - - // Fallback to WheelEvent.DOM_DELTA_LINE - let amount = this._applyScrollModifier(ev.deltaY, ev); - if (ev.deltaMode === WheelEvent.DOM_DELTA_PIXEL) { - amount /= this._currentRowHeight + 0.0; // Prevent integer division - this._wheelPartialScroll += amount; - amount = Math.floor(Math.abs(this._wheelPartialScroll)) * (this._wheelPartialScroll > 0 ? 1 : -1); - this._wheelPartialScroll %= 1; - } else if (ev.deltaMode === WheelEvent.DOM_DELTA_PAGE) { - amount *= this._bufferService.rows; - } - return amount; - } - - private _applyScrollModifier(amount: number, ev: WheelEvent): number { - const modifier = this._optionsService.rawOptions.fastScrollModifier; - // Multiply the scroll speed when the modifier is down - if ((modifier === 'alt' && ev.altKey) || - (modifier === 'ctrl' && ev.ctrlKey) || - (modifier === 'shift' && ev.shiftKey)) { - return amount * this._optionsService.rawOptions.fastScrollSensitivity * this._optionsService.rawOptions.scrollSensitivity; - } - - return amount * this._optionsService.rawOptions.scrollSensitivity; - } - - /** - * Handles the touchstart event, recording the touch occurred. - * @param ev The touch event. - */ - public onTouchStart(ev: TouchEvent): void { - this._lastTouchY = ev.touches[0].pageY; - } - - /** - * Handles the touchmove event, scrolling the viewport if the position shifted. - * @param ev The touch event. - */ - public onTouchMove(ev: TouchEvent): boolean { - const deltaY = this._lastTouchY - ev.touches[0].pageY; - this._lastTouchY = ev.touches[0].pageY; - if (deltaY === 0) { - return false; - } - this._viewportElement.scrollTop += deltaY; - return this._bubbleScroll(ev, deltaY); - } -} diff --git a/node_modules/xterm/src/browser/input/CompositionHelper.ts b/node_modules/xterm/src/browser/input/CompositionHelper.ts deleted file mode 100644 index 61051b5..0000000 --- a/node_modules/xterm/src/browser/input/CompositionHelper.ts +++ /dev/null @@ -1,237 +0,0 @@ -/** - * Copyright (c) 2016 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IRenderService } from 'browser/services/Services'; -import { IBufferService, ICoreService, IOptionsService } from 'common/services/Services'; - -interface IPosition { - start: number; - end: number; -} - -/** - * Encapsulates the logic for handling compositionstart, compositionupdate and compositionend - * events, displaying the in-progress composition to the UI and forwarding the final composition - * to the handler. - */ -export class CompositionHelper { - /** - * Whether input composition is currently happening, eg. via a mobile keyboard, speech input or - * IME. This variable determines whether the compositionText should be displayed on the UI. - */ - private _isComposing: boolean; - public get isComposing(): boolean { return this._isComposing; } - - /** - * The position within the input textarea's value of the current composition. - */ - private _compositionPosition: IPosition; - - /** - * Whether a composition is in the process of being sent, setting this to false will cancel any - * in-progress composition. - */ - private _isSendingComposition: boolean; - - /** - * Data already sent due to keydown event. - */ - private _dataAlreadySent: string; - - constructor( - private readonly _textarea: HTMLTextAreaElement, - private readonly _compositionView: HTMLElement, - @IBufferService private readonly _bufferService: IBufferService, - @IOptionsService private readonly _optionsService: IOptionsService, - @ICoreService private readonly _coreService: ICoreService, - @IRenderService private readonly _renderService: IRenderService - ) { - this._isComposing = false; - this._isSendingComposition = false; - this._compositionPosition = { start: 0, end: 0 }; - this._dataAlreadySent = ''; - } - - /** - * Handles the compositionstart event, activating the composition view. - */ - public compositionstart(): void { - this._isComposing = true; - this._compositionPosition.start = this._textarea.value.length; - this._compositionView.textContent = ''; - this._dataAlreadySent = ''; - this._compositionView.classList.add('active'); - } - - /** - * Handles the compositionupdate event, updating the composition view. - * @param ev The event. - */ - public compositionupdate(ev: Pick<CompositionEvent, 'data'>): void { - this._compositionView.textContent = ev.data; - this.updateCompositionElements(); - setTimeout(() => { - this._compositionPosition.end = this._textarea.value.length; - }, 0); - } - - /** - * Handles the compositionend event, hiding the composition view and sending the composition to - * the handler. - */ - public compositionend(): void { - this._finalizeComposition(true); - } - - /** - * Handles the keydown event, routing any necessary events to the CompositionHelper functions. - * @param ev The keydown event. - * @return Whether the Terminal should continue processing the keydown event. - */ - public keydown(ev: KeyboardEvent): boolean { - if (this._isComposing || this._isSendingComposition) { - if (ev.keyCode === 229) { - // Continue composing if the keyCode is the "composition character" - return false; - } - if (ev.keyCode === 16 || ev.keyCode === 17 || ev.keyCode === 18) { - // Continue composing if the keyCode is a modifier key - return false; - } - // Finish composition immediately. This is mainly here for the case where enter is - // pressed and the handler needs to be triggered before the command is executed. - this._finalizeComposition(false); - } - - if (ev.keyCode === 229) { - // If the "composition character" is used but gets to this point it means a non-composition - // character (eg. numbers and punctuation) was pressed when the IME was active. - this._handleAnyTextareaChanges(); - return false; - } - - return true; - } - - /** - * Finalizes the composition, resuming regular input actions. This is called when a composition - * is ending. - * @param waitForPropagation Whether to wait for events to propagate before sending - * the input. This should be false if a non-composition keystroke is entered before the - * compositionend event is triggered, such as enter, so that the composition is sent before - * the command is executed. - */ - private _finalizeComposition(waitForPropagation: boolean): void { - this._compositionView.classList.remove('active'); - this._isComposing = false; - - if (!waitForPropagation) { - // Cancel any delayed composition send requests and send the input immediately. - this._isSendingComposition = false; - const input = this._textarea.value.substring(this._compositionPosition.start, this._compositionPosition.end); - this._coreService.triggerDataEvent(input, true); - } else { - // Make a deep copy of the composition position here as a new compositionstart event may - // fire before the setTimeout executes. - const currentCompositionPosition = { - start: this._compositionPosition.start, - end: this._compositionPosition.end - }; - - // Since composition* events happen before the changes take place in the textarea on most - // browsers, use a setTimeout with 0ms time to allow the native compositionend event to - // complete. This ensures the correct character is retrieved. - // This solution was used because: - // - The compositionend event's data property is unreliable, at least on Chromium - // - The last compositionupdate event's data property does not always accurately describe - // the character, a counter example being Korean where an ending consonsant can move to - // the following character if the following input is a vowel. - this._isSendingComposition = true; - setTimeout(() => { - // Ensure that the input has not already been sent - if (this._isSendingComposition) { - this._isSendingComposition = false; - let input; - // Add length of data already sent due to keydown event, - // otherwise input characters can be duplicated. (Issue #3191) - currentCompositionPosition.start += this._dataAlreadySent.length; - if (this._isComposing) { - // Use the end position to get the string if a new composition has started. - input = this._textarea.value.substring(currentCompositionPosition.start, currentCompositionPosition.end); - } else { - // Don't use the end position here in order to pick up any characters after the - // composition has finished, for example when typing a non-composition character - // (eg. 2) after a composition character. - input = this._textarea.value.substring(currentCompositionPosition.start); - } - if (input.length > 0) { - this._coreService.triggerDataEvent(input, true); - } - } - }, 0); - } - } - - /** - * Apply any changes made to the textarea after the current event chain is allowed to complete. - * This should be called when not currently composing but a keydown event with the "composition - * character" (229) is triggered, in order to allow non-composition text to be entered when an - * IME is active. - */ - private _handleAnyTextareaChanges(): void { - const oldValue = this._textarea.value; - setTimeout(() => { - // Ignore if a composition has started since the timeout - if (!this._isComposing) { - const newValue = this._textarea.value; - const diff = newValue.replace(oldValue, ''); - if (diff.length > 0) { - this._dataAlreadySent = diff; - this._coreService.triggerDataEvent(diff, true); - } - } - }, 0); - } - - /** - * Positions the composition view on top of the cursor and the textarea just below it (so the - * IME helper dialog is positioned correctly). - * @param dontRecurse Whether to use setTimeout to recursively trigger another update, this is - * necessary as the IME events across browsers are not consistently triggered. - */ - public updateCompositionElements(dontRecurse?: boolean): void { - if (!this._isComposing) { - return; - } - - if (this._bufferService.buffer.isCursorInViewport) { - const cursorX = Math.min(this._bufferService.buffer.x, this._bufferService.cols - 1); - - const cellHeight = this._renderService.dimensions.actualCellHeight; - const cursorTop = this._bufferService.buffer.y * this._renderService.dimensions.actualCellHeight; - const cursorLeft = cursorX * this._renderService.dimensions.actualCellWidth; - - this._compositionView.style.left = cursorLeft + 'px'; - this._compositionView.style.top = cursorTop + 'px'; - this._compositionView.style.height = cellHeight + 'px'; - this._compositionView.style.lineHeight = cellHeight + 'px'; - this._compositionView.style.fontFamily = this._optionsService.rawOptions.fontFamily; - this._compositionView.style.fontSize = this._optionsService.rawOptions.fontSize + 'px'; - // Sync the textarea to the exact position of the composition view so the IME knows where the - // text is. - const compositionViewBounds = this._compositionView.getBoundingClientRect(); - this._textarea.style.left = cursorLeft + 'px'; - this._textarea.style.top = cursorTop + 'px'; - // Ensure the text area is at least 1x1, otherwise certain IMEs may break - this._textarea.style.width = Math.max(compositionViewBounds.width, 1) + 'px'; - this._textarea.style.height = Math.max(compositionViewBounds.height, 1) + 'px'; - this._textarea.style.lineHeight = compositionViewBounds.height + 'px'; - } - - if (!dontRecurse) { - setTimeout(() => this.updateCompositionElements(true), 0); - } - } -} diff --git a/node_modules/xterm/src/browser/input/Mouse.ts b/node_modules/xterm/src/browser/input/Mouse.ts deleted file mode 100644 index 2986fb3..0000000 --- a/node_modules/xterm/src/browser/input/Mouse.ts +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -export function getCoordsRelativeToElement(event: {clientX: number, clientY: number}, element: HTMLElement): [number, number] { - const rect = element.getBoundingClientRect(); - return [event.clientX - rect.left, event.clientY - rect.top]; -} - -/** - * Gets coordinates within the terminal for a particular mouse event. The result - * is returned as an array in the form [x, y] instead of an object as it's a - * little faster and this function is used in some low level code. - * @param event The mouse event. - * @param element The terminal's container element. - * @param colCount The number of columns in the terminal. - * @param rowCount The number of rows n the terminal. - * @param isSelection Whether the request is for the selection or not. This will - * apply an offset to the x value such that the left half of the cell will - * select that cell and the right half will select the next cell. - */ -export function getCoords(event: {clientX: number, clientY: number}, element: HTMLElement, colCount: number, rowCount: number, hasValidCharSize: boolean, actualCellWidth: number, actualCellHeight: number, isSelection?: boolean): [number, number] | undefined { - // Coordinates cannot be measured if there are no valid - if (!hasValidCharSize) { - return undefined; - } - - const coords = getCoordsRelativeToElement(event, element); - if (!coords) { - return undefined; - } - - coords[0] = Math.ceil((coords[0] + (isSelection ? actualCellWidth / 2 : 0)) / actualCellWidth); - coords[1] = Math.ceil(coords[1] / actualCellHeight); - - // Ensure coordinates are within the terminal viewport. Note that selections - // need an addition point of precision to cover the end point (as characters - // cover half of one char and half of the next). - coords[0] = Math.min(Math.max(coords[0], 1), colCount + (isSelection ? 1 : 0)); - coords[1] = Math.min(Math.max(coords[1], 1), rowCount); - - return coords; -} - -/** - * Gets coordinates within the terminal for a particular mouse event, wrapping - * them to the bounds of the terminal and adding 32 to both the x and y values - * as expected by xterm. - */ -export function getRawByteCoords(coords: [number, number] | undefined): { x: number, y: number } | undefined { - if (!coords) { - return undefined; - } - - // xterm sends raw bytes and starts at 32 (SP) for each. - return { x: coords[0] + 32, y: coords[1] + 32 }; -} diff --git a/node_modules/xterm/src/browser/input/MoveToCell.ts b/node_modules/xterm/src/browser/input/MoveToCell.ts deleted file mode 100644 index 82e767c..0000000 --- a/node_modules/xterm/src/browser/input/MoveToCell.ts +++ /dev/null @@ -1,249 +0,0 @@ -/** - * Copyright (c) 2018 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { C0 } from 'common/data/EscapeSequences'; -import { IBufferService } from 'common/services/Services'; - -const enum Direction { - UP = 'A', - DOWN = 'B', - RIGHT = 'C', - LEFT = 'D' -} - -/** - * Concatenates all the arrow sequences together. - * Resets the starting row to an unwrapped row, moves to the requested row, - * then moves to requested col. - */ -export function moveToCellSequence(targetX: number, targetY: number, bufferService: IBufferService, applicationCursor: boolean): string { - const startX = bufferService.buffer.x; - const startY = bufferService.buffer.y; - - // The alt buffer should try to navigate between rows - if (!bufferService.buffer.hasScrollback) { - return resetStartingRow(startX, startY, targetX, targetY, bufferService, applicationCursor) + - moveToRequestedRow(startY, targetY, bufferService, applicationCursor) + - moveToRequestedCol(startX, startY, targetX, targetY, bufferService, applicationCursor); - } - - // Only move horizontally for the normal buffer - let direction; - if (startY === targetY) { - direction = startX > targetX ? Direction.LEFT : Direction.RIGHT; - return repeat(Math.abs(startX - targetX), sequence(direction, applicationCursor)); - } - direction = startY > targetY ? Direction.LEFT : Direction.RIGHT; - const rowDifference = Math.abs(startY - targetY); - const cellsToMove = colsFromRowEnd(startY > targetY ? targetX : startX, bufferService) + - (rowDifference - 1) * bufferService.cols + 1 /* wrap around 1 row */ + - colsFromRowBeginning(startY > targetY ? startX : targetX, bufferService); - return repeat(cellsToMove, sequence(direction, applicationCursor)); -} - -/** - * Find the number of cols from a row beginning to a col. - */ -function colsFromRowBeginning(currX: number, bufferService: IBufferService): number { - return currX - 1; -} - -/** - * Find the number of cols from a col to row end. - */ -function colsFromRowEnd(currX: number, bufferService: IBufferService): number { - return bufferService.cols - currX; -} - -/** - * If the initial position of the cursor is on a row that is wrapped, move the - * cursor up to the first row that is not wrapped to have accurate vertical - * positioning. - */ -function resetStartingRow(startX: number, startY: number, targetX: number, targetY: number, bufferService: IBufferService, applicationCursor: boolean): string { - if (moveToRequestedRow(startY, targetY, bufferService, applicationCursor).length === 0) { - return ''; - } - return repeat(bufferLine( - startX, startY, startX, - startY - wrappedRowsForRow(bufferService, startY), false, bufferService - ).length, sequence(Direction.LEFT, applicationCursor)); -} - -/** - * Using the reset starting and ending row, move to the requested row, - * ignoring wrapped rows - */ -function moveToRequestedRow(startY: number, targetY: number, bufferService: IBufferService, applicationCursor: boolean): string { - const startRow = startY - wrappedRowsForRow(bufferService, startY); - const endRow = targetY - wrappedRowsForRow(bufferService, targetY); - - const rowsToMove = Math.abs(startRow - endRow) - wrappedRowsCount(startY, targetY, bufferService); - - return repeat(rowsToMove, sequence(verticalDirection(startY, targetY), applicationCursor)); -} - -/** - * Move to the requested col on the ending row - */ -function moveToRequestedCol(startX: number, startY: number, targetX: number, targetY: number, bufferService: IBufferService, applicationCursor: boolean): string { - let startRow; - if (moveToRequestedRow(startY, targetY, bufferService, applicationCursor).length > 0) { - startRow = targetY - wrappedRowsForRow(bufferService, targetY); - } else { - startRow = startY; - } - - const endRow = targetY; - const direction = horizontalDirection(startX, startY, targetX, targetY, bufferService, applicationCursor); - - return repeat(bufferLine( - startX, startRow, targetX, endRow, - direction === Direction.RIGHT, bufferService - ).length, sequence(direction, applicationCursor)); -} - -/** - * Utility functions - */ - -/** - * Calculates the number of wrapped rows between the unwrapped starting and - * ending rows. These rows need to ignored since the cursor skips over them. - */ -function wrappedRowsCount(startY: number, targetY: number, bufferService: IBufferService): number { - let wrappedRows = 0; - const startRow = startY - wrappedRowsForRow(bufferService, startY); - const endRow = targetY - wrappedRowsForRow(bufferService, targetY); - - for (let i = 0; i < Math.abs(startRow - endRow); i++) { - const direction = verticalDirection(startY, targetY) === Direction.UP ? -1 : 1; - const line = bufferService.buffer.lines.get(startRow + (direction * i)); - if (line?.isWrapped) { - wrappedRows++; - } - } - - return wrappedRows; -} - -/** - * Calculates the number of wrapped rows that make up a given row. - * @param currentRow The row to determine how many wrapped rows make it up - */ -function wrappedRowsForRow(bufferService: IBufferService, currentRow: number): number { - let rowCount = 0; - let line = bufferService.buffer.lines.get(currentRow); - let lineWraps = line?.isWrapped; - - while (lineWraps && currentRow >= 0 && currentRow < bufferService.rows) { - rowCount++; - line = bufferService.buffer.lines.get(--currentRow); - lineWraps = line?.isWrapped; - } - - return rowCount; -} - -/** - * Direction determiners - */ - -/** - * Determines if the right or left arrow is needed - */ -function horizontalDirection(startX: number, startY: number, targetX: number, targetY: number, bufferService: IBufferService, applicationCursor: boolean): Direction { - let startRow; - if (moveToRequestedRow(targetX, targetY, bufferService, applicationCursor).length > 0) { - startRow = targetY - wrappedRowsForRow(bufferService, targetY); - } else { - startRow = startY; - } - - if ((startX < targetX && - startRow <= targetY) || // down/right or same y/right - (startX >= targetX && - startRow < targetY)) { // down/left or same y/left - return Direction.RIGHT; - } - return Direction.LEFT; -} - -/** - * Determines if the up or down arrow is needed - */ -function verticalDirection(startY: number, targetY: number): Direction { - return startY > targetY ? Direction.UP : Direction.DOWN; -} - -/** - * Constructs the string of chars in the buffer from a starting row and col - * to an ending row and col - * @param startCol The starting column position - * @param startRow The starting row position - * @param endCol The ending column position - * @param endRow The ending row position - * @param forward Direction to move - */ -function bufferLine( - startCol: number, - startRow: number, - endCol: number, - endRow: number, - forward: boolean, - bufferService: IBufferService -): string { - let currentCol = startCol; - let currentRow = startRow; - let bufferStr = ''; - - while (currentCol !== endCol || currentRow !== endRow) { - currentCol += forward ? 1 : -1; - - if (forward && currentCol > bufferService.cols - 1) { - bufferStr += bufferService.buffer.translateBufferLineToString( - currentRow, false, startCol, currentCol - ); - currentCol = 0; - startCol = 0; - currentRow++; - } else if (!forward && currentCol < 0) { - bufferStr += bufferService.buffer.translateBufferLineToString( - currentRow, false, 0, startCol + 1 - ); - currentCol = bufferService.cols - 1; - startCol = currentCol; - currentRow--; - } - } - - return bufferStr + bufferService.buffer.translateBufferLineToString( - currentRow, false, startCol, currentCol - ); -} - -/** - * Constructs the escape sequence for clicking an arrow - * @param direction The direction to move - */ -function sequence(direction: Direction, applicationCursor: boolean): string { - const mod = applicationCursor ? 'O' : '['; - return C0.ESC + mod + direction; -} - -/** - * Returns a string repeated a given number of times - * Polyfill from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat - * @param count The number of times to repeat the string - * @param string The string that is to be repeated - */ -function repeat(count: number, str: string): string { - count = Math.floor(count); - let rpt = ''; - for (let i = 0; i < count; i++) { - rpt += str; - } - return rpt; -} diff --git a/node_modules/xterm/src/browser/public/Terminal.ts b/node_modules/xterm/src/browser/public/Terminal.ts deleted file mode 100644 index 1acde93..0000000 --- a/node_modules/xterm/src/browser/public/Terminal.ts +++ /dev/null @@ -1,297 +0,0 @@ -/** - * Copyright (c) 2018 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { Terminal as ITerminalApi, IMarker, IDisposable, ILinkMatcherOptions, ITheme, ILocalizableStrings, ITerminalAddon, ISelectionPosition, IBufferNamespace as IBufferNamespaceApi, IParser, ILinkProvider, IUnicodeHandling, FontWeight, IModes, IDecorationOptions, IDecoration } from 'xterm'; -import { ITerminal } from 'browser/Types'; -import { Terminal as TerminalCore } from 'browser/Terminal'; -import * as Strings from 'browser/LocalizableStrings'; -import { IEvent } from 'common/EventEmitter'; -import { ParserApi } from 'common/public/ParserApi'; -import { UnicodeApi } from 'common/public/UnicodeApi'; -import { AddonManager } from 'common/public/AddonManager'; -import { BufferNamespaceApi } from 'common/public/BufferNamespaceApi'; -import { ITerminalOptions } from 'common/Types'; - -/** - * The set of options that only have an effect when set in the Terminal constructor. - */ -const CONSTRUCTOR_ONLY_OPTIONS = ['cols', 'rows']; - -export class Terminal implements ITerminalApi { - private _core: ITerminal; - private _addonManager: AddonManager; - private _parser: IParser | undefined; - private _buffer: BufferNamespaceApi | undefined; - private _publicOptions: ITerminalOptions; - - constructor(options?: ITerminalOptions) { - this._core = new TerminalCore(options); - this._addonManager = new AddonManager(); - - this._publicOptions = { ... this._core.options }; - const getter = (propName: string): any => { - return this._core.options[propName]; - }; - const setter = (propName: string, value: any): void => { - this._checkReadonlyOptions(propName); - this._core.options[propName] = value; - }; - - for (const propName in this._core.options) { - const desc = { - get: getter.bind(this, propName), - set: setter.bind(this, propName) - }; - Object.defineProperty(this._publicOptions, propName, desc); - } - } - - private _checkReadonlyOptions(propName: string): void { - // Throw an error if any constructor only option is modified - // from terminal.options - // Modifications from anywhere else are allowed - if (CONSTRUCTOR_ONLY_OPTIONS.includes(propName)) { - throw new Error(`Option "${propName}" can only be set in the constructor`); - } - } - - private _checkProposedApi(): void { - if (!this._core.optionsService.rawOptions.allowProposedApi) { - throw new Error('You must set the allowProposedApi option to true to use proposed API'); - } - } - - public get onBell(): IEvent<void> { return this._core.onBell; } - public get onBinary(): IEvent<string> { return this._core.onBinary; } - public get onCursorMove(): IEvent<void> { return this._core.onCursorMove; } - public get onData(): IEvent<string> { return this._core.onData; } - public get onKey(): IEvent<{ key: string, domEvent: KeyboardEvent }> { return this._core.onKey; } - public get onLineFeed(): IEvent<void> { return this._core.onLineFeed; } - public get onRender(): IEvent<{ start: number, end: number }> { return this._core.onRender; } - public get onResize(): IEvent<{ cols: number, rows: number }> { return this._core.onResize; } - public get onScroll(): IEvent<number> { return this._core.onScroll; } - public get onSelectionChange(): IEvent<void> { return this._core.onSelectionChange; } - public get onTitleChange(): IEvent<string> { return this._core.onTitleChange; } - - public get element(): HTMLElement | undefined { return this._core.element; } - public get parser(): IParser { - this._checkProposedApi(); - if (!this._parser) { - this._parser = new ParserApi(this._core); - } - return this._parser; - } - public get unicode(): IUnicodeHandling { - this._checkProposedApi(); - return new UnicodeApi(this._core); - } - public get textarea(): HTMLTextAreaElement | undefined { return this._core.textarea; } - public get rows(): number { return this._core.rows; } - public get cols(): number { return this._core.cols; } - public get buffer(): IBufferNamespaceApi { - this._checkProposedApi(); - if (!this._buffer) { - this._buffer = new BufferNamespaceApi(this._core); - } - return this._buffer; - } - public get markers(): ReadonlyArray<IMarker> { - this._checkProposedApi(); - return this._core.markers; - } - public get modes(): IModes { - const m = this._core.coreService.decPrivateModes; - let mouseTrackingMode: 'none' | 'x10' | 'vt200' | 'drag' | 'any' = 'none'; - switch (this._core.coreMouseService.activeProtocol) { - case 'X10': mouseTrackingMode = 'x10'; break; - case 'VT200': mouseTrackingMode = 'vt200'; break; - case 'DRAG': mouseTrackingMode = 'drag'; break; - case 'ANY': mouseTrackingMode = 'any'; break; - } - return { - applicationCursorKeysMode: m.applicationCursorKeys, - applicationKeypadMode: m.applicationKeypad, - bracketedPasteMode: m.bracketedPasteMode, - insertMode: this._core.coreService.modes.insertMode, - mouseTrackingMode: mouseTrackingMode, - originMode: m.origin, - reverseWraparoundMode: m.reverseWraparound, - sendFocusMode: m.sendFocus, - wraparoundMode: m.wraparound - }; - } - public get options(): ITerminalOptions { - return this._publicOptions; - } - public set options(options: ITerminalOptions) { - for (const propName in options) { - this._publicOptions[propName] = options[propName]; - } - } - public blur(): void { - this._core.blur(); - } - public focus(): void { - this._core.focus(); - } - public resize(columns: number, rows: number): void { - this._verifyIntegers(columns, rows); - this._core.resize(columns, rows); - } - public open(parent: HTMLElement): void { - this._core.open(parent); - } - public attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void { - this._core.attachCustomKeyEventHandler(customKeyEventHandler); - } - public registerLinkMatcher(regex: RegExp, handler: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions): number { - this._checkProposedApi(); - return this._core.registerLinkMatcher(regex, handler, options); - } - public deregisterLinkMatcher(matcherId: number): void { - this._checkProposedApi(); - this._core.deregisterLinkMatcher(matcherId); - } - public registerLinkProvider(linkProvider: ILinkProvider): IDisposable { - this._checkProposedApi(); - return this._core.registerLinkProvider(linkProvider); - } - public registerCharacterJoiner(handler: (text: string) => [number, number][]): number { - this._checkProposedApi(); - return this._core.registerCharacterJoiner(handler); - } - public deregisterCharacterJoiner(joinerId: number): void { - this._checkProposedApi(); - this._core.deregisterCharacterJoiner(joinerId); - } - public registerMarker(cursorYOffset: number = 0): IMarker | undefined { - this._checkProposedApi(); - this._verifyIntegers(cursorYOffset); - return this._core.addMarker(cursorYOffset); - } - public registerDecoration(decorationOptions: IDecorationOptions): IDecoration | undefined { - this._checkProposedApi(); - this._verifyPositiveIntegers(decorationOptions.x ?? 0, decorationOptions.width ?? 0, decorationOptions.height ?? 0); - return this._core.registerDecoration(decorationOptions); - } - public addMarker(cursorYOffset: number): IMarker | undefined { - return this.registerMarker(cursorYOffset); - } - public hasSelection(): boolean { - return this._core.hasSelection(); - } - public select(column: number, row: number, length: number): void { - this._verifyIntegers(column, row, length); - this._core.select(column, row, length); - } - public getSelection(): string { - return this._core.getSelection(); - } - public getSelectionPosition(): ISelectionPosition | undefined { - return this._core.getSelectionPosition(); - } - public clearSelection(): void { - this._core.clearSelection(); - } - public selectAll(): void { - this._core.selectAll(); - } - public selectLines(start: number, end: number): void { - this._verifyIntegers(start, end); - this._core.selectLines(start, end); - } - public dispose(): void { - this._addonManager.dispose(); - this._core.dispose(); - } - public scrollLines(amount: number): void { - this._verifyIntegers(amount); - this._core.scrollLines(amount); - } - public scrollPages(pageCount: number): void { - this._verifyIntegers(pageCount); - this._core.scrollPages(pageCount); - } - public scrollToTop(): void { - this._core.scrollToTop(); - } - public scrollToBottom(): void { - this._core.scrollToBottom(); - } - public scrollToLine(line: number): void { - this._verifyIntegers(line); - this._core.scrollToLine(line); - } - public clear(): void { - this._core.clear(); - } - public write(data: string | Uint8Array, callback?: () => void): void { - this._core.write(data, callback); - } - public writeUtf8(data: Uint8Array, callback?: () => void): void { - this._core.write(data, callback); - } - public writeln(data: string | Uint8Array, callback?: () => void): void { - this._core.write(data); - this._core.write('\r\n', callback); - } - public paste(data: string): void { - this._core.paste(data); - } - public getOption(key: 'bellSound' | 'bellStyle' | 'cursorStyle' | 'fontFamily' | 'logLevel' | 'rendererType' | 'termName' | 'wordSeparator'): string; - public getOption(key: 'allowTransparency' | 'altClickMovesCursor' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'disableStdin' | 'macOptionIsMeta' | 'rightClickSelectsWord' | 'popOnBell' | 'visualBell'): boolean; - public getOption(key: 'cols' | 'fontSize' | 'letterSpacing' | 'lineHeight' | 'rows' | 'tabStopWidth' | 'scrollback'): number; - public getOption(key: 'fontWeight' | 'fontWeightBold'): FontWeight; - public getOption(key: string): any; - public getOption(key: any): any { - return this._core.optionsService.getOption(key); - } - public setOption(key: 'bellSound' | 'fontFamily' | 'termName' | 'wordSeparator', value: string): void; - public setOption(key: 'fontWeight' | 'fontWeightBold', value: 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' | number): void; - public setOption(key: 'logLevel', value: 'debug' | 'info' | 'warn' | 'error' | 'off'): void; - public setOption(key: 'bellStyle', value: 'none' | 'visual' | 'sound' | 'both'): void; - public setOption(key: 'cursorStyle', value: 'block' | 'underline' | 'bar'): void; - public setOption(key: 'allowTransparency' | 'altClickMovesCursor' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'disableStdin' | 'macOptionIsMeta' | 'rightClickSelectsWord' | 'popOnBell' | 'visualBell', value: boolean): void; - public setOption(key: 'fontSize' | 'letterSpacing' | 'lineHeight' | 'tabStopWidth' | 'scrollback', value: number): void; - public setOption(key: 'theme', value: ITheme): void; - public setOption(key: 'cols' | 'rows', value: number): void; - public setOption(key: string, value: any): void; - public setOption(key: any, value: any): void { - this._checkReadonlyOptions(key); - this._core.optionsService.setOption(key, value); - } - public refresh(start: number, end: number): void { - this._verifyIntegers(start, end); - this._core.refresh(start, end); - } - public reset(): void { - this._core.reset(); - } - public clearTextureAtlas(): void { - this._core.clearTextureAtlas(); - } - public loadAddon(addon: ITerminalAddon): void { - return this._addonManager.loadAddon(this, addon); - } - public static get strings(): ILocalizableStrings { - return Strings; - } - - private _verifyIntegers(...values: number[]): void { - for (const value of values) { - if (value === Infinity || isNaN(value) || value % 1 !== 0) { - throw new Error('This API only accepts integers'); - } - } - } - - private _verifyPositiveIntegers(...values: number[]): void { - for (const value of values) { - if (value && (value === Infinity || isNaN(value) || value % 1 !== 0 || value < 0)) { - throw new Error('This API only accepts positive integers'); - } - } - } -} diff --git a/node_modules/xterm/src/browser/renderer/BaseRenderLayer.ts b/node_modules/xterm/src/browser/renderer/BaseRenderLayer.ts deleted file mode 100644 index 629e943..0000000 --- a/node_modules/xterm/src/browser/renderer/BaseRenderLayer.ts +++ /dev/null @@ -1,513 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IRenderDimensions, IRenderLayer } from 'browser/renderer/Types'; -import { ICellData } from 'common/Types'; -import { DEFAULT_COLOR, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_CODE, Attributes } from 'common/buffer/Constants'; -import { IGlyphIdentifier } from 'browser/renderer/atlas/Types'; -import { DIM_OPACITY, INVERTED_DEFAULT_COLOR, TEXT_BASELINE } from 'browser/renderer/atlas/Constants'; -import { BaseCharAtlas } from 'browser/renderer/atlas/BaseCharAtlas'; -import { acquireCharAtlas } from 'browser/renderer/atlas/CharAtlasCache'; -import { AttributeData } from 'common/buffer/AttributeData'; -import { IColorSet, IColor } from 'browser/Types'; -import { CellData } from 'common/buffer/CellData'; -import { IBufferService, IOptionsService } from 'common/services/Services'; -import { throwIfFalsy } from 'browser/renderer/RendererUtils'; -import { channels, color, rgba } from 'browser/Color'; -import { removeElementFromParent } from 'browser/Dom'; -import { tryDrawCustomChar } from 'browser/renderer/CustomGlyphs'; - -export abstract class BaseRenderLayer implements IRenderLayer { - private _canvas: HTMLCanvasElement; - protected _ctx!: CanvasRenderingContext2D; - private _scaledCharWidth: number = 0; - private _scaledCharHeight: number = 0; - private _scaledCellWidth: number = 0; - private _scaledCellHeight: number = 0; - private _scaledCharLeft: number = 0; - private _scaledCharTop: number = 0; - - protected _charAtlas: BaseCharAtlas | undefined; - - /** - * An object that's reused when drawing glyphs in order to reduce GC. - */ - private _currentGlyphIdentifier: IGlyphIdentifier = { - chars: '', - code: 0, - bg: 0, - fg: 0, - bold: false, - dim: false, - italic: false - }; - - constructor( - private _container: HTMLElement, - id: string, - zIndex: number, - private _alpha: boolean, - protected _colors: IColorSet, - private _rendererId: number, - protected readonly _bufferService: IBufferService, - protected readonly _optionsService: IOptionsService - ) { - this._canvas = document.createElement('canvas'); - this._canvas.classList.add(`xterm-${id}-layer`); - this._canvas.style.zIndex = zIndex.toString(); - this._initCanvas(); - this._container.appendChild(this._canvas); - } - - public dispose(): void { - removeElementFromParent(this._canvas); - this._charAtlas?.dispose(); - } - - private _initCanvas(): void { - this._ctx = throwIfFalsy(this._canvas.getContext('2d', { alpha: this._alpha })); - // Draw the background if this is an opaque layer - if (!this._alpha) { - this._clearAll(); - } - } - - public onOptionsChanged(): void {} - public onBlur(): void {} - public onFocus(): void {} - public onCursorMove(): void {} - public onGridChanged(startRow: number, endRow: number): void {} - public onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean = false): void {} - - public setColors(colorSet: IColorSet): void { - this._refreshCharAtlas(colorSet); - } - - protected _setTransparency(alpha: boolean): void { - // Do nothing when alpha doesn't change - if (alpha === this._alpha) { - return; - } - - // Create new canvas and replace old one - const oldCanvas = this._canvas; - this._alpha = alpha; - // Cloning preserves properties - this._canvas = this._canvas.cloneNode() as HTMLCanvasElement; - this._initCanvas(); - this._container.replaceChild(this._canvas, oldCanvas); - - // Regenerate char atlas and force a full redraw - this._refreshCharAtlas(this._colors); - this.onGridChanged(0, this._bufferService.rows - 1); - } - - /** - * Refreshes the char atlas, aquiring a new one if necessary. - * @param colorSet The color set to use for the char atlas. - */ - private _refreshCharAtlas(colorSet: IColorSet): void { - if (this._scaledCharWidth <= 0 && this._scaledCharHeight <= 0) { - return; - } - this._charAtlas = acquireCharAtlas(this._optionsService.rawOptions, this._rendererId, colorSet, this._scaledCharWidth, this._scaledCharHeight); - this._charAtlas.warmUp(); - } - - public resize(dim: IRenderDimensions): void { - this._scaledCellWidth = dim.scaledCellWidth; - this._scaledCellHeight = dim.scaledCellHeight; - this._scaledCharWidth = dim.scaledCharWidth; - this._scaledCharHeight = dim.scaledCharHeight; - this._scaledCharLeft = dim.scaledCharLeft; - this._scaledCharTop = dim.scaledCharTop; - this._canvas.width = dim.scaledCanvasWidth; - this._canvas.height = dim.scaledCanvasHeight; - this._canvas.style.width = `${dim.canvasWidth}px`; - this._canvas.style.height = `${dim.canvasHeight}px`; - - // Draw the background if this is an opaque layer - if (!this._alpha) { - this._clearAll(); - } - - this._refreshCharAtlas(this._colors); - } - - public abstract reset(): void; - - public clearTextureAtlas(): void { - this._charAtlas?.clear(); - } - - /** - * Fills 1+ cells completely. This uses the existing fillStyle on the context. - * @param x The column to start at. - * @param y The row to start at - * @param width The number of columns to fill. - * @param height The number of rows to fill. - */ - protected _fillCells(x: number, y: number, width: number, height: number): void { - this._ctx.fillRect( - x * this._scaledCellWidth, - y * this._scaledCellHeight, - width * this._scaledCellWidth, - height * this._scaledCellHeight); - } - - /** - * Fills a 1px line (2px on HDPI) at the middle of the cell. This uses the - * existing fillStyle on the context. - * @param x The column to fill. - * @param y The row to fill. - */ - protected _fillMiddleLineAtCells(x: number, y: number, width: number = 1): void { - const cellOffset = Math.ceil(this._scaledCellHeight * 0.5); - this._ctx.fillRect( - x * this._scaledCellWidth, - (y + 1) * this._scaledCellHeight - cellOffset - window.devicePixelRatio, - width * this._scaledCellWidth, - window.devicePixelRatio); - } - - /** - * Fills a 1px line (2px on HDPI) at the bottom of the cell. This uses the - * existing fillStyle on the context. - * @param x The column to fill. - * @param y The row to fill. - */ - protected _fillBottomLineAtCells(x: number, y: number, width: number = 1): void { - this._ctx.fillRect( - x * this._scaledCellWidth, - (y + 1) * this._scaledCellHeight - window.devicePixelRatio - 1 /* Ensure it's drawn within the cell */, - width * this._scaledCellWidth, - window.devicePixelRatio); - } - - /** - * Fills a 1px line (2px on HDPI) at the left of the cell. This uses the - * existing fillStyle on the context. - * @param x The column to fill. - * @param y The row to fill. - */ - protected _fillLeftLineAtCell(x: number, y: number, width: number): void { - this._ctx.fillRect( - x * this._scaledCellWidth, - y * this._scaledCellHeight, - window.devicePixelRatio * width, - this._scaledCellHeight); - } - - /** - * Strokes a 1px rectangle (2px on HDPI) around a cell. This uses the existing - * strokeStyle on the context. - * @param x The column to fill. - * @param y The row to fill. - */ - protected _strokeRectAtCell(x: number, y: number, width: number, height: number): void { - this._ctx.lineWidth = window.devicePixelRatio; - this._ctx.strokeRect( - x * this._scaledCellWidth + window.devicePixelRatio / 2, - y * this._scaledCellHeight + (window.devicePixelRatio / 2), - width * this._scaledCellWidth - window.devicePixelRatio, - (height * this._scaledCellHeight) - window.devicePixelRatio); - } - - /** - * Clears the entire canvas. - */ - protected _clearAll(): void { - if (this._alpha) { - this._ctx.clearRect(0, 0, this._canvas.width, this._canvas.height); - } else { - this._ctx.fillStyle = this._colors.background.css; - this._ctx.fillRect(0, 0, this._canvas.width, this._canvas.height); - } - } - - /** - * Clears 1+ cells completely. - * @param x The column to start at. - * @param y The row to start at. - * @param width The number of columns to clear. - * @param height The number of rows to clear. - */ - protected _clearCells(x: number, y: number, width: number, height: number): void { - if (this._alpha) { - this._ctx.clearRect( - x * this._scaledCellWidth, - y * this._scaledCellHeight, - width * this._scaledCellWidth, - height * this._scaledCellHeight); - } else { - this._ctx.fillStyle = this._colors.background.css; - this._ctx.fillRect( - x * this._scaledCellWidth, - y * this._scaledCellHeight, - width * this._scaledCellWidth, - height * this._scaledCellHeight); - } - } - - /** - * Draws a truecolor character at the cell. The character will be clipped to - * ensure that it fits with the cell, including the cell to the right if it's - * a wide character. This uses the existing fillStyle on the context. - * @param cell The cell data for the character to draw. - * @param x The column to draw at. - * @param y The row to draw at. - * @param color The color of the character. - */ - protected _fillCharTrueColor(cell: CellData, x: number, y: number): void { - this._ctx.font = this._getFont(false, false); - this._ctx.textBaseline = TEXT_BASELINE; - this._clipRow(y); - - // Draw custom characters if applicable - let drawSuccess = false; - if (this._optionsService.rawOptions.customGlyphs !== false) { - drawSuccess = tryDrawCustomChar(this._ctx, cell.getChars(), x * this._scaledCellWidth, y * this._scaledCellHeight, this._scaledCellWidth, this._scaledCellHeight); - } - - // Draw the character - if (!drawSuccess) { - this._ctx.fillText( - cell.getChars(), - x * this._scaledCellWidth + this._scaledCharLeft, - y * this._scaledCellHeight + this._scaledCharTop + this._scaledCharHeight); - } - } - - /** - * Draws one or more characters at a cell. If possible this will draw using - * the character atlas to reduce draw time. - * @param chars The character or characters. - * @param code The character code. - * @param width The width of the characters. - * @param x The column to draw at. - * @param y The row to draw at. - * @param fg The foreground color, in the format stored within the attributes. - * @param bg The background color, in the format stored within the attributes. - * This is used to validate whether a cached image can be used. - * @param bold Whether the text is bold. - */ - protected _drawChars(cell: ICellData, x: number, y: number): void { - const contrastColor = this._getContrastColor(cell); - - // skip cache right away if we draw in RGB - // Note: to avoid bad runtime JoinedCellData will be skipped - // in the cache handler itself (atlasDidDraw == false) and - // fall through to uncached later down below - if (contrastColor || cell.isFgRGB() || cell.isBgRGB()) { - this._drawUncachedChars(cell, x, y, contrastColor); - return; - } - - let fg; - let bg; - if (cell.isInverse()) { - fg = (cell.isBgDefault()) ? INVERTED_DEFAULT_COLOR : cell.getBgColor(); - bg = (cell.isFgDefault()) ? INVERTED_DEFAULT_COLOR : cell.getFgColor(); - } else { - bg = (cell.isBgDefault()) ? DEFAULT_COLOR : cell.getBgColor(); - fg = (cell.isFgDefault()) ? DEFAULT_COLOR : cell.getFgColor(); - } - - const drawInBrightColor = this._optionsService.rawOptions.drawBoldTextInBrightColors && cell.isBold() && fg < 8; - - fg += drawInBrightColor ? 8 : 0; - this._currentGlyphIdentifier.chars = cell.getChars() || WHITESPACE_CELL_CHAR; - this._currentGlyphIdentifier.code = cell.getCode() || WHITESPACE_CELL_CODE; - this._currentGlyphIdentifier.bg = bg; - this._currentGlyphIdentifier.fg = fg; - this._currentGlyphIdentifier.bold = !!cell.isBold(); - this._currentGlyphIdentifier.dim = !!cell.isDim(); - this._currentGlyphIdentifier.italic = !!cell.isItalic(); - const atlasDidDraw = this._charAtlas?.draw(this._ctx, this._currentGlyphIdentifier, x * this._scaledCellWidth + this._scaledCharLeft, y * this._scaledCellHeight + this._scaledCharTop); - - if (!atlasDidDraw) { - this._drawUncachedChars(cell, x, y); - } - } - - /** - * Draws one or more characters at one or more cells. The character(s) will be - * clipped to ensure that they fit with the cell(s), including the cell to the - * right if the last character is a wide character. - * @param chars The character. - * @param width The width of the character. - * @param fg The foreground color, in the format stored within the attributes. - * @param x The column to draw at. - * @param y The row to draw at. - */ - private _drawUncachedChars(cell: ICellData, x: number, y: number, fgOverride?: IColor): void { - this._ctx.save(); - this._ctx.font = this._getFont(!!cell.isBold(), !!cell.isItalic()); - this._ctx.textBaseline = TEXT_BASELINE; - - if (cell.isInverse()) { - if (fgOverride) { - this._ctx.fillStyle = fgOverride.css; - } else if (cell.isBgDefault()) { - this._ctx.fillStyle = color.opaque(this._colors.background).css; - } else if (cell.isBgRGB()) { - this._ctx.fillStyle = `rgb(${AttributeData.toColorRGB(cell.getBgColor()).join(',')})`; - } else { - let bg = cell.getBgColor(); - if (this._optionsService.rawOptions.drawBoldTextInBrightColors && cell.isBold() && bg < 8) { - bg += 8; - } - this._ctx.fillStyle = this._colors.ansi[bg].css; - } - } else { - if (fgOverride) { - this._ctx.fillStyle = fgOverride.css; - } else if (cell.isFgDefault()) { - this._ctx.fillStyle = this._colors.foreground.css; - } else if (cell.isFgRGB()) { - this._ctx.fillStyle = `rgb(${AttributeData.toColorRGB(cell.getFgColor()).join(',')})`; - } else { - let fg = cell.getFgColor(); - if (this._optionsService.rawOptions.drawBoldTextInBrightColors && cell.isBold() && fg < 8) { - fg += 8; - } - this._ctx.fillStyle = this._colors.ansi[fg].css; - } - } - - this._clipRow(y); - - // Apply alpha to dim the character - if (cell.isDim()) { - this._ctx.globalAlpha = DIM_OPACITY; - } - - // Draw custom characters if applicable - let drawSuccess = false; - if (this._optionsService.rawOptions.customGlyphs !== false) { - drawSuccess = tryDrawCustomChar(this._ctx, cell.getChars(), x * this._scaledCellWidth, y * this._scaledCellHeight, this._scaledCellWidth, this._scaledCellHeight); - } - - // Draw the character - if (!drawSuccess) { - this._ctx.fillText( - cell.getChars(), - x * this._scaledCellWidth + this._scaledCharLeft, - y * this._scaledCellHeight + this._scaledCharTop + this._scaledCharHeight); - } - - this._ctx.restore(); - } - - - /** - * Clips a row to ensure no pixels will be drawn outside the cells in the row. - * @param y The row to clip. - */ - private _clipRow(y: number): void { - this._ctx.beginPath(); - this._ctx.rect( - 0, - y * this._scaledCellHeight, - this._bufferService.cols * this._scaledCellWidth, - this._scaledCellHeight); - this._ctx.clip(); - } - - /** - * Gets the current font. - * @param isBold If we should use the bold fontWeight. - */ - protected _getFont(isBold: boolean, isItalic: boolean): string { - const fontWeight = isBold ? this._optionsService.rawOptions.fontWeightBold : this._optionsService.rawOptions.fontWeight; - const fontStyle = isItalic ? 'italic' : ''; - - return `${fontStyle} ${fontWeight} ${this._optionsService.rawOptions.fontSize * window.devicePixelRatio}px ${this._optionsService.rawOptions.fontFamily}`; - } - - private _getContrastColor(cell: CellData): IColor | undefined { - if (this._optionsService.rawOptions.minimumContrastRatio === 1) { - return undefined; - } - - // Try get from cache first - const adjustedColor = this._colors.contrastCache.getColor(cell.bg, cell.fg); - if (adjustedColor !== undefined) { - return adjustedColor || undefined; - } - - let fgColor = cell.getFgColor(); - let fgColorMode = cell.getFgColorMode(); - let bgColor = cell.getBgColor(); - let bgColorMode = cell.getBgColorMode(); - const isInverse = !!cell.isInverse(); - const isBold = !!cell.isInverse(); - if (isInverse) { - const temp = fgColor; - fgColor = bgColor; - bgColor = temp; - const temp2 = fgColorMode; - fgColorMode = bgColorMode; - bgColorMode = temp2; - } - - const bgRgba = this._resolveBackgroundRgba(bgColorMode, bgColor, isInverse); - const fgRgba = this._resolveForegroundRgba(fgColorMode, fgColor, isInverse, isBold); - const result = rgba.ensureContrastRatio(bgRgba, fgRgba, this._optionsService.rawOptions.minimumContrastRatio); - - if (!result) { - this._colors.contrastCache.setColor(cell.bg, cell.fg, null); - return undefined; - } - - const color: IColor = { - css: channels.toCss( - (result >> 24) & 0xFF, - (result >> 16) & 0xFF, - (result >> 8) & 0xFF - ), - rgba: result - }; - this._colors.contrastCache.setColor(cell.bg, cell.fg, color); - - return color; - } - - private _resolveBackgroundRgba(bgColorMode: number, bgColor: number, inverse: boolean): number { - switch (bgColorMode) { - case Attributes.CM_P16: - case Attributes.CM_P256: - return this._colors.ansi[bgColor].rgba; - case Attributes.CM_RGB: - return bgColor << 8; - case Attributes.CM_DEFAULT: - default: - if (inverse) { - return this._colors.foreground.rgba; - } - return this._colors.background.rgba; - } - } - - private _resolveForegroundRgba(fgColorMode: number, fgColor: number, inverse: boolean, bold: boolean): number { - switch (fgColorMode) { - case Attributes.CM_P16: - case Attributes.CM_P256: - if (this._optionsService.rawOptions.drawBoldTextInBrightColors && bold && fgColor < 8) { - fgColor += 8; - } - return this._colors.ansi[fgColor].rgba; - case Attributes.CM_RGB: - return fgColor << 8; - case Attributes.CM_DEFAULT: - default: - if (inverse) { - return this._colors.background.rgba; - } - return this._colors.foreground.rgba; - } - } -} - diff --git a/node_modules/xterm/src/browser/renderer/CursorRenderLayer.ts b/node_modules/xterm/src/browser/renderer/CursorRenderLayer.ts deleted file mode 100644 index ea419cb..0000000 --- a/node_modules/xterm/src/browser/renderer/CursorRenderLayer.ts +++ /dev/null @@ -1,377 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IRenderDimensions, IRequestRedrawEvent } from 'browser/renderer/Types'; -import { BaseRenderLayer } from 'browser/renderer/BaseRenderLayer'; -import { ICellData } from 'common/Types'; -import { CellData } from 'common/buffer/CellData'; -import { IColorSet } from 'browser/Types'; -import { IBufferService, IOptionsService, ICoreService } from 'common/services/Services'; -import { IEventEmitter } from 'common/EventEmitter'; -import { ICoreBrowserService } from 'browser/services/Services'; - -interface ICursorState { - x: number; - y: number; - isFocused: boolean; - style: string; - width: number; -} - -/** - * The time between cursor blinks. - */ -const BLINK_INTERVAL = 600; - -export class CursorRenderLayer extends BaseRenderLayer { - private _state: ICursorState; - private _cursorRenderers: {[key: string]: (x: number, y: number, cell: ICellData) => void}; - private _cursorBlinkStateManager: CursorBlinkStateManager | undefined; - private _cell: ICellData = new CellData(); - - constructor( - container: HTMLElement, - zIndex: number, - colors: IColorSet, - rendererId: number, - private _onRequestRedraw: IEventEmitter<IRequestRedrawEvent>, - @IBufferService bufferService: IBufferService, - @IOptionsService optionsService: IOptionsService, - @ICoreService private readonly _coreService: ICoreService, - @ICoreBrowserService private readonly _coreBrowserService: ICoreBrowserService - ) { - super(container, 'cursor', zIndex, true, colors, rendererId, bufferService, optionsService); - this._state = { - x: 0, - y: 0, - isFocused: false, - style: '', - width: 0 - }; - this._cursorRenderers = { - 'bar': this._renderBarCursor.bind(this), - 'block': this._renderBlockCursor.bind(this), - 'underline': this._renderUnderlineCursor.bind(this) - }; - } - - public dispose(): void { - if (this._cursorBlinkStateManager) { - this._cursorBlinkStateManager.dispose(); - this._cursorBlinkStateManager = undefined; - } - super.dispose(); - } - - public resize(dim: IRenderDimensions): void { - super.resize(dim); - // Resizing the canvas discards the contents of the canvas so clear state - this._state = { - x: 0, - y: 0, - isFocused: false, - style: '', - width: 0 - }; - } - - public reset(): void { - this._clearCursor(); - this._cursorBlinkStateManager?.restartBlinkAnimation(); - this.onOptionsChanged(); - } - - public onBlur(): void { - this._cursorBlinkStateManager?.pause(); - this._onRequestRedraw.fire({ start: this._bufferService.buffer.y, end: this._bufferService.buffer.y }); - } - - public onFocus(): void { - this._cursorBlinkStateManager?.resume(); - this._onRequestRedraw.fire({ start: this._bufferService.buffer.y, end: this._bufferService.buffer.y }); - } - - public onOptionsChanged(): void { - if (this._optionsService.rawOptions.cursorBlink) { - if (!this._cursorBlinkStateManager) { - this._cursorBlinkStateManager = new CursorBlinkStateManager(this._coreBrowserService.isFocused, () => { - this._render(true); - }); - } - } else { - this._cursorBlinkStateManager?.dispose(); - this._cursorBlinkStateManager = undefined; - } - // Request a refresh from the terminal as management of rendering is being - // moved back to the terminal - this._onRequestRedraw.fire({ start: this._bufferService.buffer.y, end: this._bufferService.buffer.y }); - } - - public onCursorMove(): void { - this._cursorBlinkStateManager?.restartBlinkAnimation(); - } - - public onGridChanged(startRow: number, endRow: number): void { - if (!this._cursorBlinkStateManager || this._cursorBlinkStateManager.isPaused) { - this._render(false); - } else { - this._cursorBlinkStateManager.restartBlinkAnimation(); - } - } - - private _render(triggeredByAnimationFrame: boolean): void { - // Don't draw the cursor if it's hidden - if (!this._coreService.isCursorInitialized || this._coreService.isCursorHidden) { - this._clearCursor(); - return; - } - - const cursorY = this._bufferService.buffer.ybase + this._bufferService.buffer.y; - const viewportRelativeCursorY = cursorY - this._bufferService.buffer.ydisp; - - // Don't draw the cursor if it's off-screen - if (viewportRelativeCursorY < 0 || viewportRelativeCursorY >= this._bufferService.rows) { - this._clearCursor(); - return; - } - - // in case cursor.x == cols adjust visual cursor to cols - 1 - const cursorX = Math.min(this._bufferService.buffer.x, this._bufferService.cols - 1); - this._bufferService.buffer.lines.get(cursorY)!.loadCell(cursorX, this._cell); - if (this._cell.content === undefined) { - return; - } - - if (!this._coreBrowserService.isFocused) { - this._clearCursor(); - this._ctx.save(); - this._ctx.fillStyle = this._colors.cursor.css; - const cursorStyle = this._optionsService.rawOptions.cursorStyle; - if (cursorStyle && cursorStyle !== 'block') { - this._cursorRenderers[cursorStyle](cursorX, viewportRelativeCursorY, this._cell); - } else { - this._renderBlurCursor(cursorX, viewportRelativeCursorY, this._cell); - } - this._ctx.restore(); - this._state.x = cursorX; - this._state.y = viewportRelativeCursorY; - this._state.isFocused = false; - this._state.style = cursorStyle; - this._state.width = this._cell.getWidth(); - return; - } - - // Don't draw the cursor if it's blinking - if (this._cursorBlinkStateManager && !this._cursorBlinkStateManager.isCursorVisible) { - this._clearCursor(); - return; - } - - if (this._state) { - // The cursor is already in the correct spot, don't redraw - if (this._state.x === cursorX && - this._state.y === viewportRelativeCursorY && - this._state.isFocused === this._coreBrowserService.isFocused && - this._state.style === this._optionsService.rawOptions.cursorStyle && - this._state.width === this._cell.getWidth()) { - return; - } - this._clearCursor(); - } - - this._ctx.save(); - this._cursorRenderers[this._optionsService.rawOptions.cursorStyle || 'block'](cursorX, viewportRelativeCursorY, this._cell); - this._ctx.restore(); - - this._state.x = cursorX; - this._state.y = viewportRelativeCursorY; - this._state.isFocused = false; - this._state.style = this._optionsService.rawOptions.cursorStyle; - this._state.width = this._cell.getWidth(); - } - - private _clearCursor(): void { - if (this._state) { - // Avoid potential rounding errors when device pixel ratio is less than 1 - if (window.devicePixelRatio < 1) { - this._clearAll(); - } else { - this._clearCells(this._state.x, this._state.y, this._state.width, 1); - } - this._state = { - x: 0, - y: 0, - isFocused: false, - style: '', - width: 0 - }; - } - } - - private _renderBarCursor(x: number, y: number, cell: ICellData): void { - this._ctx.save(); - this._ctx.fillStyle = this._colors.cursor.css; - this._fillLeftLineAtCell(x, y, this._optionsService.rawOptions.cursorWidth); - this._ctx.restore(); - } - - private _renderBlockCursor(x: number, y: number, cell: ICellData): void { - this._ctx.save(); - this._ctx.fillStyle = this._colors.cursor.css; - this._fillCells(x, y, cell.getWidth(), 1); - this._ctx.fillStyle = this._colors.cursorAccent.css; - this._fillCharTrueColor(cell, x, y); - this._ctx.restore(); - } - - private _renderUnderlineCursor(x: number, y: number, cell: ICellData): void { - this._ctx.save(); - this._ctx.fillStyle = this._colors.cursor.css; - this._fillBottomLineAtCells(x, y); - this._ctx.restore(); - } - - private _renderBlurCursor(x: number, y: number, cell: ICellData): void { - this._ctx.save(); - this._ctx.strokeStyle = this._colors.cursor.css; - this._strokeRectAtCell(x, y, cell.getWidth(), 1); - this._ctx.restore(); - } -} - -class CursorBlinkStateManager { - public isCursorVisible: boolean; - - private _animationFrame: number | undefined; - private _blinkStartTimeout: number | undefined; - private _blinkInterval: number | undefined; - - /** - * The time at which the animation frame was restarted, this is used on the - * next render to restart the timers so they don't need to restart the timers - * multiple times over a short period. - */ - private _animationTimeRestarted: number | undefined; - - constructor( - isFocused: boolean, - private _renderCallback: () => void - ) { - this.isCursorVisible = true; - if (isFocused) { - this._restartInterval(); - } - } - - public get isPaused(): boolean { return !(this._blinkStartTimeout || this._blinkInterval); } - - public dispose(): void { - if (this._blinkInterval) { - window.clearInterval(this._blinkInterval); - this._blinkInterval = undefined; - } - if (this._blinkStartTimeout) { - window.clearTimeout(this._blinkStartTimeout); - this._blinkStartTimeout = undefined; - } - if (this._animationFrame) { - window.cancelAnimationFrame(this._animationFrame); - this._animationFrame = undefined; - } - } - - public restartBlinkAnimation(): void { - if (this.isPaused) { - return; - } - // Save a timestamp so that the restart can be done on the next interval - this._animationTimeRestarted = Date.now(); - // Force a cursor render to ensure it's visible and in the correct position - this.isCursorVisible = true; - if (!this._animationFrame) { - this._animationFrame = window.requestAnimationFrame(() => { - this._renderCallback(); - this._animationFrame = undefined; - }); - } - } - - private _restartInterval(timeToStart: number = BLINK_INTERVAL): void { - // Clear any existing interval - if (this._blinkInterval) { - window.clearInterval(this._blinkInterval); - this._blinkInterval = undefined; - } - - // Setup the initial timeout which will hide the cursor, this is done before - // the regular interval is setup in order to support restarting the blink - // animation in a lightweight way (without thrashing clearInterval and - // setInterval). - this._blinkStartTimeout = window.setTimeout(() => { - // Check if another animation restart was requested while this was being - // started - if (this._animationTimeRestarted) { - const time = BLINK_INTERVAL - (Date.now() - this._animationTimeRestarted); - this._animationTimeRestarted = undefined; - if (time > 0) { - this._restartInterval(time); - return; - } - } - - // Hide the cursor - this.isCursorVisible = false; - this._animationFrame = window.requestAnimationFrame(() => { - this._renderCallback(); - this._animationFrame = undefined; - }); - - // Setup the blink interval - this._blinkInterval = window.setInterval(() => { - // Adjust the animation time if it was restarted - if (this._animationTimeRestarted) { - // calc time diff - // Make restart interval do a setTimeout initially? - const time = BLINK_INTERVAL - (Date.now() - this._animationTimeRestarted); - this._animationTimeRestarted = undefined; - this._restartInterval(time); - return; - } - - // Invert visibility and render - this.isCursorVisible = !this.isCursorVisible; - this._animationFrame = window.requestAnimationFrame(() => { - this._renderCallback(); - this._animationFrame = undefined; - }); - }, BLINK_INTERVAL); - }, timeToStart); - } - - public pause(): void { - this.isCursorVisible = true; - if (this._blinkInterval) { - window.clearInterval(this._blinkInterval); - this._blinkInterval = undefined; - } - if (this._blinkStartTimeout) { - window.clearTimeout(this._blinkStartTimeout); - this._blinkStartTimeout = undefined; - } - if (this._animationFrame) { - window.cancelAnimationFrame(this._animationFrame); - this._animationFrame = undefined; - } - } - - public resume(): void { - // Clear out any existing timers just in case - this.pause(); - - this._animationTimeRestarted = undefined; - this._restartInterval(); - this.restartBlinkAnimation(); - } -} diff --git a/node_modules/xterm/src/browser/renderer/CustomGlyphs.ts b/node_modules/xterm/src/browser/renderer/CustomGlyphs.ts deleted file mode 100644 index 7756279..0000000 --- a/node_modules/xterm/src/browser/renderer/CustomGlyphs.ts +++ /dev/null @@ -1,563 +0,0 @@ -/** - * Copyright (c) 2021 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { throwIfFalsy } from 'browser/renderer/RendererUtils'; - -interface IBlockVector { - x: number; - y: number; - w: number; - h: number; -} - -export const blockElementDefinitions: { [index: string]: IBlockVector[] | undefined } = { - // Block elements (0x2580-0x2590) - '▀': [{ x: 0, y: 0, w: 8, h: 4 }], // UPPER HALF BLOCK - '▁': [{ x: 0, y: 7, w: 8, h: 1 }], // LOWER ONE EIGHTH BLOCK - '▂': [{ x: 0, y: 6, w: 8, h: 2 }], // LOWER ONE QUARTER BLOCK - '▃': [{ x: 0, y: 5, w: 8, h: 3 }], // LOWER THREE EIGHTHS BLOCK - '▄': [{ x: 0, y: 4, w: 8, h: 4 }], // LOWER HALF BLOCK - '▅': [{ x: 0, y: 3, w: 8, h: 5 }], // LOWER FIVE EIGHTHS BLOCK - '▆': [{ x: 0, y: 2, w: 8, h: 6 }], // LOWER THREE QUARTERS BLOCK - '▇': [{ x: 0, y: 1, w: 8, h: 7 }], // LOWER SEVEN EIGHTHS BLOCK - '█': [{ x: 0, y: 0, w: 8, h: 8 }], // FULL BLOCK - '▉': [{ x: 0, y: 0, w: 7, h: 8 }], // LEFT SEVEN EIGHTHS BLOCK - '▊': [{ x: 0, y: 0, w: 6, h: 8 }], // LEFT THREE QUARTERS BLOCK - '▋': [{ x: 0, y: 0, w: 5, h: 8 }], // LEFT FIVE EIGHTHS BLOCK - '▌': [{ x: 0, y: 0, w: 4, h: 8 }], // LEFT HALF BLOCK - '▍': [{ x: 0, y: 0, w: 3, h: 8 }], // LEFT THREE EIGHTHS BLOCK - '▎': [{ x: 0, y: 0, w: 2, h: 8 }], // LEFT ONE QUARTER BLOCK - '▏': [{ x: 0, y: 0, w: 1, h: 8 }], // LEFT ONE EIGHTH BLOCK - '▐': [{ x: 4, y: 0, w: 4, h: 8 }], // RIGHT HALF BLOCK - - // Block elements (0x2594-0x2595) - '▔': [{ x: 0, y: 0, w: 9, h: 1 }], // UPPER ONE EIGHTH BLOCK - '▕': [{ x: 7, y: 0, w: 1, h: 8 }], // RIGHT ONE EIGHTH BLOCK - - // Terminal graphic characters (0x2596-0x259F) - '▖': [{ x: 0, y: 4, w: 4, h: 4 }], // QUADRANT LOWER LEFT - '▗': [{ x: 4, y: 4, w: 4, h: 4 }], // QUADRANT LOWER RIGHT - '▘': [{ x: 0, y: 0, w: 4, h: 4 }], // QUADRANT UPPER LEFT - '▙': [{ x: 0, y: 0, w: 4, h: 8 }, { x: 0, y: 4, w: 8, h: 4 }], // QUADRANT UPPER LEFT AND LOWER LEFT AND LOWER RIGHT - '▚': [{ x: 0, y: 0, w: 4, h: 4 }, { x: 4, y: 4, w: 4, h: 4 }], // QUADRANT UPPER LEFT AND LOWER RIGHT - '▛': [{ x: 0, y: 0, w: 4, h: 8 }, { x: 0, y: 0, w: 4, h: 8 }], // QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER LEFT - '▜': [{ x: 0, y: 0, w: 8, h: 4 }, { x: 4, y: 0, w: 4, h: 8 }], // QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER RIGHT - '▝': [{ x: 4, y: 0, w: 4, h: 4 }], // QUADRANT UPPER RIGHT - '▞': [{ x: 4, y: 0, w: 4, h: 4 }, { x: 0, y: 4, w: 4, h: 4 }], // QUADRANT UPPER RIGHT AND LOWER LEFT - '▟': [{ x: 4, y: 0, w: 4, h: 8 }, { x: 0, y: 4, w: 8, h: 4 }], // QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT - - // VERTICAL ONE EIGHTH BLOCK-2 through VERTICAL ONE EIGHTH BLOCK-7 - '\u{1FB70}': [{ x: 1, y: 0, w: 1, h: 8 }], - '\u{1FB71}': [{ x: 2, y: 0, w: 1, h: 8 }], - '\u{1FB72}': [{ x: 3, y: 0, w: 1, h: 8 }], - '\u{1FB73}': [{ x: 4, y: 0, w: 1, h: 8 }], - '\u{1FB74}': [{ x: 5, y: 0, w: 1, h: 8 }], - '\u{1FB75}': [{ x: 6, y: 0, w: 1, h: 8 }], - - // HORIZONTAL ONE EIGHTH BLOCK-2 through HORIZONTAL ONE EIGHTH BLOCK-7 - '\u{1FB76}': [{ x: 0, y: 1, w: 8, h: 1 }], - '\u{1FB77}': [{ x: 0, y: 2, w: 8, h: 1 }], - '\u{1FB78}': [{ x: 0, y: 3, w: 8, h: 1 }], - '\u{1FB79}': [{ x: 0, y: 4, w: 8, h: 1 }], - '\u{1FB7A}': [{ x: 0, y: 5, w: 8, h: 1 }], - '\u{1FB7B}': [{ x: 0, y: 6, w: 8, h: 1 }], - - // LEFT AND LOWER ONE EIGHTH BLOCK - '\u{1FB7C}': [{ x: 0, y: 0, w: 1, h: 8 }, { x: 0, y: 7, w: 8, h: 1 }], - // LEFT AND UPPER ONE EIGHTH BLOCK - '\u{1FB7D}': [{ x: 0, y: 0, w: 1, h: 8 }, { x: 0, y: 0, w: 8, h: 1 }], - // RIGHT AND UPPER ONE EIGHTH BLOCK - '\u{1FB7E}': [{ x: 7, y: 0, w: 1, h: 8 }, { x: 0, y: 0, w: 8, h: 1 }], - // RIGHT AND LOWER ONE EIGHTH BLOCK - '\u{1FB7F}': [{ x: 7, y: 0, w: 1, h: 8 }, { x: 0, y: 7, w: 8, h: 1 }], - // UPPER AND LOWER ONE EIGHTH BLOCK - '\u{1FB80}': [{ x: 0, y: 0, w: 8, h: 1 }, { x: 0, y: 7, w: 8, h: 1 }], - // HORIZONTAL ONE EIGHTH BLOCK-1358 - '\u{1FB81}': [{ x: 0, y: 0, w: 8, h: 1 }, { x: 0, y: 2, w: 8, h: 1 }, { x: 0, y: 4, w: 8, h: 1 }, { x: 0, y: 7, w: 8, h: 1 }], - - // UPPER ONE QUARTER BLOCK - '\u{1FB82}': [{ x: 0, y: 0, w: 8, h: 2 }], - // UPPER THREE EIGHTHS BLOCK - '\u{1FB83}': [{ x: 0, y: 0, w: 8, h: 3 }], - // UPPER FIVE EIGHTHS BLOCK - '\u{1FB84}': [{ x: 0, y: 0, w: 8, h: 5 }], - // UPPER THREE QUARTERS BLOCK - '\u{1FB85}': [{ x: 0, y: 0, w: 8, h: 6 }], - // UPPER SEVEN EIGHTHS BLOCK - '\u{1FB86}': [{ x: 0, y: 0, w: 8, h: 7 }], - - // RIGHT ONE QUARTER BLOCK - '\u{1FB87}': [{ x: 6, y: 0, w: 2, h: 8 }], - // RIGHT THREE EIGHTHS B0OCK - '\u{1FB88}': [{ x: 5, y: 0, w: 3, h: 8 }], - // RIGHT FIVE EIGHTHS BL0CK - '\u{1FB89}': [{ x: 3, y: 0, w: 5, h: 8 }], - // RIGHT THREE QUARTERS 0LOCK - '\u{1FB8A}': [{ x: 2, y: 0, w: 6, h: 8 }], - // RIGHT SEVEN EIGHTHS B0OCK - '\u{1FB8B}': [{ x: 1, y: 0, w: 7, h: 8 }], - - // CHECKER BOARD FILL - '\u{1FB95}': [ - { x: 0, y: 0, w: 2, h: 2 }, { x: 4, y: 0, w: 2, h: 2 }, - { x: 2, y: 2, w: 2, h: 2 }, { x: 6, y: 2, w: 2, h: 2 }, - { x: 0, y: 4, w: 2, h: 2 }, { x: 4, y: 4, w: 2, h: 2 }, - { x: 2, y: 6, w: 2, h: 2 }, { x: 6, y: 6, w: 2, h: 2 } - ], - // INVERSE CHECKER BOARD FILL - '\u{1FB96}': [ - { x: 2, y: 0, w: 2, h: 2 }, { x: 6, y: 0, w: 2, h: 2 }, - { x: 0, y: 2, w: 2, h: 2 }, { x: 4, y: 2, w: 2, h: 2 }, - { x: 2, y: 4, w: 2, h: 2 }, { x: 6, y: 4, w: 2, h: 2 }, - { x: 0, y: 6, w: 2, h: 2 }, { x: 4, y: 6, w: 2, h: 2 } - ], - // HEAVY HORIZONTAL FILL (upper middle and lower one quarter block) - '\u{1FB97}': [{ x: 0, y: 2, w: 8, h: 2 }, { x: 0, y: 6, w: 8, h: 2 }] -}; - -type PatternDefinition = number[][]; - -/** - * Defines the repeating pattern used by special characters, the pattern is made up of a 2d array of - * pixel values to be filled (1) or not filled (0). - */ -const patternCharacterDefinitions: { [key: string]: PatternDefinition | undefined } = { - // Shade characters (0x2591-0x2593) - '░': [ // LIGHT SHADE (25%) - [1, 0, 0, 0], - [0, 0, 0, 0], - [0, 0, 1, 0], - [0, 0, 0, 0] - ], - '▒': [ // MEDIUM SHADE (50%) - [1, 0], - [0, 0], - [0, 1], - [0, 0] - ], - '▓': [ // DARK SHADE (75%) - [0, 1], - [1, 1], - [1, 0], - [1, 1] - ] -}; - -const enum Shapes { - /** │ */ TOP_TO_BOTTOM = 'M.5,0 L.5,1', - /** ─ */ LEFT_TO_RIGHT = 'M0,.5 L1,.5', - - /** └ */ TOP_TO_RIGHT = 'M.5,0 L.5,.5 L1,.5', - /** ┘ */ TOP_TO_LEFT = 'M.5,0 L.5,.5 L0,.5', - /** ┐ */ LEFT_TO_BOTTOM = 'M0,.5 L.5,.5 L.5,1', - /** ┌ */ RIGHT_TO_BOTTOM = 'M0.5,1 L.5,.5 L1,.5', - - /** ╵ */ MIDDLE_TO_TOP = 'M.5,.5 L.5,0', - /** ╴ */ MIDDLE_TO_LEFT = 'M.5,.5 L0,.5', - /** ╶ */ MIDDLE_TO_RIGHT = 'M.5,.5 L1,.5', - /** ╷ */ MIDDLE_TO_BOTTOM = 'M.5,.5 L.5,1', - - /** ┴ */ T_TOP = 'M0,.5 L1,.5 M.5,.5 L.5,0', - /** ┤ */ T_LEFT = 'M.5,0 L.5,1 M.5,.5 L0,.5', - /** ├ */ T_RIGHT = 'M.5,0 L.5,1 M.5,.5 L1,.5', - /** ┬ */ T_BOTTOM = 'M0,.5 L1,.5 M.5,.5 L.5,1', - - /** ┼ */ CROSS = 'M0,.5 L1,.5 M.5,0 L.5,1', - - /** ╌ */ TWO_DASHES_HORIZONTAL = 'M.1,.5 L.4,.5 M.6,.5 L.9,.5', // .2 empty, .3 filled - /** ┄ */ THREE_DASHES_HORIZONTAL = 'M.0667,.5 L.2667,.5 M.4,.5 L.6,.5 M.7333,.5 L.9333,.5', // .1333 empty, .2 filled - /** ┉ */ FOUR_DASHES_HORIZONTAL = 'M.05,.5 L.2,.5 M.3,.5 L.45,.5 M.55,.5 L.7,.5 M.8,.5 L.95,.5', // .1 empty, .15 filled - /** ╎ */ TWO_DASHES_VERTICAL = 'M.5,.1 L.5,.4 M.5,.6 L.5,.9', - /** ┆ */ THREE_DASHES_VERTICAL = 'M.5,.0667 L.5,.2667 M.5,.4 L.5,.6 M.5,.7333 L.5,.9333', - /** ┊ */ FOUR_DASHES_VERTICAL = 'M.5,.05 L.5,.2 M.5,.3 L.5,.45 L.5,.55 M.5,.7 L.5,.95', -} - -const enum Style { - NORMAL = 1, - BOLD = 3 -} - -/** - * This contains the definitions of all box drawing characters in the format of SVG paths (ie. the - * svg d attribute). - */ -export const boxDrawingDefinitions: { [character: string]: { [fontWeight: number]: string | ((xp: number, yp: number) => string) } | undefined } = { - // Uniform normal and bold - '─': { [Style.NORMAL]: Shapes.LEFT_TO_RIGHT }, - '━': { [Style.BOLD]: Shapes.LEFT_TO_RIGHT }, - '│': { [Style.NORMAL]: Shapes.TOP_TO_BOTTOM }, - '┃': { [Style.BOLD]: Shapes.TOP_TO_BOTTOM }, - '┌': { [Style.NORMAL]: Shapes.RIGHT_TO_BOTTOM }, - '┏': { [Style.BOLD]: Shapes.RIGHT_TO_BOTTOM }, - '┐': { [Style.NORMAL]: Shapes.LEFT_TO_BOTTOM }, - '┓': { [Style.BOLD]: Shapes.LEFT_TO_BOTTOM }, - '└': { [Style.NORMAL]: Shapes.TOP_TO_RIGHT }, - '┗': { [Style.BOLD]: Shapes.TOP_TO_RIGHT }, - '┘': { [Style.NORMAL]: Shapes.TOP_TO_LEFT }, - '┛': { [Style.BOLD]: Shapes.TOP_TO_LEFT }, - '├': { [Style.NORMAL]: Shapes.T_RIGHT }, - '┣': { [Style.BOLD]: Shapes.T_RIGHT }, - '┤': { [Style.NORMAL]: Shapes.T_LEFT }, - '┫': { [Style.BOLD]: Shapes.T_LEFT }, - '┬': { [Style.NORMAL]: Shapes.T_BOTTOM }, - '┳': { [Style.BOLD]: Shapes.T_BOTTOM }, - '┴': { [Style.NORMAL]: Shapes.T_TOP }, - '┻': { [Style.BOLD]: Shapes.T_TOP }, - '┼': { [Style.NORMAL]: Shapes.CROSS }, - '╋': { [Style.BOLD]: Shapes.CROSS }, - '╴': { [Style.NORMAL]: Shapes.MIDDLE_TO_LEFT }, - '╸': { [Style.BOLD]: Shapes.MIDDLE_TO_LEFT }, - '╵': { [Style.NORMAL]: Shapes.MIDDLE_TO_TOP }, - '╹': { [Style.BOLD]: Shapes.MIDDLE_TO_TOP }, - '╶': { [Style.NORMAL]: Shapes.MIDDLE_TO_RIGHT }, - '╺': { [Style.BOLD]: Shapes.MIDDLE_TO_RIGHT }, - '╷': { [Style.NORMAL]: Shapes.MIDDLE_TO_BOTTOM }, - '╻': { [Style.BOLD]: Shapes.MIDDLE_TO_BOTTOM }, - - // Double border - '═': { [Style.NORMAL]: (xp, yp) => `M0,${.5 - yp} L1,${.5 - yp} M0,${.5 + yp} L1,${.5 + yp}` }, - '║': { [Style.NORMAL]: (xp, yp) => `M${.5 - xp},0 L${.5 - xp},1 M${.5 + xp},0 L${.5 + xp},1` }, - '╒': { [Style.NORMAL]: (xp, yp) => `M.5,1 L.5,${.5 - yp} L1,${.5 - yp} M.5,${.5 + yp} L1,${.5 + yp}` }, - '╓': { [Style.NORMAL]: (xp, yp) => `M${.5 - xp},1 L${.5 - xp},.5 L1,.5 M${.5 + xp},.5 L${.5 + xp},1` }, - '╔': { [Style.NORMAL]: (xp, yp) => `M1,${.5 - yp} L${.5 - xp},${.5 - yp} L${.5 - xp},1 M1,${.5 + yp} L${.5 + xp},${.5 + yp} L${.5 + xp},1` }, - '╕': { [Style.NORMAL]: (xp, yp) => `M0,${.5 - yp} L.5,${.5 - yp} L.5,1 M0,${.5 + yp} L.5,${.5 + yp}` }, - '╖': { [Style.NORMAL]: (xp, yp) => `M${.5 + xp},1 L${.5 + xp},.5 L0,.5 M${.5 - xp},.5 L${.5 - xp},1` }, - '╗': { [Style.NORMAL]: (xp, yp) => `M0,${.5 + yp} L${.5 - xp},${.5 + yp} L${.5 - xp},1 M0,${.5 - yp} L${.5 + xp},${.5 - yp} L${.5 + xp},1` }, - '╘': { [Style.NORMAL]: (xp, yp) => `M.5,0 L.5,${.5 + yp} L1,${.5 + yp} M.5,${.5 - yp} L1,${.5 - yp}` }, - '╙': { [Style.NORMAL]: (xp, yp) => `M1,.5 L${.5 - xp},.5 L${.5 - xp},0 M${.5 + xp},.5 L${.5 + xp},0` }, - '╚': { [Style.NORMAL]: (xp, yp) => `M1,${.5 - yp} L${.5 + xp},${.5 - yp} L${.5 + xp},0 M1,${.5 + yp} L${.5 - xp},${.5 + yp} L${.5 - xp},0` }, - '╛': { [Style.NORMAL]: (xp, yp) => `M0,${.5 + yp} L.5,${.5 + yp} L.5,0 M0,${.5 - yp} L.5,${.5 - yp}` }, - '╜': { [Style.NORMAL]: (xp, yp) => `M0,.5 L${.5 + xp},.5 L${.5 + xp},0 M${.5 - xp},.5 L${.5 - xp},0` }, - '╝': { [Style.NORMAL]: (xp, yp) => `M0,${.5 - yp} L${.5 - xp},${.5 - yp} L${.5 - xp},0 M0,${.5 + yp} L${.5 + xp},${.5 + yp} L${.5 + xp},0` }, - '╞': { [Style.NORMAL]: (xp, yp) => `${Shapes.TOP_TO_BOTTOM} M.5,${.5 - yp} L1,${.5 - yp} M.5,${.5 + yp} L1,${.5 + yp}` }, - '╟': { [Style.NORMAL]: (xp, yp) => `M${.5 - xp},0 L${.5 - xp},1 M${.5 + xp},0 L${.5 + xp},1 M${.5 + xp},.5 L1,.5` }, - '╠': { [Style.NORMAL]: (xp, yp) => `M${.5 - xp},0 L${.5 - xp},1 M1,${.5 + yp} L${.5 + xp},${.5 + yp} L${.5 + xp},1 M1,${.5 - yp} L${.5 + xp},${.5 - yp} L${.5 + xp},0` }, - '╡': { [Style.NORMAL]: (xp, yp) => `${Shapes.TOP_TO_BOTTOM} M0,${.5 - yp} L.5,${.5 - yp} M0,${.5 + yp} L.5,${.5 + yp}` }, - '╢': { [Style.NORMAL]: (xp, yp) => `M0,.5 L${.5 - xp},.5 M${.5 - xp},0 L${.5 - xp},1 M${.5 + xp},0 L${.5 + xp},1` }, - '╣': { [Style.NORMAL]: (xp, yp) => `M${.5 + xp},0 L${.5 + xp},1 M0,${.5 + yp} L${.5 - xp},${.5 + yp} L${.5 - xp},1 M0,${.5 - yp} L${.5 - xp},${.5 - yp} L${.5 - xp},0` }, - '╤': { [Style.NORMAL]: (xp, yp) => `M0,${.5 - yp} L1,${.5 - yp} M0,${.5 + yp} L1,${.5 + yp} M.5,${.5 + yp} L.5,1` }, - '╥': { [Style.NORMAL]: (xp, yp) => `${Shapes.LEFT_TO_RIGHT} M${.5 - xp},.5 L${.5 - xp},1 M${.5 + xp},.5 L${.5 + xp},1` }, - '╦': { [Style.NORMAL]: (xp, yp) => `M0,${.5 - yp} L1,${.5 - yp} M0,${.5 + yp} L${.5 - xp},${.5 + yp} L${.5 - xp},1 M1,${.5 + yp} L${.5 + xp},${.5 + yp} L${.5 + xp},1` }, - '╧': { [Style.NORMAL]: (xp, yp) => `M.5,0 L.5,${.5 - yp} M0,${.5 - yp} L1,${.5 - yp} M0,${.5 + yp} L1,${.5 + yp}` }, - '╨': { [Style.NORMAL]: (xp, yp) => `${Shapes.LEFT_TO_RIGHT} M${.5 - xp},.5 L${.5 - xp},0 M${.5 + xp},.5 L${.5 + xp},0` }, - '╩': { [Style.NORMAL]: (xp, yp) => `M0,${.5 + yp} L1,${.5 + yp} M0,${.5 - yp} L${.5 - xp},${.5 - yp} L${.5 - xp},0 M1,${.5 - yp} L${.5 + xp},${.5 - yp} L${.5 + xp},0` }, - '╪': { [Style.NORMAL]: (xp, yp) => `${Shapes.TOP_TO_BOTTOM} M0,${.5 - yp} L1,${.5 - yp} M0,${.5 + yp} L1,${.5 + yp}` }, - '╫': { [Style.NORMAL]: (xp, yp) => `${Shapes.LEFT_TO_RIGHT} M${.5 - xp},0 L${.5 - xp},1 M${.5 + xp},0 L${.5 + xp},1` }, - '╬': { [Style.NORMAL]: (xp, yp) => `M0,${.5 + yp} L${.5 - xp},${.5 + yp} L${.5 - xp},1 M1,${.5 + yp} L${.5 + xp},${.5 + yp} L${.5 + xp},1 M0,${.5 - yp} L${.5 - xp},${.5 - yp} L${.5 - xp},0 M1,${.5 - yp} L${.5 + xp},${.5 - yp} L${.5 + xp},0` }, - - // Diagonal - '╱': { [Style.NORMAL]: 'M1,0 L0,1' }, - '╲': { [Style.NORMAL]: 'M0,0 L1,1' }, - '╳': { [Style.NORMAL]: 'M1,0 L0,1 M0,0 L1,1' }, - - // Mixed weight - '╼': { [Style.NORMAL]: Shapes.MIDDLE_TO_LEFT, [Style.BOLD]: Shapes.MIDDLE_TO_RIGHT }, - '╽': { [Style.NORMAL]: Shapes.MIDDLE_TO_TOP, [Style.BOLD]: Shapes.MIDDLE_TO_BOTTOM }, - '╾': { [Style.NORMAL]: Shapes.MIDDLE_TO_RIGHT, [Style.BOLD]: Shapes.MIDDLE_TO_LEFT }, - '╿': { [Style.NORMAL]: Shapes.MIDDLE_TO_BOTTOM, [Style.BOLD]: Shapes.MIDDLE_TO_TOP }, - '┍': { [Style.NORMAL]: Shapes.MIDDLE_TO_BOTTOM, [Style.BOLD]: Shapes.MIDDLE_TO_RIGHT }, - '┎': { [Style.NORMAL]: Shapes.MIDDLE_TO_RIGHT, [Style.BOLD]: Shapes.MIDDLE_TO_BOTTOM }, - '┑': { [Style.NORMAL]: Shapes.MIDDLE_TO_BOTTOM, [Style.BOLD]: Shapes.MIDDLE_TO_LEFT }, - '┒': { [Style.NORMAL]: Shapes.MIDDLE_TO_LEFT, [Style.BOLD]: Shapes.MIDDLE_TO_BOTTOM }, - '┕': { [Style.NORMAL]: Shapes.MIDDLE_TO_TOP, [Style.BOLD]: Shapes.MIDDLE_TO_RIGHT }, - '┖': { [Style.NORMAL]: Shapes.MIDDLE_TO_RIGHT, [Style.BOLD]: Shapes.MIDDLE_TO_TOP }, - '┙': { [Style.NORMAL]: Shapes.MIDDLE_TO_TOP, [Style.BOLD]: Shapes.MIDDLE_TO_LEFT }, - '┚': { [Style.NORMAL]: Shapes.MIDDLE_TO_LEFT, [Style.BOLD]: Shapes.MIDDLE_TO_TOP }, - '┝': { [Style.NORMAL]: Shapes.TOP_TO_BOTTOM, [Style.BOLD]: Shapes.MIDDLE_TO_RIGHT }, - '┞': { [Style.NORMAL]: Shapes.RIGHT_TO_BOTTOM, [Style.BOLD]: Shapes.MIDDLE_TO_TOP }, - '┟': { [Style.NORMAL]: Shapes.TOP_TO_RIGHT, [Style.BOLD]: Shapes.MIDDLE_TO_BOTTOM }, - '┠': { [Style.NORMAL]: Shapes.MIDDLE_TO_RIGHT, [Style.BOLD]: Shapes.TOP_TO_BOTTOM }, - '┡': { [Style.NORMAL]: Shapes.MIDDLE_TO_BOTTOM, [Style.BOLD]: Shapes.TOP_TO_RIGHT }, - '┢': { [Style.NORMAL]: Shapes.MIDDLE_TO_TOP, [Style.BOLD]: Shapes.RIGHT_TO_BOTTOM }, - '┥': { [Style.NORMAL]: Shapes.TOP_TO_BOTTOM, [Style.BOLD]: Shapes.MIDDLE_TO_LEFT }, - '┦': { [Style.NORMAL]: Shapes.LEFT_TO_BOTTOM, [Style.BOLD]: Shapes.MIDDLE_TO_TOP }, - '┧': { [Style.NORMAL]: Shapes.TOP_TO_LEFT, [Style.BOLD]: Shapes.MIDDLE_TO_BOTTOM }, - '┨': { [Style.NORMAL]: Shapes.MIDDLE_TO_LEFT, [Style.BOLD]: Shapes.TOP_TO_BOTTOM }, - '┩': { [Style.NORMAL]: Shapes.MIDDLE_TO_BOTTOM, [Style.BOLD]: Shapes.TOP_TO_LEFT }, - '┪': { [Style.NORMAL]: Shapes.MIDDLE_TO_TOP, [Style.BOLD]: Shapes.LEFT_TO_BOTTOM }, - '┭': { [Style.NORMAL]: Shapes.RIGHT_TO_BOTTOM, [Style.BOLD]: Shapes.MIDDLE_TO_LEFT }, - '┮': { [Style.NORMAL]: Shapes.LEFT_TO_BOTTOM, [Style.BOLD]: Shapes.MIDDLE_TO_RIGHT }, - '┯': { [Style.NORMAL]: Shapes.MIDDLE_TO_BOTTOM, [Style.BOLD]: Shapes.LEFT_TO_RIGHT }, - '┰': { [Style.NORMAL]: Shapes.LEFT_TO_RIGHT, [Style.BOLD]: Shapes.MIDDLE_TO_BOTTOM }, - '┱': { [Style.NORMAL]: Shapes.MIDDLE_TO_RIGHT, [Style.BOLD]: Shapes.LEFT_TO_BOTTOM }, - '┲': { [Style.NORMAL]: Shapes.MIDDLE_TO_LEFT, [Style.BOLD]: Shapes.RIGHT_TO_BOTTOM }, - '┵': { [Style.NORMAL]: Shapes.TOP_TO_RIGHT, [Style.BOLD]: Shapes.MIDDLE_TO_LEFT }, - '┶': { [Style.NORMAL]: Shapes.TOP_TO_LEFT, [Style.BOLD]: Shapes.MIDDLE_TO_RIGHT }, - '┷': { [Style.NORMAL]: Shapes.MIDDLE_TO_TOP, [Style.BOLD]: Shapes.LEFT_TO_RIGHT }, - '┸': { [Style.NORMAL]: Shapes.LEFT_TO_RIGHT, [Style.BOLD]: Shapes.MIDDLE_TO_TOP }, - '┹': { [Style.NORMAL]: Shapes.MIDDLE_TO_RIGHT, [Style.BOLD]: Shapes.TOP_TO_LEFT }, - '┺': { [Style.NORMAL]: Shapes.MIDDLE_TO_LEFT, [Style.BOLD]: Shapes.TOP_TO_RIGHT }, - '┽': { [Style.NORMAL]: `${Shapes.TOP_TO_BOTTOM} ${Shapes.MIDDLE_TO_RIGHT}`, [Style.BOLD]: Shapes.MIDDLE_TO_LEFT }, - '┾': { [Style.NORMAL]: `${Shapes.TOP_TO_BOTTOM} ${Shapes.MIDDLE_TO_LEFT}`, [Style.BOLD]: Shapes.MIDDLE_TO_RIGHT }, - '┿': { [Style.NORMAL]: Shapes.TOP_TO_BOTTOM, [Style.BOLD]: Shapes.LEFT_TO_RIGHT }, - '╀': { [Style.NORMAL]: `${Shapes.LEFT_TO_RIGHT} ${Shapes.MIDDLE_TO_BOTTOM}`, [Style.BOLD]: Shapes.MIDDLE_TO_TOP }, - '╁': { [Style.NORMAL]: `${Shapes.MIDDLE_TO_TOP} ${Shapes.LEFT_TO_RIGHT}`, [Style.BOLD]: Shapes.MIDDLE_TO_BOTTOM }, - '╂': { [Style.NORMAL]: Shapes.LEFT_TO_RIGHT, [Style.BOLD]: Shapes.TOP_TO_BOTTOM }, - '╃': { [Style.NORMAL]: Shapes.RIGHT_TO_BOTTOM, [Style.BOLD]: Shapes.TOP_TO_LEFT }, - '╄': { [Style.NORMAL]: Shapes.LEFT_TO_BOTTOM, [Style.BOLD]: Shapes.TOP_TO_RIGHT }, - '╅': { [Style.NORMAL]: Shapes.TOP_TO_RIGHT, [Style.BOLD]: Shapes.LEFT_TO_BOTTOM }, - '╆': { [Style.NORMAL]: Shapes.TOP_TO_LEFT, [Style.BOLD]: Shapes.RIGHT_TO_BOTTOM }, - '╇': { [Style.NORMAL]: Shapes.MIDDLE_TO_BOTTOM, [Style.BOLD]: `${Shapes.MIDDLE_TO_TOP} ${Shapes.LEFT_TO_RIGHT}` }, - '╈': { [Style.NORMAL]: Shapes.MIDDLE_TO_TOP, [Style.BOLD]: `${Shapes.LEFT_TO_RIGHT} ${Shapes.MIDDLE_TO_BOTTOM}` }, - '╉': { [Style.NORMAL]: Shapes.MIDDLE_TO_RIGHT, [Style.BOLD]: `${Shapes.TOP_TO_BOTTOM} ${Shapes.MIDDLE_TO_LEFT}` }, - '╊': { [Style.NORMAL]: Shapes.MIDDLE_TO_LEFT, [Style.BOLD]: `${Shapes.TOP_TO_BOTTOM} ${Shapes.MIDDLE_TO_RIGHT}` }, - - // Dashed - '╌': { [Style.NORMAL]: Shapes.TWO_DASHES_HORIZONTAL }, - '╍': { [Style.BOLD]: Shapes.TWO_DASHES_HORIZONTAL }, - '┄': { [Style.NORMAL]: Shapes.THREE_DASHES_HORIZONTAL }, - '┅': { [Style.BOLD]: Shapes.THREE_DASHES_HORIZONTAL }, - '┈': { [Style.NORMAL]: Shapes.FOUR_DASHES_HORIZONTAL }, - '┉': { [Style.BOLD]: Shapes.FOUR_DASHES_HORIZONTAL }, - '╎': { [Style.NORMAL]: Shapes.TWO_DASHES_VERTICAL }, - '╏': { [Style.BOLD]: Shapes.TWO_DASHES_VERTICAL }, - '┆': { [Style.NORMAL]: Shapes.THREE_DASHES_VERTICAL }, - '┇': { [Style.BOLD]: Shapes.THREE_DASHES_VERTICAL }, - '┊': { [Style.NORMAL]: Shapes.FOUR_DASHES_VERTICAL }, - '┋': { [Style.BOLD]: Shapes.FOUR_DASHES_VERTICAL }, - - // Curved - '╭': { [Style.NORMAL]: 'C.5,1,.5,.5,1,.5' }, - '╮': { [Style.NORMAL]: 'C.5,1,.5,.5,0,.5' }, - '╯': { [Style.NORMAL]: 'C.5,0,.5,.5,0,.5' }, - '╰': { [Style.NORMAL]: 'C.5,0,.5,.5,1,.5' } -}; - -/** - * Try drawing a custom block element or box drawing character, returning whether it was - * successfully drawn. - */ -export function tryDrawCustomChar( - ctx: CanvasRenderingContext2D, - c: string, - xOffset: number, - yOffset: number, - scaledCellWidth: number, - scaledCellHeight: number -): boolean { - const blockElementDefinition = blockElementDefinitions[c]; - if (blockElementDefinition) { - drawBlockElementChar(ctx, blockElementDefinition, xOffset, yOffset, scaledCellWidth, scaledCellHeight); - return true; - } - - const patternDefinition = patternCharacterDefinitions[c]; - if (patternDefinition) { - drawPatternChar(ctx, patternDefinition, xOffset, yOffset, scaledCellWidth, scaledCellHeight); - return true; - } - - const boxDrawingDefinition = boxDrawingDefinitions[c]; - if (boxDrawingDefinition) { - drawBoxDrawingChar(ctx, boxDrawingDefinition, xOffset, yOffset, scaledCellWidth, scaledCellHeight); - return true; - } - - return false; -} - -function drawBlockElementChar( - ctx: CanvasRenderingContext2D, - charDefinition: IBlockVector[], - xOffset: number, - yOffset: number, - scaledCellWidth: number, - scaledCellHeight: number -): void { - for (let i = 0; i < charDefinition.length; i++) { - const box = charDefinition[i]; - const xEighth = scaledCellWidth / 8; - const yEighth = scaledCellHeight / 8; - ctx.fillRect( - xOffset + box.x * xEighth, - yOffset + box.y * yEighth, - box.w * xEighth, - box.h * yEighth - ); - } -} - -const cachedPatterns: Map<PatternDefinition, Map</* fillStyle */string, CanvasPattern>> = new Map(); - -function drawPatternChar( - ctx: CanvasRenderingContext2D, - charDefinition: number[][], - xOffset: number, - yOffset: number, - scaledCellWidth: number, - scaledCellHeight: number -): void { - let patternSet = cachedPatterns.get(charDefinition); - if (!patternSet) { - patternSet = new Map(); - cachedPatterns.set(charDefinition, patternSet); - } - const fillStyle = ctx.fillStyle; - if (typeof fillStyle !== 'string') { - throw new Error(`Unexpected fillStyle type "${fillStyle}"`); - } - let pattern = patternSet.get(fillStyle); - if (!pattern) { - const width = charDefinition[0].length; - const height = charDefinition.length; - const tmpCanvas = document.createElement('canvas'); - tmpCanvas.width = width; - tmpCanvas.height = height; - const tmpCtx = throwIfFalsy(tmpCanvas.getContext('2d')); - const imageData = new ImageData(width, height); - - // Extract rgba from fillStyle - let r: number; - let g: number; - let b: number; - let a: number; - if (fillStyle.startsWith('#')) { - r = parseInt(fillStyle.substr(1, 2), 16); - g = parseInt(fillStyle.substr(3, 2), 16); - b = parseInt(fillStyle.substr(5, 2), 16); - a = fillStyle.length > 7 && parseInt(fillStyle.substr(7, 2), 16) || 1; - } else if (fillStyle.startsWith('rgba')) { - ([r, g, b, a] = fillStyle.substring(5, fillStyle.length - 1).split(',').map(e => parseFloat(e))); - } else { - throw new Error(`Unexpected fillStyle color format "${fillStyle}" when drawing pattern glyph`); - } - - for (let y = 0; y < height; y++) { - for (let x = 0; x < width; x++) { - imageData.data[(y * width + x) * 4 ] = r; - imageData.data[(y * width + x) * 4 + 1] = g; - imageData.data[(y * width + x) * 4 + 2] = b; - imageData.data[(y * width + x) * 4 + 3] = charDefinition[y][x] * (a * 255); - } - } - tmpCtx.putImageData(imageData, 0, 0); - pattern = throwIfFalsy(ctx.createPattern(tmpCanvas, null)); - patternSet.set(fillStyle, pattern); - } - ctx.fillStyle = pattern; - ctx.fillRect(xOffset, yOffset, scaledCellWidth, scaledCellHeight); -} - -/** - * Draws the following box drawing characters by mapping a subset of SVG d attribute instructions to - * canvas draw calls. - * - * Box styles: ┎┰┒┍┯┑╓╥╖╒╤╕ ┏┳┓┌┲┓┌┬┐┏┱┐ - * ┌─┬─┐ ┏━┳━┓ ╔═╦═╗ ┠╂┨┝┿┥╟╫╢╞╪╡ ┡╇┩├╊┫┢╈┪┣╉┤ - * │ │ │ ┃ ┃ ┃ ║ ║ ║ ┖┸┚┕┷┙╙╨╜╘╧╛ └┴┘└┺┛┗┻┛┗┹┘ - * ├─┼─┤ ┣━╋━┫ ╠═╬═╣ ┏┱┐┌┲┓┌┬┐┌┬┐ ┏┳┓┌┮┓┌┬┐┏┭┐ - * │ │ │ ┃ ┃ ┃ ║ ║ ║ ┡╃┤├╄┩├╆┪┢╅┤ ┞╀┦├┾┫┟╁┧┣┽┤ - * └─┴─┘ ┗━┻━┛ ╚═╩═╝ └┴┘└┴┘└┺┛┗┹┘ └┴┘└┶┛┗┻┛┗┵┘ - * - * Other: - * ╭─╮ ╲ ╱ ╷╻╎╏┆┇┊┋ ╺╾╴ ╌╌╌ ┄┄┄ ┈┈┈ - * │ │ ╳ ╽╿╎╏┆┇┊┋ ╶╼╸ ╍╍╍ ┅┅┅ ┉┉┉ - * ╰─╯ ╱ ╲ ╹╵╎╏┆┇┊┋ - * - * All box drawing characters: - * ─ ━ │ ┃ ┄ ┅ ┆ ┇ ┈ ┉ ┊ ┋ ┌ ┍ ┎ ┏ - * ┐ ┑ ┒ ┓ └ ┕ ┖ ┗ ┘ ┙ ┚ ┛ ├ ┝ ┞ ┟ - * ┠ ┡ ┢ ┣ ┤ ┥ ┦ ┧ ┨ ┩ ┪ ┫ ┬ ┭ ┮ ┯ - * ┰ ┱ ┲ ┳ ┴ ┵ ┶ ┷ ┸ ┹ ┺ ┻ ┼ ┽ ┾ ┿ - * ╀ ╁ ╂ ╃ ╄ ╅ ╆ ╇ ╈ ╉ ╊ ╋ ╌ ╍ ╎ ╏ - * ═ ║ ╒ ╓ ╔ ╕ ╖ ╗ ╘ ╙ ╚ ╛ ╜ ╝ ╞ ╟ - * ╠ ╡ ╢ ╣ ╤ ╥ ╦ ╧ ╨ ╩ ╪ ╫ ╬ ╭ ╮ ╯ - * ╰ ╱ ╲ ╳ ╴ ╵ ╶ ╷ ╸ ╹ ╺ ╻ ╼ ╽ ╾ ╿ - * - * --- - * - * Box drawing alignment tests: █ - * ▉ - * ╔══╦══╗ ┌──┬──┐ ╭──┬──╮ ╭──┬──╮ ┏━━┳━━┓ ┎┒┏┑ ╷ ╻ ┏┯┓ ┌┰┐ ▊ ╱╲╱╲╳╳╳ - * ║┌─╨─┐║ │╔═╧═╗│ │╒═╪═╕│ │╓─╁─╖│ ┃┌─╂─┐┃ ┗╃╄┙ ╶┼╴╺╋╸┠┼┨ ┝╋┥ ▋ ╲╱╲╱╳╳╳ - * ║│╲ ╱│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╿ │┃ ┍╅╆┓ ╵ ╹ ┗┷┛ └┸┘ ▌ ╱╲╱╲╳╳╳ - * ╠╡ ╳ ╞╣ ├╢ ╟┤ ├┼─┼─┼┤ ├╫─╂─╫┤ ┣┿╾┼╼┿┫ ┕┛┖┚ ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳ - * ║│╱ ╲│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╽ │┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▎ - * ║└─╥─┘║ │╚═╤═╝│ │╘═╪═╛│ │╙─╀─╜│ ┃└─╂─┘┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▏ - * ╚══╩══╝ └──┴──┘ ╰──┴──╯ ╰──┴──╯ ┗━━┻━━┛ └╌╌┘ ╎ ┗╍╍┛ ┋ ▁▂▃▄▅▆▇█ - * - * Source: https://www.w3.org/2001/06/utf-8-test/UTF-8-demo.html - */ -function drawBoxDrawingChar( - ctx: CanvasRenderingContext2D, - charDefinition: { [fontWeight: number]: string | ((xp: number, yp: number) => string) }, - xOffset: number, - yOffset: number, - scaledCellWidth: number, - scaledCellHeight: number -): void { - ctx.strokeStyle = ctx.fillStyle; - for (const [fontWeight, instructions] of Object.entries(charDefinition)) { - ctx.beginPath(); - ctx.lineWidth = window.devicePixelRatio * Number.parseInt(fontWeight); - let actualInstructions: string; - if (typeof instructions === 'function') { - const xp = .15; - const yp = .15 / scaledCellHeight * scaledCellWidth; - actualInstructions = instructions(xp, yp); - } else { - actualInstructions = instructions; - } - for (const instruction of actualInstructions.split(' ')) { - const type = instruction[0]; - const f = svgToCanvasInstructionMap[type]; - if (!f) { - console.error(`Could not find drawing instructions for "${type}"`); - continue; - } - const args: string[] = instruction.substring(1).split(','); - if (!args[0] || !args[1]) { - continue; - } - f(ctx, translateArgs(args, scaledCellWidth, scaledCellHeight, xOffset, yOffset)); - } - ctx.stroke(); - ctx.closePath(); - } -} - -function clamp(value: number, max: number, min: number = 0): number { - return Math.max(Math.min(value, max), min); -} - -const svgToCanvasInstructionMap: { [index: string]: any } = { - 'C': (ctx: CanvasRenderingContext2D, args: number[]) => ctx.bezierCurveTo(args[0], args[1], args[2], args[3], args[4], args[5]), - 'L': (ctx: CanvasRenderingContext2D, args: number[]) => ctx.lineTo(args[0], args[1]), - 'M': (ctx: CanvasRenderingContext2D, args: number[]) => ctx.moveTo(args[0], args[1]) -}; - -function translateArgs(args: string[], cellWidth: number, cellHeight: number, xOffset: number, yOffset: number): number[] { - const result = args.map(e => parseFloat(e) || parseInt(e)); - - if (result.length < 2) { - throw new Error('Too few arguments for instruction'); - } - - for (let x = 0; x < result.length; x += 2) { - // Translate from 0-1 to 0-cellWidth - result[x] *= cellWidth; - // Ensure coordinate doesn't escape cell bounds and round to the nearest 0.5 to ensure a crisp - // line at 100% devicePixelRatio - if (result[x] !== 0) { - result[x] = clamp(Math.round(result[x] + 0.5) - 0.5, cellWidth, 0); - } - // Apply the cell's offset (ie. x*cellWidth) - result[x] += xOffset; - } - - for (let y = 1; y < result.length; y += 2) { - // Translate from 0-1 to 0-cellHeight - result[y] *= cellHeight; - // Ensure coordinate doesn't escape cell bounds and round to the nearest 0.5 to ensure a crisp - // line at 100% devicePixelRatio - if (result[y] !== 0) { - result[y] = clamp(Math.round(result[y] + 0.5) - 0.5, cellHeight, 0); - } - // Apply the cell's offset (ie. x*cellHeight) - result[y] += yOffset; - } - - return result; -} diff --git a/node_modules/xterm/src/browser/renderer/GridCache.ts b/node_modules/xterm/src/browser/renderer/GridCache.ts deleted file mode 100644 index b48798d..0000000 --- a/node_modules/xterm/src/browser/renderer/GridCache.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -export class GridCache<T> { - public cache: (T | undefined)[][]; - - public constructor() { - this.cache = []; - } - - public resize(width: number, height: number): void { - for (let x = 0; x < width; x++) { - if (this.cache.length <= x) { - this.cache.push([]); - } - for (let y = this.cache[x].length; y < height; y++) { - this.cache[x].push(undefined); - } - this.cache[x].length = height; - } - this.cache.length = width; - } - - public clear(): void { - for (let x = 0; x < this.cache.length; x++) { - for (let y = 0; y < this.cache[x].length; y++) { - this.cache[x][y] = undefined; - } - } - } -} diff --git a/node_modules/xterm/src/browser/renderer/LinkRenderLayer.ts b/node_modules/xterm/src/browser/renderer/LinkRenderLayer.ts deleted file mode 100644 index 2492f92..0000000 --- a/node_modules/xterm/src/browser/renderer/LinkRenderLayer.ts +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IRenderDimensions } from 'browser/renderer/Types'; -import { BaseRenderLayer } from './BaseRenderLayer'; -import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; -import { is256Color } from 'browser/renderer/atlas/CharAtlasUtils'; -import { IColorSet, ILinkifierEvent, ILinkifier, ILinkifier2 } from 'browser/Types'; -import { IBufferService, IOptionsService } from 'common/services/Services'; - -export class LinkRenderLayer extends BaseRenderLayer { - private _state: ILinkifierEvent | undefined; - - constructor( - container: HTMLElement, - zIndex: number, - colors: IColorSet, - rendererId: number, - linkifier: ILinkifier, - linkifier2: ILinkifier2, - @IBufferService bufferService: IBufferService, - @IOptionsService optionsService: IOptionsService - ) { - super(container, 'link', zIndex, true, colors, rendererId, bufferService, optionsService); - linkifier.onShowLinkUnderline(e => this._onShowLinkUnderline(e)); - linkifier.onHideLinkUnderline(e => this._onHideLinkUnderline(e)); - - linkifier2.onShowLinkUnderline(e => this._onShowLinkUnderline(e)); - linkifier2.onHideLinkUnderline(e => this._onHideLinkUnderline(e)); - } - - public resize(dim: IRenderDimensions): void { - super.resize(dim); - // Resizing the canvas discards the contents of the canvas so clear state - this._state = undefined; - } - - public reset(): void { - this._clearCurrentLink(); - } - - private _clearCurrentLink(): void { - if (this._state) { - this._clearCells(this._state.x1, this._state.y1, this._state.cols - this._state.x1, 1); - const middleRowCount = this._state.y2 - this._state.y1 - 1; - if (middleRowCount > 0) { - this._clearCells(0, this._state.y1 + 1, this._state.cols, middleRowCount); - } - this._clearCells(0, this._state.y2, this._state.x2, 1); - this._state = undefined; - } - } - - private _onShowLinkUnderline(e: ILinkifierEvent): void { - if (e.fg === INVERTED_DEFAULT_COLOR) { - this._ctx.fillStyle = this._colors.background.css; - } else if (e.fg && is256Color(e.fg)) { - // 256 color support - this._ctx.fillStyle = this._colors.ansi[e.fg].css; - } else { - this._ctx.fillStyle = this._colors.foreground.css; - } - - if (e.y1 === e.y2) { - // Single line link - this._fillBottomLineAtCells(e.x1, e.y1, e.x2 - e.x1); - } else { - // Multi-line link - this._fillBottomLineAtCells(e.x1, e.y1, e.cols - e.x1); - for (let y = e.y1 + 1; y < e.y2; y++) { - this._fillBottomLineAtCells(0, y, e.cols); - } - this._fillBottomLineAtCells(0, e.y2, e.x2); - } - this._state = e; - } - - private _onHideLinkUnderline(e: ILinkifierEvent): void { - this._clearCurrentLink(); - } -} diff --git a/node_modules/xterm/src/browser/renderer/Renderer.ts b/node_modules/xterm/src/browser/renderer/Renderer.ts deleted file mode 100644 index a58893b..0000000 --- a/node_modules/xterm/src/browser/renderer/Renderer.ts +++ /dev/null @@ -1,216 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { TextRenderLayer } from 'browser/renderer/TextRenderLayer'; -import { SelectionRenderLayer } from 'browser/renderer/SelectionRenderLayer'; -import { CursorRenderLayer } from 'browser/renderer/CursorRenderLayer'; -import { IRenderLayer, IRenderer, IRenderDimensions, IRequestRedrawEvent } from 'browser/renderer/Types'; -import { LinkRenderLayer } from 'browser/renderer/LinkRenderLayer'; -import { Disposable } from 'common/Lifecycle'; -import { IColorSet, ILinkifier, ILinkifier2 } from 'browser/Types'; -import { ICharSizeService } from 'browser/services/Services'; -import { IBufferService, IOptionsService, IInstantiationService } from 'common/services/Services'; -import { removeTerminalFromCache } from 'browser/renderer/atlas/CharAtlasCache'; -import { EventEmitter, IEvent } from 'common/EventEmitter'; -import { IDecorationOptions, IDecoration } from 'xterm'; - -let nextRendererId = 1; - -export class Renderer extends Disposable implements IRenderer { - private _id = nextRendererId++; - - private _renderLayers: IRenderLayer[]; - private _devicePixelRatio: number; - - public dimensions: IRenderDimensions; - - private _onRequestRedraw = new EventEmitter<IRequestRedrawEvent>(); - public get onRequestRedraw(): IEvent<IRequestRedrawEvent> { return this._onRequestRedraw.event; } - - constructor( - private _colors: IColorSet, - private readonly _screenElement: HTMLElement, - linkifier: ILinkifier, - linkifier2: ILinkifier2, - @IInstantiationService instantiationService: IInstantiationService, - @IBufferService private readonly _bufferService: IBufferService, - @ICharSizeService private readonly _charSizeService: ICharSizeService, - @IOptionsService private readonly _optionsService: IOptionsService - ) { - super(); - const allowTransparency = this._optionsService.rawOptions.allowTransparency; - this._renderLayers = [ - instantiationService.createInstance(TextRenderLayer, this._screenElement, 0, this._colors, allowTransparency, this._id), - instantiationService.createInstance(SelectionRenderLayer, this._screenElement, 1, this._colors, this._id), - instantiationService.createInstance(LinkRenderLayer, this._screenElement, 2, this._colors, this._id, linkifier, linkifier2), - instantiationService.createInstance(CursorRenderLayer, this._screenElement, 3, this._colors, this._id, this._onRequestRedraw) - ]; - this.dimensions = { - scaledCharWidth: 0, - scaledCharHeight: 0, - scaledCellWidth: 0, - scaledCellHeight: 0, - scaledCharLeft: 0, - scaledCharTop: 0, - scaledCanvasWidth: 0, - scaledCanvasHeight: 0, - canvasWidth: 0, - canvasHeight: 0, - actualCellWidth: 0, - actualCellHeight: 0 - }; - this._devicePixelRatio = window.devicePixelRatio; - this._updateDimensions(); - this.onOptionsChanged(); - } - - public dispose(): void { - for (const l of this._renderLayers) { - l.dispose(); - } - super.dispose(); - removeTerminalFromCache(this._id); - } - - public onDevicePixelRatioChange(): void { - // If the device pixel ratio changed, the char atlas needs to be regenerated - // and the terminal needs to refreshed - if (this._devicePixelRatio !== window.devicePixelRatio) { - this._devicePixelRatio = window.devicePixelRatio; - this.onResize(this._bufferService.cols, this._bufferService.rows); - } - } - - public setColors(colors: IColorSet): void { - this._colors = colors; - // Clear layers and force a full render - for (const l of this._renderLayers) { - l.setColors(this._colors); - l.reset(); - } - } - - public onResize(cols: number, rows: number): void { - // Update character and canvas dimensions - this._updateDimensions(); - - // Resize all render layers - for (const l of this._renderLayers) { - l.resize(this.dimensions); - } - - // Resize the screen - this._screenElement.style.width = `${this.dimensions.canvasWidth}px`; - this._screenElement.style.height = `${this.dimensions.canvasHeight}px`; - } - - public onCharSizeChanged(): void { - this.onResize(this._bufferService.cols, this._bufferService.rows); - } - - public onBlur(): void { - this._runOperation(l => l.onBlur()); - } - - public onFocus(): void { - this._runOperation(l => l.onFocus()); - } - - public onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean = false): void { - this._runOperation(l => l.onSelectionChanged(start, end, columnSelectMode)); - } - - public onCursorMove(): void { - this._runOperation(l => l.onCursorMove()); - } - - public onOptionsChanged(): void { - this._runOperation(l => l.onOptionsChanged()); - } - - public clear(): void { - this._runOperation(l => l.reset()); - } - - private _runOperation(operation: (layer: IRenderLayer) => void): void { - for (const l of this._renderLayers) { - operation(l); - } - } - - /** - * Performs the refresh loop callback, calling refresh only if a refresh is - * necessary before queueing up the next one. - */ - public renderRows(start: number, end: number): void { - for (const l of this._renderLayers) { - l.onGridChanged(start, end); - } - } - - public clearTextureAtlas(): void { - for (const layer of this._renderLayers) { - layer.clearTextureAtlas(); - } - } - - /** - * Recalculates the character and canvas dimensions. - */ - private _updateDimensions(): void { - if (!this._charSizeService.hasValidSize) { - return; - } - - // Calculate the scaled character width. Width is floored as it must be - // drawn to an integer grid in order for the CharAtlas "stamps" to not be - // blurry. When text is drawn to the grid not using the CharAtlas, it is - // clipped to ensure there is no overlap with the next cell. - this.dimensions.scaledCharWidth = Math.floor(this._charSizeService.width * window.devicePixelRatio); - - // Calculate the scaled character height. Height is ceiled in case - // devicePixelRatio is a floating point number in order to ensure there is - // enough space to draw the character to the cell. - this.dimensions.scaledCharHeight = Math.ceil(this._charSizeService.height * window.devicePixelRatio); - - // Calculate the scaled cell height, if lineHeight is not 1 then the value - // will be floored because since lineHeight can never be lower then 1, there - // is a guarentee that the scaled line height will always be larger than - // scaled char height. - this.dimensions.scaledCellHeight = Math.floor(this.dimensions.scaledCharHeight * this._optionsService.rawOptions.lineHeight); - - // Calculate the y coordinate within a cell that text should draw from in - // order to draw in the center of a cell. - this.dimensions.scaledCharTop = this._optionsService.rawOptions.lineHeight === 1 ? 0 : Math.round((this.dimensions.scaledCellHeight - this.dimensions.scaledCharHeight) / 2); - - // Calculate the scaled cell width, taking the letterSpacing into account. - this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth + Math.round(this._optionsService.rawOptions.letterSpacing); - - // Calculate the x coordinate with a cell that text should draw from in - // order to draw in the center of a cell. - this.dimensions.scaledCharLeft = Math.floor(this._optionsService.rawOptions.letterSpacing / 2); - - // Recalculate the canvas dimensions; scaled* define the actual number of - // pixel in the canvas - this.dimensions.scaledCanvasHeight = this._bufferService.rows * this.dimensions.scaledCellHeight; - this.dimensions.scaledCanvasWidth = this._bufferService.cols * this.dimensions.scaledCellWidth; - - // The the size of the canvas on the page. It's very important that this - // rounds to nearest integer and not ceils as browsers often set - // window.devicePixelRatio as something like 1.100000023841858, when it's - // actually 1.1. Ceiling causes blurriness as the backing canvas image is 1 - // pixel too large for the canvas element size. - this.dimensions.canvasHeight = Math.round(this.dimensions.scaledCanvasHeight / window.devicePixelRatio); - this.dimensions.canvasWidth = Math.round(this.dimensions.scaledCanvasWidth / window.devicePixelRatio); - - // Get the _actual_ dimensions of an individual cell. This needs to be - // derived from the canvasWidth/Height calculated above which takes into - // account window.devicePixelRatio. ICharSizeService.width/height by itself - // is insufficient when the page is not at 100% zoom level as it's measured - // in CSS pixels, but the actual char size on the canvas can differ. - this.dimensions.actualCellHeight = this.dimensions.canvasHeight / this._bufferService.rows; - this.dimensions.actualCellWidth = this.dimensions.canvasWidth / this._bufferService.cols; - } -} diff --git a/node_modules/xterm/src/browser/renderer/RendererUtils.ts b/node_modules/xterm/src/browser/renderer/RendererUtils.ts deleted file mode 100644 index 48fd26a..0000000 --- a/node_modules/xterm/src/browser/renderer/RendererUtils.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -export function throwIfFalsy<T>(value: T | undefined | null): T { - if (!value) { - throw new Error('value must not be falsy'); - } - return value; -} diff --git a/node_modules/xterm/src/browser/renderer/SelectionRenderLayer.ts b/node_modules/xterm/src/browser/renderer/SelectionRenderLayer.ts deleted file mode 100644 index 9054e3c..0000000 --- a/node_modules/xterm/src/browser/renderer/SelectionRenderLayer.ts +++ /dev/null @@ -1,128 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IRenderDimensions } from 'browser/renderer/Types'; -import { BaseRenderLayer } from 'browser/renderer/BaseRenderLayer'; -import { IColorSet } from 'browser/Types'; -import { IBufferService, IOptionsService } from 'common/services/Services'; - -interface ISelectionState { - start?: [number, number]; - end?: [number, number]; - columnSelectMode?: boolean; - ydisp?: number; -} - -export class SelectionRenderLayer extends BaseRenderLayer { - private _state!: ISelectionState; - - constructor( - container: HTMLElement, - zIndex: number, - colors: IColorSet, - rendererId: number, - @IBufferService bufferService: IBufferService, - @IOptionsService optionsService: IOptionsService - ) { - super(container, 'selection', zIndex, true, colors, rendererId, bufferService, optionsService); - this._clearState(); - } - - private _clearState(): void { - this._state = { - start: undefined, - end: undefined, - columnSelectMode: undefined, - ydisp: undefined - }; - } - - public resize(dim: IRenderDimensions): void { - super.resize(dim); - // Resizing the canvas discards the contents of the canvas so clear state - this._clearState(); - } - - public reset(): void { - if (this._state.start && this._state.end) { - this._clearState(); - this._clearAll(); - } - } - - public onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void { - // Selection has not changed - if (!this._didStateChange(start, end, columnSelectMode, this._bufferService.buffer.ydisp)) { - return; - } - - // Remove all selections - this._clearAll(); - - // Selection does not exist - if (!start || !end) { - this._clearState(); - return; - } - - // Translate from buffer position to viewport position - const viewportStartRow = start[1] - this._bufferService.buffer.ydisp; - const viewportEndRow = end[1] - this._bufferService.buffer.ydisp; - const viewportCappedStartRow = Math.max(viewportStartRow, 0); - const viewportCappedEndRow = Math.min(viewportEndRow, this._bufferService.rows - 1); - - // No need to draw the selection - if (viewportCappedStartRow >= this._bufferService.rows || viewportCappedEndRow < 0) { - this._state.ydisp = this._bufferService.buffer.ydisp; - return; - } - - this._ctx.fillStyle = this._colors.selectionTransparent.css; - - if (columnSelectMode) { - const startCol = start[0]; - const width = end[0] - startCol; - const height = viewportCappedEndRow - viewportCappedStartRow + 1; - this._fillCells(startCol, viewportCappedStartRow, width, height); - } else { - // Draw first row - const startCol = viewportStartRow === viewportCappedStartRow ? start[0] : 0; - const startRowEndCol = viewportCappedStartRow === viewportEndRow ? end[0] : this._bufferService.cols; - this._fillCells(startCol, viewportCappedStartRow, startRowEndCol - startCol, 1); - - // Draw middle rows - const middleRowsCount = Math.max(viewportCappedEndRow - viewportCappedStartRow - 1, 0); - this._fillCells(0, viewportCappedStartRow + 1, this._bufferService.cols, middleRowsCount); - - // Draw final row - if (viewportCappedStartRow !== viewportCappedEndRow) { - // Only draw viewportEndRow if it's not the same as viewportStartRow - const endCol = viewportEndRow === viewportCappedEndRow ? end[0] : this._bufferService.cols; - this._fillCells(0, viewportCappedEndRow, endCol, 1); - } - } - - // Save state for next render - this._state.start = [start[0], start[1]]; - this._state.end = [end[0], end[1]]; - this._state.columnSelectMode = columnSelectMode; - this._state.ydisp = this._bufferService.buffer.ydisp; - } - - private _didStateChange(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean, ydisp: number): boolean { - return !this._areCoordinatesEqual(start, this._state.start) || - !this._areCoordinatesEqual(end, this._state.end) || - columnSelectMode !== this._state.columnSelectMode || - ydisp !== this._state.ydisp; - } - - private _areCoordinatesEqual(coord1: [number, number] | undefined, coord2: [number, number] | undefined): boolean { - if (!coord1 || !coord2) { - return false; - } - - return coord1[0] === coord2[0] && coord1[1] === coord2[1]; - } -} diff --git a/node_modules/xterm/src/browser/renderer/TextRenderLayer.ts b/node_modules/xterm/src/browser/renderer/TextRenderLayer.ts deleted file mode 100644 index 33d942f..0000000 --- a/node_modules/xterm/src/browser/renderer/TextRenderLayer.ts +++ /dev/null @@ -1,330 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IRenderDimensions } from 'browser/renderer/Types'; -import { CharData, ICellData } from 'common/Types'; -import { GridCache } from 'browser/renderer/GridCache'; -import { BaseRenderLayer } from 'browser/renderer/BaseRenderLayer'; -import { AttributeData } from 'common/buffer/AttributeData'; -import { NULL_CELL_CODE, Content } from 'common/buffer/Constants'; -import { IColorSet } from 'browser/Types'; -import { CellData } from 'common/buffer/CellData'; -import { IOptionsService, IBufferService } from 'common/services/Services'; -import { ICharacterJoinerService } from 'browser/services/Services'; -import { JoinedCellData } from 'browser/services/CharacterJoinerService'; - -/** - * This CharData looks like a null character, which will forc a clear and render - * when the character changes (a regular space ' ' character may not as it's - * drawn state is a cleared cell). - */ -// const OVERLAP_OWNED_CHAR_DATA: CharData = [null, '', 0, -1]; - -export class TextRenderLayer extends BaseRenderLayer { - private _state: GridCache<CharData>; - private _characterWidth: number = 0; - private _characterFont: string = ''; - private _characterOverlapCache: { [key: string]: boolean } = {}; - private _workCell = new CellData(); - - constructor( - container: HTMLElement, - zIndex: number, - colors: IColorSet, - alpha: boolean, - rendererId: number, - @IBufferService bufferService: IBufferService, - @IOptionsService optionsService: IOptionsService, - @ICharacterJoinerService private readonly _characterJoinerService: ICharacterJoinerService - ) { - super(container, 'text', zIndex, alpha, colors, rendererId, bufferService, optionsService); - this._state = new GridCache<CharData>(); - } - - public resize(dim: IRenderDimensions): void { - super.resize(dim); - - // Clear the character width cache if the font or width has changed - const terminalFont = this._getFont(false, false); - if (this._characterWidth !== dim.scaledCharWidth || this._characterFont !== terminalFont) { - this._characterWidth = dim.scaledCharWidth; - this._characterFont = terminalFont; - this._characterOverlapCache = {}; - } - // Resizing the canvas discards the contents of the canvas so clear state - this._state.clear(); - this._state.resize(this._bufferService.cols, this._bufferService.rows); - } - - public reset(): void { - this._state.clear(); - this._clearAll(); - } - - private _forEachCell( - firstRow: number, - lastRow: number, - callback: ( - cell: ICellData, - x: number, - y: number - ) => void - ): void { - for (let y = firstRow; y <= lastRow; y++) { - const row = y + this._bufferService.buffer.ydisp; - const line = this._bufferService.buffer.lines.get(row); - const joinedRanges = this._characterJoinerService.getJoinedCharacters(row); - for (let x = 0; x < this._bufferService.cols; x++) { - line!.loadCell(x, this._workCell); - let cell = this._workCell; - - // If true, indicates that the current character(s) to draw were joined. - let isJoined = false; - let lastCharX = x; - - // The character to the left is a wide character, drawing is owned by - // the char at x-1 - if (cell.getWidth() === 0) { - continue; - } - - // Process any joined character ranges as needed. Because of how the - // ranges are produced, we know that they are valid for the characters - // and attributes of our input. - if (joinedRanges.length > 0 && x === joinedRanges[0][0]) { - isJoined = true; - const range = joinedRanges.shift()!; - - // We already know the exact start and end column of the joined range, - // so we get the string and width representing it directly - cell = new JoinedCellData( - this._workCell, - line!.translateToString(true, range[0], range[1]), - range[1] - range[0] - ); - - // Skip over the cells occupied by this range in the loop - lastCharX = range[1] - 1; - } - - // If the character is an overlapping char and the character to the - // right is a space, take ownership of the cell to the right. We skip - // this check for joined characters because their rendering likely won't - // yield the same result as rendering the last character individually. - if (!isJoined && this._isOverlapping(cell)) { - // If the character is overlapping, we want to force a re-render on every - // frame. This is specifically to work around the case where two - // overlaping chars `a` and `b` are adjacent, the cursor is moved to b and a - // space is added. Without this, the first half of `b` would never - // get removed, and `a` would not re-render because it thinks it's - // already in the correct state. - // this._state.cache[x][y] = OVERLAP_OWNED_CHAR_DATA; - if (lastCharX < line!.length - 1 && line!.getCodePoint(lastCharX + 1) === NULL_CELL_CODE) { - // patch width to 2 - cell.content &= ~Content.WIDTH_MASK; - cell.content |= 2 << Content.WIDTH_SHIFT; - // this._clearChar(x + 1, y); - // The overlapping char's char data will force a clear and render when the - // overlapping char is no longer to the left of the character and also when - // the space changes to another character. - // this._state.cache[x + 1][y] = OVERLAP_OWNED_CHAR_DATA; - } - } - - callback( - cell, - x, - y - ); - - x = lastCharX; - } - } - } - - /** - * Draws the background for a specified range of columns. Tries to batch adjacent cells of the - * same color together to reduce draw calls. - */ - private _drawBackground(firstRow: number, lastRow: number): void { - const ctx = this._ctx; - const cols = this._bufferService.cols; - let startX: number = 0; - let startY: number = 0; - let prevFillStyle: string | null = null; - - ctx.save(); - - this._forEachCell(firstRow, lastRow, (cell, x, y) => { - // libvte and xterm both draw the background (but not foreground) of invisible characters, - // so we should too. - let nextFillStyle = null; // null represents default background color - - if (cell.isInverse()) { - if (cell.isFgDefault()) { - nextFillStyle = this._colors.foreground.css; - } else if (cell.isFgRGB()) { - nextFillStyle = `rgb(${AttributeData.toColorRGB(cell.getFgColor()).join(',')})`; - } else { - nextFillStyle = this._colors.ansi[cell.getFgColor()].css; - } - } else if (cell.isBgRGB()) { - nextFillStyle = `rgb(${AttributeData.toColorRGB(cell.getBgColor()).join(',')})`; - } else if (cell.isBgPalette()) { - nextFillStyle = this._colors.ansi[cell.getBgColor()].css; - } - - if (prevFillStyle === null) { - // This is either the first iteration, or the default background was set. Either way, we - // don't need to draw anything. - startX = x; - startY = y; - } - - if (y !== startY) { - // our row changed, draw the previous row - ctx.fillStyle = prevFillStyle || ''; - this._fillCells(startX, startY, cols - startX, 1); - startX = x; - startY = y; - } else if (prevFillStyle !== nextFillStyle) { - // our color changed, draw the previous characters in this row - ctx.fillStyle = prevFillStyle || ''; - this._fillCells(startX, startY, x - startX, 1); - startX = x; - startY = y; - } - - prevFillStyle = nextFillStyle; - }); - - // flush the last color we encountered - if (prevFillStyle !== null) { - ctx.fillStyle = prevFillStyle; - this._fillCells(startX, startY, cols - startX, 1); - } - - ctx.restore(); - } - - private _drawForeground(firstRow: number, lastRow: number): void { - this._forEachCell(firstRow, lastRow, (cell, x, y) => { - if (cell.isInvisible()) { - return; - } - this._drawChars(cell, x, y); - if (cell.isUnderline() || cell.isStrikethrough()) { - this._ctx.save(); - - if (cell.isInverse()) { - if (cell.isBgDefault()) { - this._ctx.fillStyle = this._colors.background.css; - } else if (cell.isBgRGB()) { - this._ctx.fillStyle = `rgb(${AttributeData.toColorRGB(cell.getBgColor()).join(',')})`; - } else { - let bg = cell.getBgColor(); - if (this._optionsService.rawOptions.drawBoldTextInBrightColors && cell.isBold() && bg < 8) { - bg += 8; - } - this._ctx.fillStyle = this._colors.ansi[bg].css; - } - } else { - if (cell.isFgDefault()) { - this._ctx.fillStyle = this._colors.foreground.css; - } else if (cell.isFgRGB()) { - this._ctx.fillStyle = `rgb(${AttributeData.toColorRGB(cell.getFgColor()).join(',')})`; - } else { - let fg = cell.getFgColor(); - if (this._optionsService.rawOptions.drawBoldTextInBrightColors && cell.isBold() && fg < 8) { - fg += 8; - } - this._ctx.fillStyle = this._colors.ansi[fg].css; - } - } - - if (cell.isStrikethrough()) { - this._fillMiddleLineAtCells(x, y, cell.getWidth()); - } - if (cell.isUnderline()) { - this._fillBottomLineAtCells(x, y, cell.getWidth()); - } - this._ctx.restore(); - } - }); - } - - public onGridChanged(firstRow: number, lastRow: number): void { - // Resize has not been called yet - if (this._state.cache.length === 0) { - return; - } - - if (this._charAtlas) { - this._charAtlas.beginFrame(); - } - - this._clearCells(0, firstRow, this._bufferService.cols, lastRow - firstRow + 1); - this._drawBackground(firstRow, lastRow); - this._drawForeground(firstRow, lastRow); - } - - public onOptionsChanged(): void { - this._setTransparency(this._optionsService.rawOptions.allowTransparency); - } - - /** - * Whether a character is overlapping to the next cell. - */ - private _isOverlapping(cell: ICellData): boolean { - // Only single cell characters can be overlapping, rendering issues can - // occur without this check - if (cell.getWidth() !== 1) { - return false; - } - - // We assume that any ascii character will not overlap - if (cell.getCode() < 256) { - return false; - } - - const chars = cell.getChars(); - - // Deliver from cache if available - if (this._characterOverlapCache.hasOwnProperty(chars)) { - return this._characterOverlapCache[chars]; - } - - // Setup the font - this._ctx.save(); - this._ctx.font = this._characterFont; - - // Measure the width of the character, but Math.floor it - // because that is what the renderer does when it calculates - // the character dimensions we are comparing against - const overlaps = Math.floor(this._ctx.measureText(chars).width) > this._characterWidth; - - // Restore the original context - this._ctx.restore(); - - // Cache and return - this._characterOverlapCache[chars] = overlaps; - return overlaps; - } - - /** - * Clear the charcater at the cell specified. - * @param x The column of the char. - * @param y The row of the char. - */ - // private _clearChar(x: number, y: number): void { - // let colsToClear = 1; - // // Clear the adjacent character if it was wide - // const state = this._state.cache[x][y]; - // if (state && state[CHAR_DATA_WIDTH_INDEX] === 2) { - // colsToClear = 2; - // } - // this.clearCells(x, y, colsToClear, 1); - // } -} diff --git a/node_modules/xterm/src/browser/renderer/Types.d.ts b/node_modules/xterm/src/browser/renderer/Types.d.ts deleted file mode 100644 index 6818a92..0000000 --- a/node_modules/xterm/src/browser/renderer/Types.d.ts +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IDisposable } from 'common/Types'; -import { IColorSet } from 'browser/Types'; -import { IEvent } from 'common/EventEmitter'; - -export interface IRenderDimensions { - scaledCharWidth: number; - scaledCharHeight: number; - scaledCellWidth: number; - scaledCellHeight: number; - scaledCharLeft: number; - scaledCharTop: number; - scaledCanvasWidth: number; - scaledCanvasHeight: number; - canvasWidth: number; - canvasHeight: number; - actualCellWidth: number; - actualCellHeight: number; -} - -export interface IRequestRedrawEvent { - start: number; - end: number; -} - -/** - * Note that IRenderer implementations should emit the refresh event after - * rendering rows to the screen. - */ -export interface IRenderer extends IDisposable { - readonly dimensions: IRenderDimensions; - - /** - * Fires when the renderer is requesting to be redrawn on the next animation - * frame but is _not_ a result of content changing (eg. selection changes). - */ - readonly onRequestRedraw: IEvent<IRequestRedrawEvent>; - - dispose(): void; - setColors(colors: IColorSet): void; - onDevicePixelRatioChange(): void; - onResize(cols: number, rows: number): void; - onCharSizeChanged(): void; - onBlur(): void; - onFocus(): void; - onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void; - onCursorMove(): void; - onOptionsChanged(): void; - clear(): void; - renderRows(start: number, end: number): void; - clearTextureAtlas?(): void; -} - -export interface IRenderLayer extends IDisposable { - /** - * Called when the terminal loses focus. - */ - onBlur(): void; - - /** - * * Called when the terminal gets focus. - */ - onFocus(): void; - - /** - * Called when the cursor is moved. - */ - onCursorMove(): void; - - /** - * Called when options change. - */ - onOptionsChanged(): void; - - /** - * Called when the theme changes. - */ - setColors(colorSet: IColorSet): void; - - /** - * Called when the data in the grid has changed (or needs to be rendered - * again). - */ - onGridChanged(startRow: number, endRow: number): void; - - /** - * Calls when the selection changes. - */ - onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void; - - /** - * Resize the render layer. - */ - resize(dim: IRenderDimensions): void; - - /** - * Clear the state of the render layer. - */ - reset(): void; - - /** - * Clears the texture atlas. - */ - clearTextureAtlas(): void; -} diff --git a/node_modules/xterm/src/browser/renderer/atlas/BaseCharAtlas.ts b/node_modules/xterm/src/browser/renderer/atlas/BaseCharAtlas.ts deleted file mode 100644 index 83c30d2..0000000 --- a/node_modules/xterm/src/browser/renderer/atlas/BaseCharAtlas.ts +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IGlyphIdentifier } from 'browser/renderer/atlas/Types'; -import { IDisposable } from 'common/Types'; - -export abstract class BaseCharAtlas implements IDisposable { - private _didWarmUp: boolean = false; - - public dispose(): void { } - - /** - * Perform any work needed to warm the cache before it can be used. May be called multiple times. - * Implement _doWarmUp instead if you only want to get called once. - */ - public warmUp(): void { - if (!this._didWarmUp) { - this._doWarmUp(); - this._didWarmUp = true; - } - } - - /** - * Perform any work needed to warm the cache before it can be used. Used by the default - * implementation of warmUp(), and will only be called once. - */ - private _doWarmUp(): void { } - - public clear(): void { } - - /** - * Called when we start drawing a new frame. - * - * TODO: We rely on this getting called by TextRenderLayer. This should really be called by - * Renderer instead, but we need to make Renderer the source-of-truth for the char atlas, instead - * of BaseRenderLayer. - */ - public beginFrame(): void { } - - /** - * May be called before warmUp finishes, however it is okay for the implementation to - * do nothing and return false in that case. - * - * @param ctx Where to draw the character onto. - * @param glyph Information about what to draw - * @param x The position on the context to start drawing at - * @param y The position on the context to start drawing at - * @returns The success state. True if we drew the character. - */ - public abstract draw( - ctx: CanvasRenderingContext2D, - glyph: IGlyphIdentifier, - x: number, - y: number - ): boolean; -} diff --git a/node_modules/xterm/src/browser/renderer/atlas/CharAtlasCache.ts b/node_modules/xterm/src/browser/renderer/atlas/CharAtlasCache.ts deleted file mode 100644 index 257835b..0000000 --- a/node_modules/xterm/src/browser/renderer/atlas/CharAtlasCache.ts +++ /dev/null @@ -1,95 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { generateConfig, configEquals } from 'browser/renderer/atlas/CharAtlasUtils'; -import { BaseCharAtlas } from 'browser/renderer/atlas/BaseCharAtlas'; -import { DynamicCharAtlas } from 'browser/renderer/atlas/DynamicCharAtlas'; -import { ICharAtlasConfig } from 'browser/renderer/atlas/Types'; -import { IColorSet } from 'browser/Types'; -import { ITerminalOptions } from 'common/services/Services'; - -interface ICharAtlasCacheEntry { - atlas: BaseCharAtlas; - config: ICharAtlasConfig; - // N.B. This implementation potentially holds onto copies of the terminal forever, so - // this may cause memory leaks. - ownedBy: number[]; -} - -const charAtlasCache: ICharAtlasCacheEntry[] = []; - -/** - * Acquires a char atlas, either generating a new one or returning an existing - * one that is in use by another terminal. - */ -export function acquireCharAtlas( - options: ITerminalOptions, - rendererId: number, - colors: IColorSet, - scaledCharWidth: number, - scaledCharHeight: number -): BaseCharAtlas { - const newConfig = generateConfig(scaledCharWidth, scaledCharHeight, options, colors); - - // Check to see if the renderer already owns this config - for (let i = 0; i < charAtlasCache.length; i++) { - const entry = charAtlasCache[i]; - const ownedByIndex = entry.ownedBy.indexOf(rendererId); - if (ownedByIndex >= 0) { - if (configEquals(entry.config, newConfig)) { - return entry.atlas; - } - // The configs differ, release the renderer from the entry - if (entry.ownedBy.length === 1) { - entry.atlas.dispose(); - charAtlasCache.splice(i, 1); - } else { - entry.ownedBy.splice(ownedByIndex, 1); - } - break; - } - } - - // Try match a char atlas from the cache - for (let i = 0; i < charAtlasCache.length; i++) { - const entry = charAtlasCache[i]; - if (configEquals(entry.config, newConfig)) { - // Add the renderer to the cache entry and return - entry.ownedBy.push(rendererId); - return entry.atlas; - } - } - - const newEntry: ICharAtlasCacheEntry = { - atlas: new DynamicCharAtlas( - document, - newConfig - ), - config: newConfig, - ownedBy: [rendererId] - }; - charAtlasCache.push(newEntry); - return newEntry.atlas; -} - -/** - * Removes a terminal reference from the cache, allowing its memory to be freed. - */ -export function removeTerminalFromCache(rendererId: number): void { - for (let i = 0; i < charAtlasCache.length; i++) { - const index = charAtlasCache[i].ownedBy.indexOf(rendererId); - if (index !== -1) { - if (charAtlasCache[i].ownedBy.length === 1) { - // Remove the cache entry if it's the only renderer - charAtlasCache[i].atlas.dispose(); - charAtlasCache.splice(i, 1); - } else { - // Remove the reference from the cache entry - charAtlasCache[i].ownedBy.splice(index, 1); - } - break; - } - } -} diff --git a/node_modules/xterm/src/browser/renderer/atlas/CharAtlasUtils.ts b/node_modules/xterm/src/browser/renderer/atlas/CharAtlasUtils.ts deleted file mode 100644 index be92727..0000000 --- a/node_modules/xterm/src/browser/renderer/atlas/CharAtlasUtils.ts +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { ICharAtlasConfig } from 'browser/renderer/atlas/Types'; -import { DEFAULT_COLOR } from 'common/buffer/Constants'; -import { IColorSet, IPartialColorSet } from 'browser/Types'; -import { ITerminalOptions } from 'common/services/Services'; - -export function generateConfig(scaledCharWidth: number, scaledCharHeight: number, options: ITerminalOptions, colors: IColorSet): ICharAtlasConfig { - // null out some fields that don't matter - const clonedColors: IPartialColorSet = { - foreground: colors.foreground, - background: colors.background, - cursor: undefined, - cursorAccent: undefined, - selection: undefined, - ansi: [...colors.ansi] - }; - return { - devicePixelRatio: window.devicePixelRatio, - scaledCharWidth, - scaledCharHeight, - fontFamily: options.fontFamily, - fontSize: options.fontSize, - fontWeight: options.fontWeight, - fontWeightBold: options.fontWeightBold, - allowTransparency: options.allowTransparency, - colors: clonedColors - }; -} - -export function configEquals(a: ICharAtlasConfig, b: ICharAtlasConfig): boolean { - for (let i = 0; i < a.colors.ansi.length; i++) { - if (a.colors.ansi[i].rgba !== b.colors.ansi[i].rgba) { - return false; - } - } - return a.devicePixelRatio === b.devicePixelRatio && - a.fontFamily === b.fontFamily && - a.fontSize === b.fontSize && - a.fontWeight === b.fontWeight && - a.fontWeightBold === b.fontWeightBold && - a.allowTransparency === b.allowTransparency && - a.scaledCharWidth === b.scaledCharWidth && - a.scaledCharHeight === b.scaledCharHeight && - a.colors.foreground === b.colors.foreground && - a.colors.background === b.colors.background; -} - -export function is256Color(colorCode: number): boolean { - return colorCode < DEFAULT_COLOR; -} diff --git a/node_modules/xterm/src/browser/renderer/atlas/Constants.ts b/node_modules/xterm/src/browser/renderer/atlas/Constants.ts deleted file mode 100644 index c1701e9..0000000 --- a/node_modules/xterm/src/browser/renderer/atlas/Constants.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { isFirefox, isLegacyEdge } from 'common/Platform'; - -export const INVERTED_DEFAULT_COLOR = 257; -export const DIM_OPACITY = 0.5; -// The text baseline is set conditionally by browser. Using 'ideographic' for Firefox or Legacy Edge would -// result in truncated text (Issue 3353). Using 'bottom' for Chrome would result in slightly -// unaligned Powerline fonts (PR 3356#issuecomment-850928179). -export const TEXT_BASELINE: CanvasTextBaseline = isFirefox || isLegacyEdge ? 'bottom' : 'ideographic'; - -export const CHAR_ATLAS_CELL_SPACING = 1; diff --git a/node_modules/xterm/src/browser/renderer/atlas/DynamicCharAtlas.ts b/node_modules/xterm/src/browser/renderer/atlas/DynamicCharAtlas.ts deleted file mode 100644 index 118dbcd..0000000 --- a/node_modules/xterm/src/browser/renderer/atlas/DynamicCharAtlas.ts +++ /dev/null @@ -1,404 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { DIM_OPACITY, INVERTED_DEFAULT_COLOR, TEXT_BASELINE } from 'browser/renderer/atlas/Constants'; -import { IGlyphIdentifier, ICharAtlasConfig } from 'browser/renderer/atlas/Types'; -import { BaseCharAtlas } from 'browser/renderer/atlas/BaseCharAtlas'; -import { DEFAULT_ANSI_COLORS } from 'browser/ColorManager'; -import { LRUMap } from 'browser/renderer/atlas/LRUMap'; -import { isFirefox, isSafari } from 'common/Platform'; -import { IColor } from 'browser/Types'; -import { throwIfFalsy } from 'browser/renderer/RendererUtils'; -import { color } from 'browser/Color'; - -// In practice we're probably never going to exhaust a texture this large. For debugging purposes, -// however, it can be useful to set this to a really tiny value, to verify that LRU eviction works. -const TEXTURE_WIDTH = 1024; -const TEXTURE_HEIGHT = 1024; - -const TRANSPARENT_COLOR = { - css: 'rgba(0, 0, 0, 0)', - rgba: 0 -}; - -// Drawing to the cache is expensive: If we have to draw more than this number of glyphs to the -// cache in a single frame, give up on trying to cache anything else, and try to finish the current -// frame ASAP. -// -// This helps to limit the amount of damage a program can do when it would otherwise thrash the -// cache. -const FRAME_CACHE_DRAW_LIMIT = 100; - -/** - * The number of milliseconds to wait before generating the ImageBitmap, this is to debounce/batch - * the operation as window.createImageBitmap is asynchronous. - */ -const GLYPH_BITMAP_COMMIT_DELAY = 100; - -interface IGlyphCacheValue { - index: number; - isEmpty: boolean; - inBitmap: boolean; -} - -export function getGlyphCacheKey(glyph: IGlyphIdentifier): number { - // Note that this only returns a valid key when code < 256 - // Layout: - // 0b00000000000000000000000000000001: italic (1) - // 0b00000000000000000000000000000010: dim (1) - // 0b00000000000000000000000000000100: bold (1) - // 0b00000000000000000000111111111000: fg (9) - // 0b00000000000111111111000000000000: bg (9) - // 0b00011111111000000000000000000000: code (8) - // 0b11100000000000000000000000000000: unused (3) - return glyph.code << 21 | glyph.bg << 12 | glyph.fg << 3 | (glyph.bold ? 0 : 4) + (glyph.dim ? 0 : 2) + (glyph.italic ? 0 : 1); -} - -export class DynamicCharAtlas extends BaseCharAtlas { - // An ordered map that we're using to keep track of where each glyph is in the atlas texture. - // It's ordered so that we can determine when to remove the old entries. - private _cacheMap: LRUMap<IGlyphCacheValue>; - - // The texture that the atlas is drawn to - private _cacheCanvas: HTMLCanvasElement; - private _cacheCtx: CanvasRenderingContext2D; - - // A temporary context that glyphs are drawn to before being transfered to the atlas. - private _tmpCtx: CanvasRenderingContext2D; - - // The number of characters stored in the atlas by width/height - private _width: number; - private _height: number; - - private _drawToCacheCount: number = 0; - - // An array of glyph keys that are waiting on the bitmap to be generated. - private _glyphsWaitingOnBitmap: IGlyphCacheValue[] = []; - - // The timeout that is used to batch bitmap generation so it's not requested for every new glyph. - private _bitmapCommitTimeout: number | null = null; - - // The bitmap to draw from, this is much faster on other browsers than others. - private _bitmap: ImageBitmap | null = null; - - constructor(document: Document, private _config: ICharAtlasConfig) { - super(); - this._cacheCanvas = document.createElement('canvas'); - this._cacheCanvas.width = TEXTURE_WIDTH; - this._cacheCanvas.height = TEXTURE_HEIGHT; - // The canvas needs alpha because we use clearColor to convert the background color to alpha. - // It might also contain some characters with transparent backgrounds if allowTransparency is - // set. - this._cacheCtx = throwIfFalsy(this._cacheCanvas.getContext('2d', { alpha: true })); - - const tmpCanvas = document.createElement('canvas'); - tmpCanvas.width = this._config.scaledCharWidth; - tmpCanvas.height = this._config.scaledCharHeight; - this._tmpCtx = throwIfFalsy(tmpCanvas.getContext('2d', { alpha: this._config.allowTransparency })); - - this._width = Math.floor(TEXTURE_WIDTH / this._config.scaledCharWidth); - this._height = Math.floor(TEXTURE_HEIGHT / this._config.scaledCharHeight); - const capacity = this._width * this._height; - this._cacheMap = new LRUMap(capacity); - this._cacheMap.prealloc(capacity); - - // This is useful for debugging - // document.body.appendChild(this._cacheCanvas); - } - - public dispose(): void { - if (this._bitmapCommitTimeout !== null) { - window.clearTimeout(this._bitmapCommitTimeout); - this._bitmapCommitTimeout = null; - } - } - - public beginFrame(): void { - this._drawToCacheCount = 0; - } - - public clear(): void { - if (this._cacheMap.size > 0) { - const capacity = this._width * this._height; - this._cacheMap = new LRUMap(capacity); - this._cacheMap.prealloc(capacity); - } - this._cacheCtx.clearRect(0, 0, TEXTURE_WIDTH, TEXTURE_HEIGHT); - this._tmpCtx.clearRect(0, 0, this._config.scaledCharWidth, this._config.scaledCharHeight); - } - - public draw( - ctx: CanvasRenderingContext2D, - glyph: IGlyphIdentifier, - x: number, - y: number - ): boolean { - // Space is always an empty cell, special case this as it's so common - if (glyph.code === 32) { - return true; - } - - // Exit early for uncachable glyphs - if (!this._canCache(glyph)) { - return false; - } - - const glyphKey = getGlyphCacheKey(glyph); - const cacheValue = this._cacheMap.get(glyphKey); - if (cacheValue !== null && cacheValue !== undefined) { - this._drawFromCache(ctx, cacheValue, x, y); - return true; - } - if (this._drawToCacheCount < FRAME_CACHE_DRAW_LIMIT) { - let index; - if (this._cacheMap.size < this._cacheMap.capacity) { - index = this._cacheMap.size; - } else { - // we're out of space, so our call to set will delete this item - index = this._cacheMap.peek()!.index; - } - const cacheValue = this._drawToCache(glyph, index); - this._cacheMap.set(glyphKey, cacheValue); - this._drawFromCache(ctx, cacheValue, x, y); - return true; - } - return false; - } - - private _canCache(glyph: IGlyphIdentifier): boolean { - // Only cache ascii and extended characters for now, to be safe. In the future, we could do - // something more complicated to determine the expected width of a character. - // - // If we switch the renderer over to webgl at some point, we may be able to use blending modes - // to draw overlapping glyphs from the atlas: - // https://github.com/servo/webrender/issues/464#issuecomment-255632875 - // https://webglfundamentals.org/webgl/lessons/webgl-text-texture.html - return glyph.code < 256; - } - - private _toCoordinateX(index: number): number { - return (index % this._width) * this._config.scaledCharWidth; - } - - private _toCoordinateY(index: number): number { - return Math.floor(index / this._width) * this._config.scaledCharHeight; - } - - private _drawFromCache( - ctx: CanvasRenderingContext2D, - cacheValue: IGlyphCacheValue, - x: number, - y: number - ): void { - // We don't actually need to do anything if this is whitespace. - if (cacheValue.isEmpty) { - return; - } - const cacheX = this._toCoordinateX(cacheValue.index); - const cacheY = this._toCoordinateY(cacheValue.index); - ctx.drawImage( - cacheValue.inBitmap ? this._bitmap! : this._cacheCanvas, - cacheX, - cacheY, - this._config.scaledCharWidth, - this._config.scaledCharHeight, - x, - y, - this._config.scaledCharWidth, - this._config.scaledCharHeight - ); - } - - private _getColorFromAnsiIndex(idx: number): IColor { - if (idx < this._config.colors.ansi.length) { - return this._config.colors.ansi[idx]; - } - return DEFAULT_ANSI_COLORS[idx]; - } - - private _getBackgroundColor(glyph: IGlyphIdentifier): IColor { - if (this._config.allowTransparency) { - // The background color might have some transparency, so we need to render it as fully - // transparent in the atlas. Otherwise we'd end up drawing the transparent background twice - // around the anti-aliased edges of the glyph, and it would look too dark. - return TRANSPARENT_COLOR; - } - if (glyph.bg === INVERTED_DEFAULT_COLOR) { - return this._config.colors.foreground; - } - if (glyph.bg < 256) { - return this._getColorFromAnsiIndex(glyph.bg); - } - return this._config.colors.background; - } - - private _getForegroundColor(glyph: IGlyphIdentifier): IColor { - if (glyph.fg === INVERTED_DEFAULT_COLOR) { - return color.opaque(this._config.colors.background); - } - if (glyph.fg < 256) { - // 256 color support - return this._getColorFromAnsiIndex(glyph.fg); - } - return this._config.colors.foreground; - } - - // TODO: We do this (or something similar) in multiple places. We should split this off - // into a shared function. - private _drawToCache(glyph: IGlyphIdentifier, index: number): IGlyphCacheValue { - this._drawToCacheCount++; - - this._tmpCtx.save(); - - // draw the background - const backgroundColor = this._getBackgroundColor(glyph); - // Use a 'copy' composite operation to clear any existing glyph out of _tmpCtxWithAlpha, regardless of - // transparency in backgroundColor - this._tmpCtx.globalCompositeOperation = 'copy'; - this._tmpCtx.fillStyle = backgroundColor.css; - this._tmpCtx.fillRect(0, 0, this._config.scaledCharWidth, this._config.scaledCharHeight); - this._tmpCtx.globalCompositeOperation = 'source-over'; - - // draw the foreground/glyph - const fontWeight = glyph.bold ? this._config.fontWeightBold : this._config.fontWeight; - const fontStyle = glyph.italic ? 'italic' : ''; - this._tmpCtx.font = - `${fontStyle} ${fontWeight} ${this._config.fontSize * this._config.devicePixelRatio}px ${this._config.fontFamily}`; - this._tmpCtx.textBaseline = TEXT_BASELINE; - - this._tmpCtx.fillStyle = this._getForegroundColor(glyph).css; - - // Apply alpha to dim the character - if (glyph.dim) { - this._tmpCtx.globalAlpha = DIM_OPACITY; - } - // Draw the character - this._tmpCtx.fillText(glyph.chars, 0, this._config.scaledCharHeight); - - // clear the background from the character to avoid issues with drawing over the previous - // character if it extends past it's bounds - let imageData = this._tmpCtx.getImageData( - 0, 0, this._config.scaledCharWidth, this._config.scaledCharHeight - ); - let isEmpty = false; - if (!this._config.allowTransparency) { - isEmpty = clearColor(imageData, backgroundColor); - } - - // If this charcater is underscore and empty, shift it up until it is visible, try for a maximum - // of 5 pixels. - if (isEmpty && glyph.chars === '_' && !this._config.allowTransparency) { - for (let offset = 1; offset <= 5; offset++) { - // Draw the character - this._tmpCtx.fillText(glyph.chars, 0, this._config.scaledCharHeight - offset); - - // clear the background from the character to avoid issues with drawing over the previous - // character if it extends past it's bounds - imageData = this._tmpCtx.getImageData( - 0, 0, this._config.scaledCharWidth, this._config.scaledCharHeight - ); - isEmpty = clearColor(imageData, backgroundColor); - if (!isEmpty) { - break; - } - } - } - - this._tmpCtx.restore(); - - // copy the data from imageData to _cacheCanvas - const x = this._toCoordinateX(index); - const y = this._toCoordinateY(index); - // putImageData doesn't do any blending, so it will overwrite any existing cache entry for us - this._cacheCtx.putImageData(imageData, x, y); - - // Add the glyph and queue it to the bitmap (if the browser supports it) - const cacheValue = { - index, - isEmpty, - inBitmap: false - }; - this._addGlyphToBitmap(cacheValue); - - return cacheValue; - } - - private _addGlyphToBitmap(cacheValue: IGlyphCacheValue): void { - // Support is patchy for createImageBitmap at the moment, pass a canvas back - // if support is lacking as drawImage works there too. Firefox is also - // included here as ImageBitmap appears both buggy and has horrible - // performance (tested on v55). - if (!('createImageBitmap' in window) || isFirefox || isSafari) { - return; - } - - // Add the glyph to the queue - this._glyphsWaitingOnBitmap.push(cacheValue); - - // Check if bitmap generation timeout already exists - if (this._bitmapCommitTimeout !== null) { - return; - } - - this._bitmapCommitTimeout = window.setTimeout(() => this._generateBitmap(), GLYPH_BITMAP_COMMIT_DELAY); - } - - private _generateBitmap(): void { - const glyphsMovingToBitmap = this._glyphsWaitingOnBitmap; - this._glyphsWaitingOnBitmap = []; - window.createImageBitmap(this._cacheCanvas).then(bitmap => { - // Set bitmap - this._bitmap = bitmap; - - // Mark all new glyphs as in bitmap, excluding glyphs that came in after - // the bitmap was requested - for (let i = 0; i < glyphsMovingToBitmap.length; i++) { - const value = glyphsMovingToBitmap[i]; - // It doesn't matter if the value was already evicted, it will be - // released from memory after this block if so. - value.inBitmap = true; - } - }); - this._bitmapCommitTimeout = null; - } -} - -// This is used for debugging the renderer, just swap out `new DynamicCharAtlas` with -// `new NoneCharAtlas`. -export class NoneCharAtlas extends BaseCharAtlas { - constructor(document: Document, config: ICharAtlasConfig) { - super(); - } - - public draw( - ctx: CanvasRenderingContext2D, - glyph: IGlyphIdentifier, - x: number, - y: number - ): boolean { - return false; - } -} - -/** - * Makes a partiicular rgb color in an ImageData completely transparent. - * @returns True if the result is "empty", meaning all pixels are fully transparent. - */ -function clearColor(imageData: ImageData, color: IColor): boolean { - let isEmpty = true; - const r = color.rgba >>> 24; - const g = color.rgba >>> 16 & 0xFF; - const b = color.rgba >>> 8 & 0xFF; - for (let offset = 0; offset < imageData.data.length; offset += 4) { - if (imageData.data[offset] === r && - imageData.data[offset + 1] === g && - imageData.data[offset + 2] === b) { - imageData.data[offset + 3] = 0; - } else { - isEmpty = false; - } - } - return isEmpty; -} diff --git a/node_modules/xterm/src/browser/renderer/atlas/LRUMap.ts b/node_modules/xterm/src/browser/renderer/atlas/LRUMap.ts deleted file mode 100644 index f70962f..0000000 --- a/node_modules/xterm/src/browser/renderer/atlas/LRUMap.ts +++ /dev/null @@ -1,136 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -interface ILinkedListNode<T> { - prev: ILinkedListNode<T> | null; - next: ILinkedListNode<T> | null; - key: number | null; - value: T | null; -} - -export class LRUMap<T> { - private _map: { [key: number]: ILinkedListNode<T> } = {}; - private _head: ILinkedListNode<T> | null = null; - private _tail: ILinkedListNode<T> | null = null; - private _nodePool: ILinkedListNode<T>[] = []; - public size: number = 0; - - constructor(public capacity: number) { } - - private _unlinkNode(node: ILinkedListNode<T>): void { - const prev = node.prev; - const next = node.next; - if (node === this._head) { - this._head = next; - } - if (node === this._tail) { - this._tail = prev; - } - if (prev !== null) { - prev.next = next; - } - if (next !== null) { - next.prev = prev; - } - } - - private _appendNode(node: ILinkedListNode<T>): void { - const tail = this._tail; - if (tail !== null) { - tail.next = node; - } - node.prev = tail; - node.next = null; - this._tail = node; - if (this._head === null) { - this._head = node; - } - } - - /** - * Preallocate a bunch of linked-list nodes. Allocating these nodes ahead of time means that - * they're more likely to live next to each other in memory, which seems to improve performance. - * - * Each empty object only consumes about 60 bytes of memory, so this is pretty cheap, even for - * large maps. - */ - public prealloc(count: number): void { - const nodePool = this._nodePool; - for (let i = 0; i < count; i++) { - nodePool.push({ - prev: null, - next: null, - key: null, - value: null - }); - } - } - - public get(key: number): T | null { - // This is unsafe: We're assuming our keyspace doesn't overlap with Object.prototype. However, - // it's faster than calling hasOwnProperty, and in our case, it would never overlap. - const node = this._map[key]; - if (node !== undefined) { - this._unlinkNode(node); - this._appendNode(node); - return node.value; - } - return null; - } - - /** - * Gets a value from a key without marking it as the most recently used item. - */ - public peekValue(key: number): T | null { - const node = this._map[key]; - if (node !== undefined) { - return node.value; - } - return null; - } - - public peek(): T | null { - const head = this._head; - return head === null ? null : head.value; - } - - public set(key: number, value: T): void { - // This is unsafe: See note above. - let node = this._map[key]; - if (node !== undefined) { - // already exists, we just need to mutate it and move it to the end of the list - node = this._map[key]; - this._unlinkNode(node); - node.value = value; - } else if (this.size >= this.capacity) { - // we're out of space: recycle the head node, move it to the tail - node = this._head!; - this._unlinkNode(node); - delete this._map[node.key!]; - node.key = key; - node.value = value; - this._map[key] = node; - } else { - // make a new element - const nodePool = this._nodePool; - if (nodePool.length > 0) { - // use a preallocated node if we can - node = nodePool.pop()!; - node.key = key; - node.value = value; - } else { - node = { - prev: null, - next: null, - key, - value - }; - } - this._map[key] = node; - this.size++; - } - this._appendNode(node); - } -} diff --git a/node_modules/xterm/src/browser/renderer/atlas/Types.d.ts b/node_modules/xterm/src/browser/renderer/atlas/Types.d.ts deleted file mode 100644 index d8bc54c..0000000 --- a/node_modules/xterm/src/browser/renderer/atlas/Types.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { FontWeight } from 'common/services/Services'; -import { IPartialColorSet } from 'browser/Types'; - -export interface IGlyphIdentifier { - chars: string; - code: number; - bg: number; - fg: number; - bold: boolean; - dim: boolean; - italic: boolean; -} - -export interface ICharAtlasConfig { - devicePixelRatio: number; - fontSize: number; - fontFamily: string; - fontWeight: FontWeight; - fontWeightBold: FontWeight; - scaledCharWidth: number; - scaledCharHeight: number; - allowTransparency: boolean; - colors: IPartialColorSet; -} diff --git a/node_modules/xterm/src/browser/renderer/dom/DomRenderer.ts b/node_modules/xterm/src/browser/renderer/dom/DomRenderer.ts deleted file mode 100644 index ee28339..0000000 --- a/node_modules/xterm/src/browser/renderer/dom/DomRenderer.ts +++ /dev/null @@ -1,400 +0,0 @@ -/** - * Copyright (c) 2018 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IRenderer, IRenderDimensions, IRequestRedrawEvent } from 'browser/renderer/Types'; -import { BOLD_CLASS, ITALIC_CLASS, CURSOR_CLASS, CURSOR_STYLE_BLOCK_CLASS, CURSOR_BLINK_CLASS, CURSOR_STYLE_BAR_CLASS, CURSOR_STYLE_UNDERLINE_CLASS, DomRendererRowFactory } from 'browser/renderer/dom/DomRendererRowFactory'; -import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; -import { Disposable } from 'common/Lifecycle'; -import { IColorSet, ILinkifierEvent, ILinkifier, ILinkifier2 } from 'browser/Types'; -import { ICharSizeService } from 'browser/services/Services'; -import { IOptionsService, IBufferService, IInstantiationService } from 'common/services/Services'; -import { EventEmitter, IEvent } from 'common/EventEmitter'; -import { color } from 'browser/Color'; -import { removeElementFromParent } from 'browser/Dom'; - -const TERMINAL_CLASS_PREFIX = 'xterm-dom-renderer-owner-'; -const ROW_CONTAINER_CLASS = 'xterm-rows'; -const FG_CLASS_PREFIX = 'xterm-fg-'; -const BG_CLASS_PREFIX = 'xterm-bg-'; -const FOCUS_CLASS = 'xterm-focus'; -const SELECTION_CLASS = 'xterm-selection'; - -let nextTerminalId = 1; - -/** - * A fallback renderer for when canvas is slow. This is not meant to be - * particularly fast or feature complete, more just stable and usable for when - * canvas is not an option. - */ -export class DomRenderer extends Disposable implements IRenderer { - private _rowFactory: DomRendererRowFactory; - private _terminalClass: number = nextTerminalId++; - - private _themeStyleElement!: HTMLStyleElement; - private _dimensionsStyleElement!: HTMLStyleElement; - private _rowContainer: HTMLElement; - private _rowElements: HTMLElement[] = []; - private _selectionContainer: HTMLElement; - - public dimensions: IRenderDimensions; - - public get onRequestRedraw(): IEvent<IRequestRedrawEvent> { return new EventEmitter<IRequestRedrawEvent>().event; } - - constructor( - private _colors: IColorSet, - private readonly _element: HTMLElement, - private readonly _screenElement: HTMLElement, - private readonly _viewportElement: HTMLElement, - private readonly _linkifier: ILinkifier, - private readonly _linkifier2: ILinkifier2, - @IInstantiationService instantiationService: IInstantiationService, - @ICharSizeService private readonly _charSizeService: ICharSizeService, - @IOptionsService private readonly _optionsService: IOptionsService, - @IBufferService private readonly _bufferService: IBufferService - ) { - super(); - this._rowContainer = document.createElement('div'); - this._rowContainer.classList.add(ROW_CONTAINER_CLASS); - this._rowContainer.style.lineHeight = 'normal'; - this._rowContainer.setAttribute('aria-hidden', 'true'); - this._refreshRowElements(this._bufferService.cols, this._bufferService.rows); - this._selectionContainer = document.createElement('div'); - this._selectionContainer.classList.add(SELECTION_CLASS); - this._selectionContainer.setAttribute('aria-hidden', 'true'); - - this.dimensions = { - scaledCharWidth: 0, - scaledCharHeight: 0, - scaledCellWidth: 0, - scaledCellHeight: 0, - scaledCharLeft: 0, - scaledCharTop: 0, - scaledCanvasWidth: 0, - scaledCanvasHeight: 0, - canvasWidth: 0, - canvasHeight: 0, - actualCellWidth: 0, - actualCellHeight: 0 - }; - this._updateDimensions(); - this._injectCss(); - - this._rowFactory = instantiationService.createInstance(DomRendererRowFactory, document, this._colors); - - this._element.classList.add(TERMINAL_CLASS_PREFIX + this._terminalClass); - this._screenElement.appendChild(this._rowContainer); - this._screenElement.appendChild(this._selectionContainer); - - this._linkifier.onShowLinkUnderline(e => this._onLinkHover(e)); - this._linkifier.onHideLinkUnderline(e => this._onLinkLeave(e)); - - this._linkifier2.onShowLinkUnderline(e => this._onLinkHover(e)); - this._linkifier2.onHideLinkUnderline(e => this._onLinkLeave(e)); - } - - public dispose(): void { - this._element.classList.remove(TERMINAL_CLASS_PREFIX + this._terminalClass); - - // Outside influences such as React unmounts may manipulate the DOM before our disposal. - // https://github.com/xtermjs/xterm.js/issues/2960 - removeElementFromParent(this._rowContainer, this._selectionContainer, this._themeStyleElement, this._dimensionsStyleElement); - - super.dispose(); - } - - private _updateDimensions(): void { - this.dimensions.scaledCharWidth = this._charSizeService.width * window.devicePixelRatio; - this.dimensions.scaledCharHeight = Math.ceil(this._charSizeService.height * window.devicePixelRatio); - this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth + Math.round(this._optionsService.rawOptions.letterSpacing); - this.dimensions.scaledCellHeight = Math.floor(this.dimensions.scaledCharHeight * this._optionsService.rawOptions.lineHeight); - this.dimensions.scaledCharLeft = 0; - this.dimensions.scaledCharTop = 0; - this.dimensions.scaledCanvasWidth = this.dimensions.scaledCellWidth * this._bufferService.cols; - this.dimensions.scaledCanvasHeight = this.dimensions.scaledCellHeight * this._bufferService.rows; - this.dimensions.canvasWidth = Math.round(this.dimensions.scaledCanvasWidth / window.devicePixelRatio); - this.dimensions.canvasHeight = Math.round(this.dimensions.scaledCanvasHeight / window.devicePixelRatio); - this.dimensions.actualCellWidth = this.dimensions.canvasWidth / this._bufferService.cols; - this.dimensions.actualCellHeight = this.dimensions.canvasHeight / this._bufferService.rows; - - for (const element of this._rowElements) { - element.style.width = `${this.dimensions.canvasWidth}px`; - element.style.height = `${this.dimensions.actualCellHeight}px`; - element.style.lineHeight = `${this.dimensions.actualCellHeight}px`; - // Make sure rows don't overflow onto following row - element.style.overflow = 'hidden'; - } - - if (!this._dimensionsStyleElement) { - this._dimensionsStyleElement = document.createElement('style'); - this._screenElement.appendChild(this._dimensionsStyleElement); - } - - const styles = - `${this._terminalSelector} .${ROW_CONTAINER_CLASS} span {` + - ` display: inline-block;` + - ` height: 100%;` + - ` vertical-align: top;` + - ` width: ${this.dimensions.actualCellWidth}px` + - `}`; - - this._dimensionsStyleElement.textContent = styles; - - this._selectionContainer.style.height = this._viewportElement.style.height; - this._screenElement.style.width = `${this.dimensions.canvasWidth}px`; - this._screenElement.style.height = `${this.dimensions.canvasHeight}px`; - } - - public setColors(colors: IColorSet): void { - this._colors = colors; - this._injectCss(); - } - - private _injectCss(): void { - if (!this._themeStyleElement) { - this._themeStyleElement = document.createElement('style'); - this._screenElement.appendChild(this._themeStyleElement); - } - - // Base CSS - let styles = - `${this._terminalSelector} .${ROW_CONTAINER_CLASS} {` + - ` color: ${this._colors.foreground.css};` + - ` font-family: ${this._optionsService.rawOptions.fontFamily};` + - ` font-size: ${this._optionsService.rawOptions.fontSize}px;` + - `}`; - // Text styles - styles += - `${this._terminalSelector} span:not(.${BOLD_CLASS}) {` + - ` font-weight: ${this._optionsService.rawOptions.fontWeight};` + - `}` + - `${this._terminalSelector} span.${BOLD_CLASS} {` + - ` font-weight: ${this._optionsService.rawOptions.fontWeightBold};` + - `}` + - `${this._terminalSelector} span.${ITALIC_CLASS} {` + - ` font-style: italic;` + - `}`; - // Blink animation - styles += - `@keyframes blink_box_shadow` + `_` + this._terminalClass + ` {` + - ` 50% {` + - ` box-shadow: none;` + - ` }` + - `}`; - styles += - `@keyframes blink_block` + `_` + this._terminalClass + ` {` + - ` 0% {` + - ` background-color: ${this._colors.cursor.css};` + - ` color: ${this._colors.cursorAccent.css};` + - ` }` + - ` 50% {` + - ` background-color: ${this._colors.cursorAccent.css};` + - ` color: ${this._colors.cursor.css};` + - ` }` + - `}`; - // Cursor - styles += - `${this._terminalSelector} .${ROW_CONTAINER_CLASS}:not(.${FOCUS_CLASS}) .${CURSOR_CLASS}.${CURSOR_STYLE_BLOCK_CLASS} {` + - ` outline: 1px solid ${this._colors.cursor.css};` + - ` outline-offset: -1px;` + - `}` + - `${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${CURSOR_CLASS}.${CURSOR_BLINK_CLASS}:not(.${CURSOR_STYLE_BLOCK_CLASS}) {` + - ` animation: blink_box_shadow` + `_` + this._terminalClass + ` 1s step-end infinite;` + - `}` + - `${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${CURSOR_CLASS}.${CURSOR_BLINK_CLASS}.${CURSOR_STYLE_BLOCK_CLASS} {` + - ` animation: blink_block` + `_` + this._terminalClass + ` 1s step-end infinite;` + - `}` + - `${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${CURSOR_CLASS}.${CURSOR_STYLE_BLOCK_CLASS} {` + - ` background-color: ${this._colors.cursor.css};` + - ` color: ${this._colors.cursorAccent.css};` + - `}` + - `${this._terminalSelector} .${ROW_CONTAINER_CLASS} .${CURSOR_CLASS}.${CURSOR_STYLE_BAR_CLASS} {` + - ` box-shadow: ${this._optionsService.rawOptions.cursorWidth}px 0 0 ${this._colors.cursor.css} inset;` + - `}` + - `${this._terminalSelector} .${ROW_CONTAINER_CLASS} .${CURSOR_CLASS}.${CURSOR_STYLE_UNDERLINE_CLASS} {` + - ` box-shadow: 0 -1px 0 ${this._colors.cursor.css} inset;` + - `}`; - // Selection - styles += - `${this._terminalSelector} .${SELECTION_CLASS} {` + - ` position: absolute;` + - ` top: 0;` + - ` left: 0;` + - ` z-index: 1;` + - ` pointer-events: none;` + - `}` + - `${this._terminalSelector} .${SELECTION_CLASS} div {` + - ` position: absolute;` + - ` background-color: ${this._colors.selectionTransparent.css};` + - `}`; - // Colors - this._colors.ansi.forEach((c, i) => { - styles += - `${this._terminalSelector} .${FG_CLASS_PREFIX}${i} { color: ${c.css}; }` + - `${this._terminalSelector} .${BG_CLASS_PREFIX}${i} { background-color: ${c.css}; }`; - }); - styles += - `${this._terminalSelector} .${FG_CLASS_PREFIX}${INVERTED_DEFAULT_COLOR} { color: ${color.opaque(this._colors.background).css}; }` + - `${this._terminalSelector} .${BG_CLASS_PREFIX}${INVERTED_DEFAULT_COLOR} { background-color: ${this._colors.foreground.css}; }`; - - this._themeStyleElement.textContent = styles; - } - - public onDevicePixelRatioChange(): void { - this._updateDimensions(); - } - - private _refreshRowElements(cols: number, rows: number): void { - // Add missing elements - for (let i = this._rowElements.length; i <= rows; i++) { - const row = document.createElement('div'); - this._rowContainer.appendChild(row); - this._rowElements.push(row); - } - // Remove excess elements - while (this._rowElements.length > rows) { - this._rowContainer.removeChild(this._rowElements.pop()!); - } - } - - public onResize(cols: number, rows: number): void { - this._refreshRowElements(cols, rows); - this._updateDimensions(); - } - - public onCharSizeChanged(): void { - this._updateDimensions(); - } - - public onBlur(): void { - this._rowContainer.classList.remove(FOCUS_CLASS); - } - - public onFocus(): void { - this._rowContainer.classList.add(FOCUS_CLASS); - } - - public onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void { - // Remove all selections - while (this._selectionContainer.children.length) { - this._selectionContainer.removeChild(this._selectionContainer.children[0]); - } - - // Selection does not exist - if (!start || !end) { - return; - } - - // Translate from buffer position to viewport position - const viewportStartRow = start[1] - this._bufferService.buffer.ydisp; - const viewportEndRow = end[1] - this._bufferService.buffer.ydisp; - const viewportCappedStartRow = Math.max(viewportStartRow, 0); - const viewportCappedEndRow = Math.min(viewportEndRow, this._bufferService.rows - 1); - - // No need to draw the selection - if (viewportCappedStartRow >= this._bufferService.rows || viewportCappedEndRow < 0) { - return; - } - - // Create the selections - const documentFragment = document.createDocumentFragment(); - - if (columnSelectMode) { - documentFragment.appendChild( - this._createSelectionElement(viewportCappedStartRow, start[0], end[0], viewportCappedEndRow - viewportCappedStartRow + 1) - ); - } else { - // Draw first row - const startCol = viewportStartRow === viewportCappedStartRow ? start[0] : 0; - const endCol = viewportCappedStartRow === viewportEndRow ? end[0] : this._bufferService.cols; - documentFragment.appendChild(this._createSelectionElement(viewportCappedStartRow, startCol, endCol)); - // Draw middle rows - const middleRowsCount = viewportCappedEndRow - viewportCappedStartRow - 1; - documentFragment.appendChild(this._createSelectionElement(viewportCappedStartRow + 1, 0, this._bufferService.cols, middleRowsCount)); - // Draw final row - if (viewportCappedStartRow !== viewportCappedEndRow) { - // Only draw viewportEndRow if it's not the same as viewporttartRow - const endCol = viewportEndRow === viewportCappedEndRow ? end[0] : this._bufferService.cols; - documentFragment.appendChild(this._createSelectionElement(viewportCappedEndRow, 0, endCol)); - } - } - this._selectionContainer.appendChild(documentFragment); - } - - /** - * Creates a selection element at the specified position. - * @param row The row of the selection. - * @param colStart The start column. - * @param colEnd The end columns. - */ - private _createSelectionElement(row: number, colStart: number, colEnd: number, rowCount: number = 1): HTMLElement { - const element = document.createElement('div'); - element.style.height = `${rowCount * this.dimensions.actualCellHeight}px`; - element.style.top = `${row * this.dimensions.actualCellHeight}px`; - element.style.left = `${colStart * this.dimensions.actualCellWidth}px`; - element.style.width = `${this.dimensions.actualCellWidth * (colEnd - colStart)}px`; - return element; - } - - public onCursorMove(): void { - // No-op, the cursor is drawn when rows are drawn - } - - public onOptionsChanged(): void { - // Force a refresh - this._updateDimensions(); - this._injectCss(); - } - - public clear(): void { - for (const e of this._rowElements) { - e.innerText = ''; - } - } - - public renderRows(start: number, end: number): void { - const cursorAbsoluteY = this._bufferService.buffer.ybase + this._bufferService.buffer.y; - const cursorX = Math.min(this._bufferService.buffer.x, this._bufferService.cols - 1); - const cursorBlink = this._optionsService.rawOptions.cursorBlink; - - for (let y = start; y <= end; y++) { - const rowElement = this._rowElements[y]; - rowElement.innerText = ''; - - const row = y + this._bufferService.buffer.ydisp; - const lineData = this._bufferService.buffer.lines.get(row); - const cursorStyle = this._optionsService.rawOptions.cursorStyle; - rowElement.appendChild(this._rowFactory.createRow(lineData!, row, row === cursorAbsoluteY, cursorStyle, cursorX, cursorBlink, this.dimensions.actualCellWidth, this._bufferService.cols)); - } - } - - private get _terminalSelector(): string { - return `.${TERMINAL_CLASS_PREFIX}${this._terminalClass}`; - } - - private _onLinkHover(e: ILinkifierEvent): void { - this._setCellUnderline(e.x1, e.x2, e.y1, e.y2, e.cols, true); - } - - private _onLinkLeave(e: ILinkifierEvent): void { - this._setCellUnderline(e.x1, e.x2, e.y1, e.y2, e.cols, false); - } - - private _setCellUnderline(x: number, x2: number, y: number, y2: number, cols: number, enabled: boolean): void { - while (x !== x2 || y !== y2) { - const row = this._rowElements[y]; - if (!row) { - return; - } - const span = row.children[x] as HTMLElement; - if (span) { - span.style.textDecoration = enabled ? 'underline' : 'none'; - } - if (++x >= cols) { - x = 0; - y++; - } - } - } -} diff --git a/node_modules/xterm/src/browser/renderer/dom/DomRendererRowFactory.ts b/node_modules/xterm/src/browser/renderer/dom/DomRendererRowFactory.ts deleted file mode 100644 index fda800a..0000000 --- a/node_modules/xterm/src/browser/renderer/dom/DomRendererRowFactory.ts +++ /dev/null @@ -1,259 +0,0 @@ -/** - * Copyright (c) 2018 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IBufferLine } from 'common/Types'; -import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; -import { NULL_CELL_CODE, WHITESPACE_CELL_CHAR, Attributes } from 'common/buffer/Constants'; -import { CellData } from 'common/buffer/CellData'; -import { ICoreService, IOptionsService } from 'common/services/Services'; -import { color, rgba } from 'browser/Color'; -import { IColorSet, IColor } from 'browser/Types'; -import { ICharacterJoinerService } from 'browser/services/Services'; -import { JoinedCellData } from 'browser/services/CharacterJoinerService'; - -export const BOLD_CLASS = 'xterm-bold'; -export const DIM_CLASS = 'xterm-dim'; -export const ITALIC_CLASS = 'xterm-italic'; -export const UNDERLINE_CLASS = 'xterm-underline'; -export const STRIKETHROUGH_CLASS = 'xterm-strikethrough'; -export const CURSOR_CLASS = 'xterm-cursor'; -export const CURSOR_BLINK_CLASS = 'xterm-cursor-blink'; -export const CURSOR_STYLE_BLOCK_CLASS = 'xterm-cursor-block'; -export const CURSOR_STYLE_BAR_CLASS = 'xterm-cursor-bar'; -export const CURSOR_STYLE_UNDERLINE_CLASS = 'xterm-cursor-underline'; - -export class DomRendererRowFactory { - private _workCell: CellData = new CellData(); - - constructor( - private readonly _document: Document, - private _colors: IColorSet, - @ICharacterJoinerService private readonly _characterJoinerService: ICharacterJoinerService, - @IOptionsService private readonly _optionsService: IOptionsService, - @ICoreService private readonly _coreService: ICoreService - ) { - } - - public setColors(colors: IColorSet): void { - this._colors = colors; - } - - public createRow(lineData: IBufferLine, row: number, isCursorRow: boolean, cursorStyle: string | undefined, cursorX: number, cursorBlink: boolean, cellWidth: number, cols: number): DocumentFragment { - const fragment = this._document.createDocumentFragment(); - - const joinedRanges = this._characterJoinerService.getJoinedCharacters(row); - // Find the line length first, this prevents the need to output a bunch of - // empty cells at the end. This cannot easily be integrated into the main - // loop below because of the colCount feature (which can be removed after we - // properly support reflow and disallow data to go beyond the right-side of - // the viewport). - let lineLength = 0; - for (let x = Math.min(lineData.length, cols) - 1; x >= 0; x--) { - if (lineData.loadCell(x, this._workCell).getCode() !== NULL_CELL_CODE || (isCursorRow && x === cursorX)) { - lineLength = x + 1; - break; - } - } - - for (let x = 0; x < lineLength; x++) { - lineData.loadCell(x, this._workCell); - let width = this._workCell.getWidth(); - - // The character to the left is a wide character, drawing is owned by the char at x-1 - if (width === 0) { - continue; - } - - // If true, indicates that the current character(s) to draw were joined. - let isJoined = false; - let lastCharX = x; - - // Process any joined character ranges as needed. Because of how the - // ranges are produced, we know that they are valid for the characters - // and attributes of our input. - let cell = this._workCell; - if (joinedRanges.length > 0 && x === joinedRanges[0][0]) { - isJoined = true; - const range = joinedRanges.shift()!; - - // We already know the exact start and end column of the joined range, - // so we get the string and width representing it directly - cell = new JoinedCellData( - this._workCell, - lineData.translateToString(true, range[0], range[1]), - range[1] - range[0] - ); - - // Skip over the cells occupied by this range in the loop - lastCharX = range[1] - 1; - - // Recalculate width - width = cell.getWidth(); - } - - const charElement = this._document.createElement('span'); - if (width > 1) { - charElement.style.width = `${cellWidth * width}px`; - } - - if (isJoined) { - // Ligatures in the DOM renderer must use display inline, as they may not show with - // inline-block if they are outside the bounds of the element - charElement.style.display = 'inline'; - - // The DOM renderer colors the background of the cursor but for ligatures all cells are - // joined. The workaround here is to show a cursor around the whole ligature so it shows up, - // the cursor looks the same when on any character of the ligature though - if (cursorX >= x && cursorX <= lastCharX) { - cursorX = x; - } - } - - if (!this._coreService.isCursorHidden && isCursorRow && x === cursorX) { - charElement.classList.add(CURSOR_CLASS); - - if (cursorBlink) { - charElement.classList.add(CURSOR_BLINK_CLASS); - } - - switch (cursorStyle) { - case 'bar': - charElement.classList.add(CURSOR_STYLE_BAR_CLASS); - break; - case 'underline': - charElement.classList.add(CURSOR_STYLE_UNDERLINE_CLASS); - break; - default: - charElement.classList.add(CURSOR_STYLE_BLOCK_CLASS); - break; - } - } - - if (cell.isBold()) { - charElement.classList.add(BOLD_CLASS); - } - - if (cell.isItalic()) { - charElement.classList.add(ITALIC_CLASS); - } - - if (cell.isDim()) { - charElement.classList.add(DIM_CLASS); - } - - if (cell.isUnderline()) { - charElement.classList.add(UNDERLINE_CLASS); - } - - if (cell.isInvisible()) { - charElement.textContent = WHITESPACE_CELL_CHAR; - } else { - charElement.textContent = cell.getChars() || WHITESPACE_CELL_CHAR; - } - - if (cell.isStrikethrough()) { - charElement.classList.add(STRIKETHROUGH_CLASS); - } - - let fg = cell.getFgColor(); - let fgColorMode = cell.getFgColorMode(); - let bg = cell.getBgColor(); - let bgColorMode = cell.getBgColorMode(); - const isInverse = !!cell.isInverse(); - if (isInverse) { - const temp = fg; - fg = bg; - bg = temp; - const temp2 = fgColorMode; - fgColorMode = bgColorMode; - bgColorMode = temp2; - } - - // Foreground - switch (fgColorMode) { - case Attributes.CM_P16: - case Attributes.CM_P256: - if (cell.isBold() && fg < 8 && this._optionsService.rawOptions.drawBoldTextInBrightColors) { - fg += 8; - } - if (!this._applyMinimumContrast(charElement, this._colors.background, this._colors.ansi[fg])) { - charElement.classList.add(`xterm-fg-${fg}`); - } - break; - case Attributes.CM_RGB: - const color = rgba.toColor( - (fg >> 16) & 0xFF, - (fg >> 8) & 0xFF, - (fg ) & 0xFF - ); - if (!this._applyMinimumContrast(charElement, this._colors.background, color)) { - this._addStyle(charElement, `color:#${padStart(fg.toString(16), '0', 6)}`); - } - break; - case Attributes.CM_DEFAULT: - default: - if (!this._applyMinimumContrast(charElement, this._colors.background, this._colors.foreground)) { - if (isInverse) { - charElement.classList.add(`xterm-fg-${INVERTED_DEFAULT_COLOR}`); - } - } - } - - // Background - switch (bgColorMode) { - case Attributes.CM_P16: - case Attributes.CM_P256: - charElement.classList.add(`xterm-bg-${bg}`); - break; - case Attributes.CM_RGB: - this._addStyle(charElement, `background-color:#${padStart(bg.toString(16), '0', 6)}`); - break; - case Attributes.CM_DEFAULT: - default: - if (isInverse) { - charElement.classList.add(`xterm-bg-${INVERTED_DEFAULT_COLOR}`); - } - } - - fragment.appendChild(charElement); - - x = lastCharX; - } - return fragment; - } - - private _applyMinimumContrast(element: HTMLElement, bg: IColor, fg: IColor): boolean { - if (this._optionsService.rawOptions.minimumContrastRatio === 1) { - return false; - } - - // Try get from cache first - let adjustedColor = this._colors.contrastCache.getColor(this._workCell.bg, this._workCell.fg); - - // Calculate and store in cache - if (adjustedColor === undefined) { - adjustedColor = color.ensureContrastRatio(bg, fg, this._optionsService.rawOptions.minimumContrastRatio); - this._colors.contrastCache.setColor(this._workCell.bg, this._workCell.fg, adjustedColor ?? null); - } - - if (adjustedColor) { - this._addStyle(element, `color:${adjustedColor.css}`); - return true; - } - - return false; - } - - private _addStyle(element: HTMLElement, style: string): void { - element.setAttribute('style', `${element.getAttribute('style') || ''}${style};`); - } -} - -function padStart(text: string, padChar: string, length: number): string { - while (text.length < length) { - text = padChar + text; - } - return text; -} diff --git a/node_modules/xterm/src/browser/selection/SelectionModel.ts b/node_modules/xterm/src/browser/selection/SelectionModel.ts deleted file mode 100644 index 1d84446..0000000 --- a/node_modules/xterm/src/browser/selection/SelectionModel.ts +++ /dev/null @@ -1,139 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IBufferService } from 'common/services/Services'; - -/** - * Represents a selection within the buffer. This model only cares about column - * and row coordinates, not wide characters. - */ -export class SelectionModel { - /** - * Whether select all is currently active. - */ - public isSelectAllActive: boolean = false; - - /** - * The minimal length of the selection from the start position. When double - * clicking on a word, the word will be selected which makes the selection - * start at the start of the word and makes this variable the length. - */ - public selectionStartLength: number = 0; - - /** - * The [x, y] position the selection starts at. - */ - public selectionStart: [number, number] | undefined; - - /** - * The [x, y] position the selection ends at. - */ - public selectionEnd: [number, number] | undefined; - - constructor( - private _bufferService: IBufferService - ) { - } - - /** - * Clears the current selection. - */ - public clearSelection(): void { - this.selectionStart = undefined; - this.selectionEnd = undefined; - this.isSelectAllActive = false; - this.selectionStartLength = 0; - } - - /** - * The final selection start, taking into consideration select all. - */ - public get finalSelectionStart(): [number, number] | undefined { - if (this.isSelectAllActive) { - return [0, 0]; - } - - if (!this.selectionEnd || !this.selectionStart) { - return this.selectionStart; - } - - return this.areSelectionValuesReversed() ? this.selectionEnd : this.selectionStart; - } - - /** - * The final selection end, taking into consideration select all, double click - * word selection and triple click line selection. - */ - public get finalSelectionEnd(): [number, number] | undefined { - if (this.isSelectAllActive) { - return [this._bufferService.cols, this._bufferService.buffer.ybase + this._bufferService.rows - 1]; - } - - if (!this.selectionStart) { - return undefined; - } - - // Use the selection start + length if the end doesn't exist or they're reversed - if (!this.selectionEnd || this.areSelectionValuesReversed()) { - const startPlusLength = this.selectionStart[0] + this.selectionStartLength; - if (startPlusLength > this._bufferService.cols) { - // Ensure the trailing EOL isn't included when the selection ends on the right edge - if (startPlusLength % this._bufferService.cols === 0) { - return [this._bufferService.cols, this.selectionStart[1] + Math.floor(startPlusLength / this._bufferService.cols) - 1]; - } - return [startPlusLength % this._bufferService.cols, this.selectionStart[1] + Math.floor(startPlusLength / this._bufferService.cols)]; - } - return [startPlusLength, this.selectionStart[1]]; - } - - // Ensure the the word/line is selected after a double/triple click - if (this.selectionStartLength) { - // Select the larger of the two when start and end are on the same line - if (this.selectionEnd[1] === this.selectionStart[1]) { - return [Math.max(this.selectionStart[0] + this.selectionStartLength, this.selectionEnd[0]), this.selectionEnd[1]]; - } - } - return this.selectionEnd; - } - - /** - * Returns whether the selection start and end are reversed. - */ - public areSelectionValuesReversed(): boolean { - const start = this.selectionStart; - const end = this.selectionEnd; - if (!start || !end) { - return false; - } - return start[1] > end[1] || (start[1] === end[1] && start[0] > end[0]); - } - - /** - * Handle the buffer being trimmed, adjust the selection position. - * @param amount The amount the buffer is being trimmed. - * @return Whether a refresh is necessary. - */ - public onTrim(amount: number): boolean { - // Adjust the selection position based on the trimmed amount. - if (this.selectionStart) { - this.selectionStart[1] -= amount; - } - if (this.selectionEnd) { - this.selectionEnd[1] -= amount; - } - - // The selection has moved off the buffer, clear it. - if (this.selectionEnd && this.selectionEnd[1] < 0) { - this.clearSelection(); - return true; - } - - // If the selection start is trimmed, ensure the start column is 0. - if (this.selectionStart && this.selectionStart[1] < 0) { - this.selectionStart[1] = 0; - } - return false; - } -} diff --git a/node_modules/xterm/src/browser/selection/Types.d.ts b/node_modules/xterm/src/browser/selection/Types.d.ts deleted file mode 100644 index 8adfc17..0000000 --- a/node_modules/xterm/src/browser/selection/Types.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -export interface ISelectionRedrawRequestEvent { - start: [number, number] | undefined; - end: [number, number] | undefined; - columnSelectMode: boolean; -} - -export interface ISelectionRequestScrollLinesEvent { - amount: number; - suppressScrollEvent: boolean; -} diff --git a/node_modules/xterm/src/browser/services/CharSizeService.ts b/node_modules/xterm/src/browser/services/CharSizeService.ts deleted file mode 100644 index b04e157..0000000 --- a/node_modules/xterm/src/browser/services/CharSizeService.ts +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Copyright (c) 2016 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IOptionsService } from 'common/services/Services'; -import { IEvent, EventEmitter } from 'common/EventEmitter'; -import { ICharSizeService } from 'browser/services/Services'; - -export class CharSizeService implements ICharSizeService { - public serviceBrand: undefined; - - public width: number = 0; - public height: number = 0; - private _measureStrategy: IMeasureStrategy; - - public get hasValidSize(): boolean { return this.width > 0 && this.height > 0; } - - private _onCharSizeChange = new EventEmitter<void>(); - public get onCharSizeChange(): IEvent<void> { return this._onCharSizeChange.event; } - - constructor( - document: Document, - parentElement: HTMLElement, - @IOptionsService private readonly _optionsService: IOptionsService - ) { - this._measureStrategy = new DomMeasureStrategy(document, parentElement, this._optionsService); - } - - public measure(): void { - const result = this._measureStrategy.measure(); - if (result.width !== this.width || result.height !== this.height) { - this.width = result.width; - this.height = result.height; - this._onCharSizeChange.fire(); - } - } -} - -interface IMeasureStrategy { - measure(): IReadonlyMeasureResult; -} - -interface IReadonlyMeasureResult { - readonly width: number; - readonly height: number; -} - -interface IMeasureResult { - width: number; - height: number; -} - -// TODO: For supporting browsers we should also provide a CanvasCharDimensionsProvider that uses ctx.measureText -class DomMeasureStrategy implements IMeasureStrategy { - private _result: IMeasureResult = { width: 0, height: 0 }; - private _measureElement: HTMLElement; - - constructor( - private _document: Document, - private _parentElement: HTMLElement, - private _optionsService: IOptionsService - ) { - this._measureElement = this._document.createElement('span'); - this._measureElement.classList.add('xterm-char-measure-element'); - this._measureElement.textContent = 'W'; - this._measureElement.setAttribute('aria-hidden', 'true'); - this._parentElement.appendChild(this._measureElement); - } - - public measure(): IReadonlyMeasureResult { - this._measureElement.style.fontFamily = this._optionsService.rawOptions.fontFamily; - this._measureElement.style.fontSize = `${this._optionsService.rawOptions.fontSize}px`; - - // Note that this triggers a synchronous layout - const geometry = this._measureElement.getBoundingClientRect(); - - // If values are 0 then the element is likely currently display:none, in which case we should - // retain the previous value. - if (geometry.width !== 0 && geometry.height !== 0) { - this._result.width = geometry.width; - this._result.height = Math.ceil(geometry.height); - } - - return this._result; - } -} diff --git a/node_modules/xterm/src/browser/services/CharacterJoinerService.ts b/node_modules/xterm/src/browser/services/CharacterJoinerService.ts deleted file mode 100644 index ca4f198..0000000 --- a/node_modules/xterm/src/browser/services/CharacterJoinerService.ts +++ /dev/null @@ -1,339 +0,0 @@ -/** - * Copyright (c) 2018 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IBufferLine, ICellData, CharData } from 'common/Types'; -import { ICharacterJoiner } from 'browser/Types'; -import { AttributeData } from 'common/buffer/AttributeData'; -import { WHITESPACE_CELL_CHAR, Content } from 'common/buffer/Constants'; -import { CellData } from 'common/buffer/CellData'; -import { IBufferService } from 'common/services/Services'; -import { ICharacterJoinerService } from 'browser/services/Services'; - -export class JoinedCellData extends AttributeData implements ICellData { - private _width: number; - // .content carries no meaning for joined CellData, simply nullify it - // thus we have to overload all other .content accessors - public content: number = 0; - public fg: number; - public bg: number; - public combinedData: string = ''; - - constructor(firstCell: ICellData, chars: string, width: number) { - super(); - this.fg = firstCell.fg; - this.bg = firstCell.bg; - this.combinedData = chars; - this._width = width; - } - - public isCombined(): number { - // always mark joined cell data as combined - return Content.IS_COMBINED_MASK; - } - - public getWidth(): number { - return this._width; - } - - public getChars(): string { - return this.combinedData; - } - - public getCode(): number { - // code always gets the highest possible fake codepoint (read as -1) - // this is needed as code is used by caches as identifier - return 0x1FFFFF; - } - - public setFromCharData(value: CharData): void { - throw new Error('not implemented'); - } - - public getAsCharData(): CharData { - return [this.fg, this.getChars(), this.getWidth(), this.getCode()]; - } -} - -export class CharacterJoinerService implements ICharacterJoinerService { - public serviceBrand: undefined; - - private _characterJoiners: ICharacterJoiner[] = []; - private _nextCharacterJoinerId: number = 0; - private _workCell: CellData = new CellData(); - - constructor( - @IBufferService private _bufferService: IBufferService - ) { } - - public register(handler: (text: string) => [number, number][]): number { - const joiner: ICharacterJoiner = { - id: this._nextCharacterJoinerId++, - handler - }; - - this._characterJoiners.push(joiner); - return joiner.id; - } - - public deregister(joinerId: number): boolean { - for (let i = 0; i < this._characterJoiners.length; i++) { - if (this._characterJoiners[i].id === joinerId) { - this._characterJoiners.splice(i, 1); - return true; - } - } - - return false; - } - - public getJoinedCharacters(row: number): [number, number][] { - if (this._characterJoiners.length === 0) { - return []; - } - - const line = this._bufferService.buffer.lines.get(row); - if (!line || line.length === 0) { - return []; - } - - const ranges: [number, number][] = []; - const lineStr = line.translateToString(true); - - // Because some cells can be represented by multiple javascript characters, - // we track the cell and the string indexes separately. This allows us to - // translate the string ranges we get from the joiners back into cell ranges - // for use when rendering - let rangeStartColumn = 0; - let currentStringIndex = 0; - let rangeStartStringIndex = 0; - let rangeAttrFG = line.getFg(0); - let rangeAttrBG = line.getBg(0); - - for (let x = 0; x < line.getTrimmedLength(); x++) { - line.loadCell(x, this._workCell); - - if (this._workCell.getWidth() === 0) { - // If this character is of width 0, skip it. - continue; - } - - // End of range - if (this._workCell.fg !== rangeAttrFG || this._workCell.bg !== rangeAttrBG) { - // If we ended up with a sequence of more than one character, - // look for ranges to join. - if (x - rangeStartColumn > 1) { - const joinedRanges = this._getJoinedRanges( - lineStr, - rangeStartStringIndex, - currentStringIndex, - line, - rangeStartColumn - ); - for (let i = 0; i < joinedRanges.length; i++) { - ranges.push(joinedRanges[i]); - } - } - - // Reset our markers for a new range. - rangeStartColumn = x; - rangeStartStringIndex = currentStringIndex; - rangeAttrFG = this._workCell.fg; - rangeAttrBG = this._workCell.bg; - } - - currentStringIndex += this._workCell.getChars().length || WHITESPACE_CELL_CHAR.length; - } - - // Process any trailing ranges. - if (this._bufferService.cols - rangeStartColumn > 1) { - const joinedRanges = this._getJoinedRanges( - lineStr, - rangeStartStringIndex, - currentStringIndex, - line, - rangeStartColumn - ); - for (let i = 0; i < joinedRanges.length; i++) { - ranges.push(joinedRanges[i]); - } - } - - return ranges; - } - - /** - * Given a segment of a line of text, find all ranges of text that should be - * joined in a single rendering unit. Ranges are internally converted to - * column ranges, rather than string ranges. - * @param line String representation of the full line of text - * @param startIndex Start position of the range to search in the string (inclusive) - * @param endIndex End position of the range to search in the string (exclusive) - */ - private _getJoinedRanges(line: string, startIndex: number, endIndex: number, lineData: IBufferLine, startCol: number): [number, number][] { - const text = line.substring(startIndex, endIndex); - // At this point we already know that there is at least one joiner so - // we can just pull its value and assign it directly rather than - // merging it into an empty array, which incurs unnecessary writes. - let allJoinedRanges: [number, number][] = []; - try { - allJoinedRanges = this._characterJoiners[0].handler(text); - } catch (error) { - console.error(error); - } - for (let i = 1; i < this._characterJoiners.length; i++) { - // We merge any overlapping ranges across the different joiners - try { - const joinerRanges = this._characterJoiners[i].handler(text); - for (let j = 0; j < joinerRanges.length; j++) { - CharacterJoinerService._mergeRanges(allJoinedRanges, joinerRanges[j]); - } - } catch (error) { - console.error(error); - } - } - this._stringRangesToCellRanges(allJoinedRanges, lineData, startCol); - return allJoinedRanges; - } - - /** - * Modifies the provided ranges in-place to adjust for variations between - * string length and cell width so that the range represents a cell range, - * rather than the string range the joiner provides. - * @param ranges String ranges containing start (inclusive) and end (exclusive) index - * @param line Cell data for the relevant line in the terminal - * @param startCol Offset within the line to start from - */ - private _stringRangesToCellRanges(ranges: [number, number][], line: IBufferLine, startCol: number): void { - let currentRangeIndex = 0; - let currentRangeStarted = false; - let currentStringIndex = 0; - let currentRange = ranges[currentRangeIndex]; - - // If we got through all of the ranges, stop searching - if (!currentRange) { - return; - } - - for (let x = startCol; x < this._bufferService.cols; x++) { - const width = line.getWidth(x); - const length = line.getString(x).length || WHITESPACE_CELL_CHAR.length; - - // We skip zero-width characters when creating the string to join the text - // so we do the same here - if (width === 0) { - continue; - } - - // Adjust the start of the range - if (!currentRangeStarted && currentRange[0] <= currentStringIndex) { - currentRange[0] = x; - currentRangeStarted = true; - } - - // Adjust the end of the range - if (currentRange[1] <= currentStringIndex) { - currentRange[1] = x; - - // We're finished with this range, so we move to the next one - currentRange = ranges[++currentRangeIndex]; - - // If there are no more ranges left, stop searching - if (!currentRange) { - break; - } - - // Ranges can be on adjacent characters. Because the end index of the - // ranges are exclusive, this means that the index for the start of a - // range can be the same as the end index of the previous range. To - // account for the start of the next range, we check here just in case. - if (currentRange[0] <= currentStringIndex) { - currentRange[0] = x; - currentRangeStarted = true; - } else { - currentRangeStarted = false; - } - } - - // Adjust the string index based on the character length to line up with - // the column adjustment - currentStringIndex += length; - } - - // If there is still a range left at the end, it must extend all the way to - // the end of the line. - if (currentRange) { - currentRange[1] = this._bufferService.cols; - } - } - - /** - * Merges the range defined by the provided start and end into the list of - * existing ranges. The merge is done in place on the existing range for - * performance and is also returned. - * @param ranges Existing range list - * @param newRange Tuple of two numbers representing the new range to merge in. - * @returns The ranges input with the new range merged in place - */ - private static _mergeRanges(ranges: [number, number][], newRange: [number, number]): [number, number][] { - let inRange = false; - for (let i = 0; i < ranges.length; i++) { - const range = ranges[i]; - if (!inRange) { - if (newRange[1] <= range[0]) { - // Case 1: New range is before the search range - ranges.splice(i, 0, newRange); - return ranges; - } - - if (newRange[1] <= range[1]) { - // Case 2: New range is either wholly contained within the - // search range or overlaps with the front of it - range[0] = Math.min(newRange[0], range[0]); - return ranges; - } - - if (newRange[0] < range[1]) { - // Case 3: New range either wholly contains the search range - // or overlaps with the end of it - range[0] = Math.min(newRange[0], range[0]); - inRange = true; - } - - // Case 4: New range starts after the search range - continue; - } else { - if (newRange[1] <= range[0]) { - // Case 5: New range extends from previous range but doesn't - // reach the current one - ranges[i - 1][1] = newRange[1]; - return ranges; - } - - if (newRange[1] <= range[1]) { - // Case 6: New range extends from prvious range into the - // current range - ranges[i - 1][1] = Math.max(newRange[1], range[1]); - ranges.splice(i, 1); - return ranges; - } - - // Case 7: New range extends from previous range past the - // end of the current range - ranges.splice(i, 1); - i--; - } - } - - if (inRange) { - // Case 8: New range extends past the last existing range - ranges[ranges.length - 1][1] = newRange[1]; - } else { - // Case 9: New range starts after the last existing range - ranges.push(newRange); - } - - return ranges; - } -} diff --git a/node_modules/xterm/src/browser/services/CoreBrowserService.ts b/node_modules/xterm/src/browser/services/CoreBrowserService.ts deleted file mode 100644 index 4eabc89..0000000 --- a/node_modules/xterm/src/browser/services/CoreBrowserService.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { ICoreBrowserService } from './Services'; - -export class CoreBrowserService implements ICoreBrowserService { - public serviceBrand: undefined; - - constructor( - private _textarea: HTMLTextAreaElement - ) { - } - - public get isFocused(): boolean { - const docOrShadowRoot = this._textarea.getRootNode ? this._textarea.getRootNode() as Document | ShadowRoot : document; - return docOrShadowRoot.activeElement === this._textarea && document.hasFocus(); - } -} diff --git a/node_modules/xterm/src/browser/services/MouseService.ts b/node_modules/xterm/src/browser/services/MouseService.ts deleted file mode 100644 index 348ba64..0000000 --- a/node_modules/xterm/src/browser/services/MouseService.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { ICharSizeService, IRenderService, IMouseService } from './Services'; -import { getCoords, getRawByteCoords } from 'browser/input/Mouse'; - -export class MouseService implements IMouseService { - public serviceBrand: undefined; - - constructor( - @IRenderService private readonly _renderService: IRenderService, - @ICharSizeService private readonly _charSizeService: ICharSizeService - ) { - } - - public getCoords(event: {clientX: number, clientY: number}, element: HTMLElement, colCount: number, rowCount: number, isSelection?: boolean): [number, number] | undefined { - return getCoords( - event, - element, - colCount, - rowCount, - this._charSizeService.hasValidSize, - this._renderService.dimensions.actualCellWidth, - this._renderService.dimensions.actualCellHeight, - isSelection - ); - } - - public getRawByteCoords(event: MouseEvent, element: HTMLElement, colCount: number, rowCount: number): { x: number, y: number } | undefined { - const coords = this.getCoords(event, element, colCount, rowCount); - return getRawByteCoords(coords); - } -} diff --git a/node_modules/xterm/src/browser/services/RenderService.ts b/node_modules/xterm/src/browser/services/RenderService.ts deleted file mode 100644 index da458ab..0000000 --- a/node_modules/xterm/src/browser/services/RenderService.ts +++ /dev/null @@ -1,223 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IRenderer, IRenderDimensions } from 'browser/renderer/Types'; -import { RenderDebouncer } from 'browser/RenderDebouncer'; -import { EventEmitter, IEvent } from 'common/EventEmitter'; -import { Disposable } from 'common/Lifecycle'; -import { ScreenDprMonitor } from 'browser/ScreenDprMonitor'; -import { addDisposableDomListener } from 'browser/Lifecycle'; -import { IColorSet, IRenderDebouncer } from 'browser/Types'; -import { IOptionsService, IBufferService } from 'common/services/Services'; -import { ICharSizeService, IRenderService } from 'browser/services/Services'; - -interface ISelectionState { - start: [number, number] | undefined; - end: [number, number] | undefined; - columnSelectMode: boolean; -} - -export class RenderService extends Disposable implements IRenderService { - public serviceBrand: undefined; - - private _renderDebouncer: IRenderDebouncer; - private _screenDprMonitor: ScreenDprMonitor; - - private _isPaused: boolean = false; - private _needsFullRefresh: boolean = false; - private _isNextRenderRedrawOnly: boolean = true; - private _needsSelectionRefresh: boolean = false; - private _canvasWidth: number = 0; - private _canvasHeight: number = 0; - private _selectionState: ISelectionState = { - start: undefined, - end: undefined, - columnSelectMode: false - }; - - private _onDimensionsChange = new EventEmitter<IRenderDimensions>(); - public get onDimensionsChange(): IEvent<IRenderDimensions> { return this._onDimensionsChange.event; } - private _onRender = new EventEmitter<{ start: number, end: number }>(); - public get onRenderedBufferChange(): IEvent<{ start: number, end: number }> { return this._onRender.event; } - private _onRefreshRequest = new EventEmitter<{ start: number, end: number }>(); - public get onRefreshRequest(): IEvent<{ start: number, end: number }> { return this._onRefreshRequest.event; } - - public get dimensions(): IRenderDimensions { return this._renderer.dimensions; } - - constructor( - private _renderer: IRenderer, - private _rowCount: number, - screenElement: HTMLElement, - @IOptionsService optionsService: IOptionsService, - @ICharSizeService private readonly _charSizeService: ICharSizeService, - @IBufferService bufferService: IBufferService - ) { - super(); - - this.register({ dispose: () => this._renderer.dispose() }); - - this._renderDebouncer = new RenderDebouncer((start, end) => this._renderRows(start, end)); - this.register(this._renderDebouncer); - - this._screenDprMonitor = new ScreenDprMonitor(); - this._screenDprMonitor.setListener(() => this.onDevicePixelRatioChange()); - this.register(this._screenDprMonitor); - - this.register(bufferService.onResize(() => this._fullRefresh())); - this.register(bufferService.buffers.onBufferActivate(() => this._renderer?.clear())); - this.register(optionsService.onOptionChange(() => this._renderer.onOptionsChanged())); - this.register(this._charSizeService.onCharSizeChange(() => this.onCharSizeChanged())); - - // No need to register this as renderer is explicitly disposed in RenderService.dispose - this._renderer.onRequestRedraw(e => this.refreshRows(e.start, e.end, true)); - - // dprchange should handle this case, we need this as well for browsers that don't support the - // matchMedia query. - this.register(addDisposableDomListener(window, 'resize', () => this.onDevicePixelRatioChange())); - - // Detect whether IntersectionObserver is detected and enable renderer pause - // and resume based on terminal visibility if so - if ('IntersectionObserver' in window) { - const observer = new IntersectionObserver(e => this._onIntersectionChange(e[e.length - 1]), { threshold: 0 }); - observer.observe(screenElement); - this.register({ dispose: () => observer.disconnect() }); - } - } - - private _onIntersectionChange(entry: IntersectionObserverEntry): void { - this._isPaused = entry.isIntersecting === undefined ? (entry.intersectionRatio === 0) : !entry.isIntersecting; - - // Terminal was hidden on open - if (!this._isPaused && !this._charSizeService.hasValidSize) { - this._charSizeService.measure(); - } - - if (!this._isPaused && this._needsFullRefresh) { - this.refreshRows(0, this._rowCount - 1); - this._needsFullRefresh = false; - } - } - - public refreshRows(start: number, end: number, isRedrawOnly: boolean = false): void { - if (this._isPaused) { - this._needsFullRefresh = true; - return; - } - if (!isRedrawOnly) { - this._isNextRenderRedrawOnly = false; - } - this._renderDebouncer.refresh(start, end, this._rowCount); - } - - private _renderRows(start: number, end: number): void { - this._renderer.renderRows(start, end); - - // Update selection if needed - if (this._needsSelectionRefresh) { - this._renderer.onSelectionChanged(this._selectionState.start, this._selectionState.end, this._selectionState.columnSelectMode); - this._needsSelectionRefresh = false; - } - - // Fire render event only if it was not a redraw - if (!this._isNextRenderRedrawOnly) { - this._onRender.fire({ start, end }); - } - this._isNextRenderRedrawOnly = true; - } - - public resize(cols: number, rows: number): void { - this._rowCount = rows; - this._fireOnCanvasResize(); - } - - public changeOptions(): void { - this._renderer.onOptionsChanged(); - this.refreshRows(0, this._rowCount - 1); - this._fireOnCanvasResize(); - } - - private _fireOnCanvasResize(): void { - // Don't fire the event if the dimensions haven't changed - if (this._renderer.dimensions.canvasWidth === this._canvasWidth && this._renderer.dimensions.canvasHeight === this._canvasHeight) { - return; - } - this._onDimensionsChange.fire(this._renderer.dimensions); - } - - public dispose(): void { - super.dispose(); - } - - public setRenderer(renderer: IRenderer): void { - // TODO: RenderService should be the only one to dispose the renderer - this._renderer.dispose(); - this._renderer = renderer; - this._renderer.onRequestRedraw(e => this.refreshRows(e.start, e.end, true)); - - // Force a refresh - this._needsSelectionRefresh = true; - this._fullRefresh(); - } - - private _fullRefresh(): void { - if (this._isPaused) { - this._needsFullRefresh = true; - } else { - this.refreshRows(0, this._rowCount - 1); - } - } - - public clearTextureAtlas(): void { - this._renderer?.clearTextureAtlas?.(); - this._fullRefresh(); - } - - public setColors(colors: IColorSet): void { - this._renderer.setColors(colors); - this._fullRefresh(); - } - - public onDevicePixelRatioChange(): void { - // Force char size measurement as DomMeasureStrategy(getBoundingClientRect) is not stable - // when devicePixelRatio changes - this._charSizeService.measure(); - - this._renderer.onDevicePixelRatioChange(); - this.refreshRows(0, this._rowCount - 1); - } - - public onResize(cols: number, rows: number): void { - this._renderer.onResize(cols, rows); - this._fullRefresh(); - } - - // TODO: Is this useful when we have onResize? - public onCharSizeChanged(): void { - this._renderer.onCharSizeChanged(); - } - - public onBlur(): void { - this._renderer.onBlur(); - } - - public onFocus(): void { - this._renderer.onFocus(); - } - - public onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void { - this._selectionState.start = start; - this._selectionState.end = end; - this._selectionState.columnSelectMode = columnSelectMode; - this._renderer.onSelectionChanged(start, end, columnSelectMode); - } - - public onCursorMove(): void { - this._renderer.onCursorMove(); - } - - public clear(): void { - this._renderer.clear(); - } -} diff --git a/node_modules/xterm/src/browser/services/SelectionService.ts b/node_modules/xterm/src/browser/services/SelectionService.ts deleted file mode 100644 index 1ea2395..0000000 --- a/node_modules/xterm/src/browser/services/SelectionService.ts +++ /dev/null @@ -1,1009 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { ISelectionRedrawRequestEvent, ISelectionRequestScrollLinesEvent } from 'browser/selection/Types'; -import { IBuffer } from 'common/buffer/Types'; -import { IBufferLine, IDisposable } from 'common/Types'; -import * as Browser from 'common/Platform'; -import { SelectionModel } from 'browser/selection/SelectionModel'; -import { CellData } from 'common/buffer/CellData'; -import { EventEmitter, IEvent } from 'common/EventEmitter'; -import { IMouseService, ISelectionService, IRenderService } from 'browser/services/Services'; -import { ILinkifier2 } from 'browser/Types'; -import { IBufferService, IOptionsService, ICoreService } from 'common/services/Services'; -import { getCoordsRelativeToElement } from 'browser/input/Mouse'; -import { moveToCellSequence } from 'browser/input/MoveToCell'; -import { Disposable } from 'common/Lifecycle'; -import { getRangeLength } from 'common/buffer/BufferRange'; - -/** - * The number of pixels the mouse needs to be above or below the viewport in - * order to scroll at the maximum speed. - */ -const DRAG_SCROLL_MAX_THRESHOLD = 50; - -/** - * The maximum scrolling speed - */ -const DRAG_SCROLL_MAX_SPEED = 15; - -/** - * The number of milliseconds between drag scroll updates. - */ -const DRAG_SCROLL_INTERVAL = 50; - -/** - * The maximum amount of time that can have elapsed for an alt click to move the - * cursor. - */ -const ALT_CLICK_MOVE_CURSOR_TIME = 500; - -const NON_BREAKING_SPACE_CHAR = String.fromCharCode(160); -const ALL_NON_BREAKING_SPACE_REGEX = new RegExp(NON_BREAKING_SPACE_CHAR, 'g'); - -/** - * Represents a position of a word on a line. - */ -interface IWordPosition { - start: number; - length: number; -} - -/** - * A selection mode, this drives how the selection behaves on mouse move. - */ -export const enum SelectionMode { - NORMAL, - WORD, - LINE, - COLUMN -} - -/** - * A class that manages the selection of the terminal. With help from - * SelectionModel, SelectionService handles with all logic associated with - * dealing with the selection, including handling mouse interaction, wide - * characters and fetching the actual text within the selection. Rendering is - * not handled by the SelectionService but the onRedrawRequest event is fired - * when the selection is ready to be redrawn (on an animation frame). - */ -export class SelectionService extends Disposable implements ISelectionService { - public serviceBrand: undefined; - - protected _model: SelectionModel; - - /** - * The amount to scroll every drag scroll update (depends on how far the mouse - * drag is above or below the terminal). - */ - private _dragScrollAmount: number = 0; - - /** - * The current selection mode. - */ - protected _activeSelectionMode: SelectionMode; - - /** - * A setInterval timer that is active while the mouse is down whose callback - * scrolls the viewport when necessary. - */ - private _dragScrollIntervalTimer: number | undefined; - - /** - * The animation frame ID used for refreshing the selection. - */ - private _refreshAnimationFrame: number | undefined; - - /** - * Whether selection is enabled. - */ - private _enabled = true; - - private _mouseMoveListener: EventListener; - private _mouseUpListener: EventListener; - private _trimListener: IDisposable; - private _workCell: CellData = new CellData(); - - private _mouseDownTimeStamp: number = 0; - private _oldHasSelection: boolean = false; - private _oldSelectionStart: [number, number] | undefined = undefined; - private _oldSelectionEnd: [number, number] | undefined = undefined; - - private _onLinuxMouseSelection = this.register(new EventEmitter<string>()); - public get onLinuxMouseSelection(): IEvent<string> { return this._onLinuxMouseSelection.event; } - private _onRedrawRequest = this.register(new EventEmitter<ISelectionRedrawRequestEvent>()); - public get onRequestRedraw(): IEvent<ISelectionRedrawRequestEvent> { return this._onRedrawRequest.event; } - private _onSelectionChange = this.register(new EventEmitter<void>()); - public get onSelectionChange(): IEvent<void> { return this._onSelectionChange.event; } - private _onRequestScrollLines = this.register(new EventEmitter<ISelectionRequestScrollLinesEvent>()); - public get onRequestScrollLines(): IEvent<ISelectionRequestScrollLinesEvent> { return this._onRequestScrollLines.event; } - - constructor( - private readonly _element: HTMLElement, - private readonly _screenElement: HTMLElement, - private readonly _linkifier: ILinkifier2, - @IBufferService private readonly _bufferService: IBufferService, - @ICoreService private readonly _coreService: ICoreService, - @IMouseService private readonly _mouseService: IMouseService, - @IOptionsService private readonly _optionsService: IOptionsService, - @IRenderService private readonly _renderService: IRenderService - ) { - super(); - - // Init listeners - this._mouseMoveListener = event => this._onMouseMove(event as MouseEvent); - this._mouseUpListener = event => this._onMouseUp(event as MouseEvent); - this._coreService.onUserInput(() => { - if (this.hasSelection) { - this.clearSelection(); - } - }); - this._trimListener = this._bufferService.buffer.lines.onTrim(amount => this._onTrim(amount)); - this.register(this._bufferService.buffers.onBufferActivate(e => this._onBufferActivate(e))); - - this.enable(); - - this._model = new SelectionModel(this._bufferService); - this._activeSelectionMode = SelectionMode.NORMAL; - } - - public dispose(): void { - this._removeMouseDownListeners(); - } - - public reset(): void { - this.clearSelection(); - } - - /** - * Disables the selection manager. This is useful for when terminal mouse - * are enabled. - */ - public disable(): void { - this.clearSelection(); - this._enabled = false; - } - - /** - * Enable the selection manager. - */ - public enable(): void { - this._enabled = true; - } - - public get selectionStart(): [number, number] | undefined { return this._model.finalSelectionStart; } - public get selectionEnd(): [number, number] | undefined { return this._model.finalSelectionEnd; } - - /** - * Gets whether there is an active text selection. - */ - public get hasSelection(): boolean { - const start = this._model.finalSelectionStart; - const end = this._model.finalSelectionEnd; - if (!start || !end) { - return false; - } - return start[0] !== end[0] || start[1] !== end[1]; - } - - /** - * Gets the text currently selected. - */ - public get selectionText(): string { - const start = this._model.finalSelectionStart; - const end = this._model.finalSelectionEnd; - if (!start || !end) { - return ''; - } - - const buffer = this._bufferService.buffer; - const result: string[] = []; - - if (this._activeSelectionMode === SelectionMode.COLUMN) { - // Ignore zero width selections - if (start[0] === end[0]) { - return ''; - } - - for (let i = start[1]; i <= end[1]; i++) { - const lineText = buffer.translateBufferLineToString(i, true, start[0], end[0]); - result.push(lineText); - } - } else { - // Get first row - const startRowEndCol = start[1] === end[1] ? end[0] : undefined; - result.push(buffer.translateBufferLineToString(start[1], true, start[0], startRowEndCol)); - - // Get middle rows - for (let i = start[1] + 1; i <= end[1] - 1; i++) { - const bufferLine = buffer.lines.get(i); - const lineText = buffer.translateBufferLineToString(i, true); - if (bufferLine?.isWrapped) { - result[result.length - 1] += lineText; - } else { - result.push(lineText); - } - } - - // Get final row - if (start[1] !== end[1]) { - const bufferLine = buffer.lines.get(end[1]); - const lineText = buffer.translateBufferLineToString(end[1], true, 0, end[0]); - if (bufferLine && bufferLine!.isWrapped) { - result[result.length - 1] += lineText; - } else { - result.push(lineText); - } - } - } - - // Format string by replacing non-breaking space chars with regular spaces - // and joining the array into a multi-line string. - const formattedResult = result.map(line => { - return line.replace(ALL_NON_BREAKING_SPACE_REGEX, ' '); - }).join(Browser.isWindows ? '\r\n' : '\n'); - - return formattedResult; - } - - /** - * Clears the current terminal selection. - */ - public clearSelection(): void { - this._model.clearSelection(); - this._removeMouseDownListeners(); - this.refresh(); - this._onSelectionChange.fire(); - } - - /** - * Queues a refresh, redrawing the selection on the next opportunity. - * @param isLinuxMouseSelection Whether the selection should be registered as a new - * selection on Linux. - */ - public refresh(isLinuxMouseSelection?: boolean): void { - // Queue the refresh for the renderer - if (!this._refreshAnimationFrame) { - this._refreshAnimationFrame = window.requestAnimationFrame(() => this._refresh()); - } - - // If the platform is Linux and the refresh call comes from a mouse event, - // we need to update the selection for middle click to paste selection. - if (Browser.isLinux && isLinuxMouseSelection) { - const selectionText = this.selectionText; - if (selectionText.length) { - this._onLinuxMouseSelection.fire(this.selectionText); - } - } - } - - /** - * Fires the refresh event, causing consumers to pick it up and redraw the - * selection state. - */ - private _refresh(): void { - this._refreshAnimationFrame = undefined; - this._onRedrawRequest.fire({ - start: this._model.finalSelectionStart, - end: this._model.finalSelectionEnd, - columnSelectMode: this._activeSelectionMode === SelectionMode.COLUMN - }); - } - - /** - * Checks if the current click was inside the current selection - * @param event The mouse event - */ - private _isClickInSelection(event: MouseEvent): boolean { - const coords = this._getMouseBufferCoords(event); - const start = this._model.finalSelectionStart; - const end = this._model.finalSelectionEnd; - - if (!start || !end || !coords) { - return false; - } - - return this._areCoordsInSelection(coords, start, end); - } - - protected _areCoordsInSelection(coords: [number, number], start: [number, number], end: [number, number]): boolean { - return (coords[1] > start[1] && coords[1] < end[1]) || - (start[1] === end[1] && coords[1] === start[1] && coords[0] >= start[0] && coords[0] < end[0]) || - (start[1] < end[1] && coords[1] === end[1] && coords[0] < end[0]) || - (start[1] < end[1] && coords[1] === start[1] && coords[0] >= start[0]); - } - - /** - * Selects word at the current mouse event coordinates. - * @param event The mouse event. - */ - private _selectWordAtCursor(event: MouseEvent, allowWhitespaceOnlySelection: boolean): boolean { - // Check if there is a link under the cursor first and select that if so - const range = this._linkifier.currentLink?.link?.range; - if (range) { - this._model.selectionStart = [range.start.x - 1, range.start.y - 1]; - this._model.selectionStartLength = getRangeLength(range, this._bufferService.cols); - this._model.selectionEnd = undefined; - return true; - } - - const coords = this._getMouseBufferCoords(event); - if (coords) { - this._selectWordAt(coords, allowWhitespaceOnlySelection); - this._model.selectionEnd = undefined; - return true; - } - return false; - } - - /** - * Selects all text within the terminal. - */ - public selectAll(): void { - this._model.isSelectAllActive = true; - this.refresh(); - this._onSelectionChange.fire(); - } - - public selectLines(start: number, end: number): void { - this._model.clearSelection(); - start = Math.max(start, 0); - end = Math.min(end, this._bufferService.buffer.lines.length - 1); - this._model.selectionStart = [0, start]; - this._model.selectionEnd = [this._bufferService.cols, end]; - this.refresh(); - this._onSelectionChange.fire(); - } - - /** - * Handle the buffer being trimmed, adjust the selection position. - * @param amount The amount the buffer is being trimmed. - */ - private _onTrim(amount: number): void { - const needsRefresh = this._model.onTrim(amount); - if (needsRefresh) { - this.refresh(); - } - } - - /** - * Gets the 0-based [x, y] buffer coordinates of the current mouse event. - * @param event The mouse event. - */ - private _getMouseBufferCoords(event: MouseEvent): [number, number] | undefined { - const coords = this._mouseService.getCoords(event, this._screenElement, this._bufferService.cols, this._bufferService.rows, true); - if (!coords) { - return undefined; - } - - // Convert to 0-based - coords[0]--; - coords[1]--; - - // Convert viewport coords to buffer coords - coords[1] += this._bufferService.buffer.ydisp; - return coords; - } - - /** - * Gets the amount the viewport should be scrolled based on how far out of the - * terminal the mouse is. - * @param event The mouse event. - */ - private _getMouseEventScrollAmount(event: MouseEvent): number { - let offset = getCoordsRelativeToElement(event, this._screenElement)[1]; - const terminalHeight = this._renderService.dimensions.canvasHeight; - if (offset >= 0 && offset <= terminalHeight) { - return 0; - } - if (offset > terminalHeight) { - offset -= terminalHeight; - } - - offset = Math.min(Math.max(offset, -DRAG_SCROLL_MAX_THRESHOLD), DRAG_SCROLL_MAX_THRESHOLD); - offset /= DRAG_SCROLL_MAX_THRESHOLD; - return (offset / Math.abs(offset)) + Math.round(offset * (DRAG_SCROLL_MAX_SPEED - 1)); - } - - /** - * Returns whether the selection manager should force selection, regardless of - * whether the terminal is in mouse events mode. - * @param event The mouse event. - */ - public shouldForceSelection(event: MouseEvent): boolean { - if (Browser.isMac) { - return event.altKey && this._optionsService.rawOptions.macOptionClickForcesSelection; - } - - return event.shiftKey; - } - - /** - * Handles te mousedown event, setting up for a new selection. - * @param event The mousedown event. - */ - public onMouseDown(event: MouseEvent): void { - this._mouseDownTimeStamp = event.timeStamp; - // If we have selection, we want the context menu on right click even if the - // terminal is in mouse mode. - if (event.button === 2 && this.hasSelection) { - return; - } - - // Only action the primary button - if (event.button !== 0) { - return; - } - - // Allow selection when using a specific modifier key, even when disabled - if (!this._enabled) { - if (!this.shouldForceSelection(event)) { - return; - } - - // Don't send the mouse down event to the current process, we want to select - event.stopPropagation(); - } - - // Tell the browser not to start a regular selection - event.preventDefault(); - - // Reset drag scroll state - this._dragScrollAmount = 0; - - if (this._enabled && event.shiftKey) { - this._onIncrementalClick(event); - } else { - if (event.detail === 1) { - this._onSingleClick(event); - } else if (event.detail === 2) { - this._onDoubleClick(event); - } else if (event.detail === 3) { - this._onTripleClick(event); - } - } - - this._addMouseDownListeners(); - this.refresh(true); - } - - /** - * Adds listeners when mousedown is triggered. - */ - private _addMouseDownListeners(): void { - // Listen on the document so that dragging outside of viewport works - if (this._screenElement.ownerDocument) { - this._screenElement.ownerDocument.addEventListener('mousemove', this._mouseMoveListener); - this._screenElement.ownerDocument.addEventListener('mouseup', this._mouseUpListener); - } - this._dragScrollIntervalTimer = window.setInterval(() => this._dragScroll(), DRAG_SCROLL_INTERVAL); - } - - /** - * Removes the listeners that are registered when mousedown is triggered. - */ - private _removeMouseDownListeners(): void { - if (this._screenElement.ownerDocument) { - this._screenElement.ownerDocument.removeEventListener('mousemove', this._mouseMoveListener); - this._screenElement.ownerDocument.removeEventListener('mouseup', this._mouseUpListener); - } - clearInterval(this._dragScrollIntervalTimer); - this._dragScrollIntervalTimer = undefined; - } - - /** - * Performs an incremental click, setting the selection end position to the mouse - * position. - * @param event The mouse event. - */ - private _onIncrementalClick(event: MouseEvent): void { - if (this._model.selectionStart) { - this._model.selectionEnd = this._getMouseBufferCoords(event); - } - } - - /** - * Performs a single click, resetting relevant state and setting the selection - * start position. - * @param event The mouse event. - */ - private _onSingleClick(event: MouseEvent): void { - this._model.selectionStartLength = 0; - this._model.isSelectAllActive = false; - this._activeSelectionMode = this.shouldColumnSelect(event) ? SelectionMode.COLUMN : SelectionMode.NORMAL; - - // Initialize the new selection - this._model.selectionStart = this._getMouseBufferCoords(event); - if (!this._model.selectionStart) { - return; - } - this._model.selectionEnd = undefined; - - // Ensure the line exists - const line = this._bufferService.buffer.lines.get(this._model.selectionStart[1]); - if (!line) { - return; - } - - // Return early if the click event is not in the buffer (eg. in scroll bar) - if (line.length === this._model.selectionStart[0]) { - return; - } - - // If the mouse is over the second half of a wide character, adjust the - // selection to cover the whole character - if (line.hasWidth(this._model.selectionStart[0]) === 0) { - this._model.selectionStart[0]++; - } - } - - /** - * Performs a double click, selecting the current word. - * @param event The mouse event. - */ - private _onDoubleClick(event: MouseEvent): void { - if (this._selectWordAtCursor(event, true)) { - this._activeSelectionMode = SelectionMode.WORD; - } - } - - /** - * Performs a triple click, selecting the current line and activating line - * select mode. - * @param event The mouse event. - */ - private _onTripleClick(event: MouseEvent): void { - const coords = this._getMouseBufferCoords(event); - if (coords) { - this._activeSelectionMode = SelectionMode.LINE; - this._selectLineAt(coords[1]); - } - } - - /** - * Returns whether the selection manager should operate in column select mode - * @param event the mouse or keyboard event - */ - public shouldColumnSelect(event: KeyboardEvent | MouseEvent): boolean { - return event.altKey && !(Browser.isMac && this._optionsService.rawOptions.macOptionClickForcesSelection); - } - - /** - * Handles the mousemove event when the mouse button is down, recording the - * end of the selection and refreshing the selection. - * @param event The mousemove event. - */ - private _onMouseMove(event: MouseEvent): void { - // If the mousemove listener is active it means that a selection is - // currently being made, we should stop propagation to prevent mouse events - // to be sent to the pty. - event.stopImmediatePropagation(); - - // Do nothing if there is no selection start, this can happen if the first - // click in the terminal is an incremental click - if (!this._model.selectionStart) { - return; - } - - // Record the previous position so we know whether to redraw the selection - // at the end. - const previousSelectionEnd = this._model.selectionEnd ? [this._model.selectionEnd[0], this._model.selectionEnd[1]] : null; - - // Set the initial selection end based on the mouse coordinates - this._model.selectionEnd = this._getMouseBufferCoords(event); - if (!this._model.selectionEnd) { - this.refresh(true); - return; - } - - // Select the entire line if line select mode is active. - if (this._activeSelectionMode === SelectionMode.LINE) { - if (this._model.selectionEnd[1] < this._model.selectionStart[1]) { - this._model.selectionEnd[0] = 0; - } else { - this._model.selectionEnd[0] = this._bufferService.cols; - } - } else if (this._activeSelectionMode === SelectionMode.WORD) { - this._selectToWordAt(this._model.selectionEnd); - } - - // Determine the amount of scrolling that will happen. - this._dragScrollAmount = this._getMouseEventScrollAmount(event); - - // If the cursor was above or below the viewport, make sure it's at the - // start or end of the viewport respectively. This should only happen when - // NOT in column select mode. - if (this._activeSelectionMode !== SelectionMode.COLUMN) { - if (this._dragScrollAmount > 0) { - this._model.selectionEnd[0] = this._bufferService.cols; - } else if (this._dragScrollAmount < 0) { - this._model.selectionEnd[0] = 0; - } - } - - // If the character is a wide character include the cell to the right in the - // selection. Note that selections at the very end of the line will never - // have a character. - const buffer = this._bufferService.buffer; - if (this._model.selectionEnd[1] < buffer.lines.length) { - const line = buffer.lines.get(this._model.selectionEnd[1]); - if (line && line.hasWidth(this._model.selectionEnd[0]) === 0) { - this._model.selectionEnd[0]++; - } - } - - // Only draw here if the selection changes. - if (!previousSelectionEnd || - previousSelectionEnd[0] !== this._model.selectionEnd[0] || - previousSelectionEnd[1] !== this._model.selectionEnd[1]) { - this.refresh(true); - } - } - - /** - * The callback that occurs every DRAG_SCROLL_INTERVAL ms that does the - * scrolling of the viewport. - */ - private _dragScroll(): void { - if (!this._model.selectionEnd || !this._model.selectionStart) { - return; - } - if (this._dragScrollAmount) { - this._onRequestScrollLines.fire({ amount: this._dragScrollAmount, suppressScrollEvent: false }); - // Re-evaluate selection - // If the cursor was above or below the viewport, make sure it's at the - // start or end of the viewport respectively. This should only happen when - // NOT in column select mode. - const buffer = this._bufferService.buffer; - if (this._dragScrollAmount > 0) { - if (this._activeSelectionMode !== SelectionMode.COLUMN) { - this._model.selectionEnd[0] = this._bufferService.cols; - } - this._model.selectionEnd[1] = Math.min(buffer.ydisp + this._bufferService.rows, buffer.lines.length - 1); - } else { - if (this._activeSelectionMode !== SelectionMode.COLUMN) { - this._model.selectionEnd[0] = 0; - } - this._model.selectionEnd[1] = buffer.ydisp; - } - this.refresh(); - } - } - - /** - * Handles the mouseup event, removing the mousedown listeners. - * @param event The mouseup event. - */ - private _onMouseUp(event: MouseEvent): void { - const timeElapsed = event.timeStamp - this._mouseDownTimeStamp; - - this._removeMouseDownListeners(); - - if (this.selectionText.length <= 1 && timeElapsed < ALT_CLICK_MOVE_CURSOR_TIME && event.altKey && this._optionsService.getOption('altClickMovesCursor')) { - if (this._bufferService.buffer.ybase === this._bufferService.buffer.ydisp) { - const coordinates = this._mouseService.getCoords( - event, - this._element, - this._bufferService.cols, - this._bufferService.rows, - false - ); - if (coordinates && coordinates[0] !== undefined && coordinates[1] !== undefined) { - const sequence = moveToCellSequence(coordinates[0] - 1, coordinates[1] - 1, this._bufferService, this._coreService.decPrivateModes.applicationCursorKeys); - this._coreService.triggerDataEvent(sequence, true); - } - } - } else { - this._fireEventIfSelectionChanged(); - } - } - - private _fireEventIfSelectionChanged(): void { - const start = this._model.finalSelectionStart; - const end = this._model.finalSelectionEnd; - const hasSelection = !!start && !!end && (start[0] !== end[0] || start[1] !== end[1]); - - if (!hasSelection) { - if (this._oldHasSelection) { - this._fireOnSelectionChange(start, end, hasSelection); - } - return; - } - - // Sanity check, these should not be undefined as there is a selection - if (!start || !end) { - return; - } - - if (!this._oldSelectionStart || !this._oldSelectionEnd || ( - start[0] !== this._oldSelectionStart[0] || start[1] !== this._oldSelectionStart[1] || - end[0] !== this._oldSelectionEnd[0] || end[1] !== this._oldSelectionEnd[1])) { - - this._fireOnSelectionChange(start, end, hasSelection); - } - } - - private _fireOnSelectionChange(start: [number, number] | undefined, end: [number, number] | undefined, hasSelection: boolean): void { - this._oldSelectionStart = start; - this._oldSelectionEnd = end; - this._oldHasSelection = hasSelection; - this._onSelectionChange.fire(); - } - - private _onBufferActivate(e: {activeBuffer: IBuffer, inactiveBuffer: IBuffer}): void { - this.clearSelection(); - // Only adjust the selection on trim, shiftElements is rarely used (only in - // reverseIndex) and delete in a splice is only ever used when the same - // number of elements was just added. Given this is could actually be - // beneficial to leave the selection as is for these cases. - this._trimListener.dispose(); - this._trimListener = e.activeBuffer.lines.onTrim(amount => this._onTrim(amount)); - } - - /** - * Converts a viewport column to the character index on the buffer line, the - * latter takes into account wide characters. - * @param coords The coordinates to find the 2 index for. - */ - private _convertViewportColToCharacterIndex(bufferLine: IBufferLine, coords: [number, number]): number { - let charIndex = coords[0]; - for (let i = 0; coords[0] >= i; i++) { - const length = bufferLine.loadCell(i, this._workCell).getChars().length; - if (this._workCell.getWidth() === 0) { - // Wide characters aren't included in the line string so decrement the - // index so the index is back on the wide character. - charIndex--; - } else if (length > 1 && coords[0] !== i) { - // Emojis take up multiple characters, so adjust accordingly. For these - // we don't want ot include the character at the column as we're - // returning the start index in the string, not the end index. - charIndex += length - 1; - } - } - return charIndex; - } - - public setSelection(col: number, row: number, length: number): void { - this._model.clearSelection(); - this._removeMouseDownListeners(); - this._model.selectionStart = [col, row]; - this._model.selectionStartLength = length; - this.refresh(); - } - - public rightClickSelect(ev: MouseEvent): void { - if (!this._isClickInSelection(ev)) { - if (this._selectWordAtCursor(ev, false)) { - this.refresh(true); - } - this._fireEventIfSelectionChanged(); - } - } - - /** - * Gets positional information for the word at the coordinated specified. - * @param coords The coordinates to get the word at. - */ - private _getWordAt(coords: [number, number], allowWhitespaceOnlySelection: boolean, followWrappedLinesAbove: boolean = true, followWrappedLinesBelow: boolean = true): IWordPosition | undefined { - // Ensure coords are within viewport (eg. not within scroll bar) - if (coords[0] >= this._bufferService.cols) { - return undefined; - } - - const buffer = this._bufferService.buffer; - const bufferLine = buffer.lines.get(coords[1]); - if (!bufferLine) { - return undefined; - } - - const line = buffer.translateBufferLineToString(coords[1], false); - - // Get actual index, taking into consideration wide characters - let startIndex = this._convertViewportColToCharacterIndex(bufferLine, coords); - let endIndex = startIndex; - - // Record offset to be used later - const charOffset = coords[0] - startIndex; - let leftWideCharCount = 0; - let rightWideCharCount = 0; - let leftLongCharOffset = 0; - let rightLongCharOffset = 0; - - if (line.charAt(startIndex) === ' ') { - // Expand until non-whitespace is hit - while (startIndex > 0 && line.charAt(startIndex - 1) === ' ') { - startIndex--; - } - while (endIndex < line.length && line.charAt(endIndex + 1) === ' ') { - endIndex++; - } - } else { - // Expand until whitespace is hit. This algorithm works by scanning left - // and right from the starting position, keeping both the index format - // (line) and the column format (bufferLine) in sync. When a wide - // character is hit, it is recorded and the column index is adjusted. - let startCol = coords[0]; - let endCol = coords[0]; - - // Consider the initial position, skip it and increment the wide char - // variable - if (bufferLine.getWidth(startCol) === 0) { - leftWideCharCount++; - startCol--; - } - if (bufferLine.getWidth(endCol) === 2) { - rightWideCharCount++; - endCol++; - } - - // Adjust the end index for characters whose length are > 1 (emojis) - const length = bufferLine.getString(endCol).length; - if (length > 1) { - rightLongCharOffset += length - 1; - endIndex += length - 1; - } - - // Expand the string in both directions until a space is hit - while (startCol > 0 && startIndex > 0 && !this._isCharWordSeparator(bufferLine.loadCell(startCol - 1, this._workCell))) { - bufferLine.loadCell(startCol - 1, this._workCell); - const length = this._workCell.getChars().length; - if (this._workCell.getWidth() === 0) { - // If the next character is a wide char, record it and skip the column - leftWideCharCount++; - startCol--; - } else if (length > 1) { - // If the next character's string is longer than 1 char (eg. emoji), - // adjust the index - leftLongCharOffset += length - 1; - startIndex -= length - 1; - } - startIndex--; - startCol--; - } - while (endCol < bufferLine.length && endIndex + 1 < line.length && !this._isCharWordSeparator(bufferLine.loadCell(endCol + 1, this._workCell))) { - bufferLine.loadCell(endCol + 1, this._workCell); - const length = this._workCell.getChars().length; - if (this._workCell.getWidth() === 2) { - // If the next character is a wide char, record it and skip the column - rightWideCharCount++; - endCol++; - } else if (length > 1) { - // If the next character's string is longer than 1 char (eg. emoji), - // adjust the index - rightLongCharOffset += length - 1; - endIndex += length - 1; - } - endIndex++; - endCol++; - } - } - - // Incremenet the end index so it is at the start of the next character - endIndex++; - - // Calculate the start _column_, converting the the string indexes back to - // column coordinates. - let start = - startIndex // The index of the selection's start char in the line string - + charOffset // The difference between the initial char's column and index - - leftWideCharCount // The number of wide chars left of the initial char - + leftLongCharOffset; // The number of additional chars left of the initial char added by columns with strings longer than 1 (emojis) - - // Calculate the length in _columns_, converting the the string indexes back - // to column coordinates. - let length = Math.min(this._bufferService.cols, // Disallow lengths larger than the terminal cols - endIndex // The index of the selection's end char in the line string - - startIndex // The index of the selection's start char in the line string - + leftWideCharCount // The number of wide chars left of the initial char - + rightWideCharCount // The number of wide chars right of the initial char (inclusive) - - leftLongCharOffset // The number of additional chars left of the initial char added by columns with strings longer than 1 (emojis) - - rightLongCharOffset); // The number of additional chars right of the initial char (inclusive) added by columns with strings longer than 1 (emojis) - - if (!allowWhitespaceOnlySelection && line.slice(startIndex, endIndex).trim() === '') { - return undefined; - } - - // Recurse upwards if the line is wrapped and the word wraps to the above line - if (followWrappedLinesAbove) { - if (start === 0 && bufferLine.getCodePoint(0) !== 32 /* ' ' */) { - const previousBufferLine = buffer.lines.get(coords[1] - 1); - if (previousBufferLine && bufferLine.isWrapped && previousBufferLine.getCodePoint(this._bufferService.cols - 1) !== 32 /* ' ' */) { - const previousLineWordPosition = this._getWordAt([this._bufferService.cols - 1, coords[1] - 1], false, true, false); - if (previousLineWordPosition) { - const offset = this._bufferService.cols - previousLineWordPosition.start; - start -= offset; - length += offset; - } - } - } - } - - // Recurse downwards if the line is wrapped and the word wraps to the next line - if (followWrappedLinesBelow) { - if (start + length === this._bufferService.cols && bufferLine.getCodePoint(this._bufferService.cols - 1) !== 32 /* ' ' */) { - const nextBufferLine = buffer.lines.get(coords[1] + 1); - if (nextBufferLine?.isWrapped && nextBufferLine.getCodePoint(0) !== 32 /* ' ' */) { - const nextLineWordPosition = this._getWordAt([0, coords[1] + 1], false, false, true); - if (nextLineWordPosition) { - length += nextLineWordPosition.length; - } - } - } - } - - return { start, length }; - } - - /** - * Selects the word at the coordinates specified. - * @param coords The coordinates to get the word at. - * @param allowWhitespaceOnlySelection If whitespace should be selected - */ - protected _selectWordAt(coords: [number, number], allowWhitespaceOnlySelection: boolean): void { - const wordPosition = this._getWordAt(coords, allowWhitespaceOnlySelection); - if (wordPosition) { - // Adjust negative start value - while (wordPosition.start < 0) { - wordPosition.start += this._bufferService.cols; - coords[1]--; - } - this._model.selectionStart = [wordPosition.start, coords[1]]; - this._model.selectionStartLength = wordPosition.length; - } - } - - /** - * Sets the selection end to the word at the coordinated specified. - * @param coords The coordinates to get the word at. - */ - private _selectToWordAt(coords: [number, number]): void { - const wordPosition = this._getWordAt(coords, true); - if (wordPosition) { - let endRow = coords[1]; - - // Adjust negative start value - while (wordPosition.start < 0) { - wordPosition.start += this._bufferService.cols; - endRow--; - } - - // Adjust wrapped length value, this only needs to happen when values are reversed as in that - // case we're interested in the start of the word, not the end - if (!this._model.areSelectionValuesReversed()) { - while (wordPosition.start + wordPosition.length > this._bufferService.cols) { - wordPosition.length -= this._bufferService.cols; - endRow++; - } - } - - this._model.selectionEnd = [this._model.areSelectionValuesReversed() ? wordPosition.start : wordPosition.start + wordPosition.length, endRow]; - } - } - - /** - * Gets whether the character is considered a word separator by the select - * word logic. - * @param char The character to check. - */ - private _isCharWordSeparator(cell: CellData): boolean { - // Zero width characters are never separators as they are always to the - // right of wide characters - if (cell.getWidth() === 0) { - return false; - } - return this._optionsService.rawOptions.wordSeparator.indexOf(cell.getChars()) >= 0; - } - - /** - * Selects the line specified. - * @param line The line index. - */ - protected _selectLineAt(line: number): void { - const wrappedRange = this._bufferService.buffer.getWrappedRangeForLine(line); - this._model.selectionStart = [0, wrappedRange.first]; - this._model.selectionEnd = [this._bufferService.cols, wrappedRange.last]; - this._model.selectionStartLength = 0; - } -} diff --git a/node_modules/xterm/src/browser/services/Services.ts b/node_modules/xterm/src/browser/services/Services.ts deleted file mode 100644 index 7faf3f0..0000000 --- a/node_modules/xterm/src/browser/services/Services.ts +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IEvent } from 'common/EventEmitter'; -import { IRenderDimensions, IRenderer } from 'browser/renderer/Types'; -import { IColorSet } from 'browser/Types'; -import { ISelectionRedrawRequestEvent as ISelectionRequestRedrawEvent, ISelectionRequestScrollLinesEvent } from 'browser/selection/Types'; -import { createDecorator } from 'common/services/ServiceRegistry'; -import { IDisposable } from 'common/Types'; -import { IDecorationOptions, IDecoration } from 'xterm'; -import { IBufferService } from 'common/services/Services'; - -export const ICharSizeService = createDecorator<ICharSizeService>('CharSizeService'); -export interface ICharSizeService { - serviceBrand: undefined; - - readonly width: number; - readonly height: number; - readonly hasValidSize: boolean; - - readonly onCharSizeChange: IEvent<void>; - - measure(): void; -} - -export const ICoreBrowserService = createDecorator<ICoreBrowserService>('CoreBrowserService'); -export interface ICoreBrowserService { - serviceBrand: undefined; - - readonly isFocused: boolean; -} - -export const IMouseService = createDecorator<IMouseService>('MouseService'); -export interface IMouseService { - serviceBrand: undefined; - - getCoords(event: {clientX: number, clientY: number}, element: HTMLElement, colCount: number, rowCount: number, isSelection?: boolean): [number, number] | undefined; - getRawByteCoords(event: MouseEvent, element: HTMLElement, colCount: number, rowCount: number): { x: number, y: number } | undefined; -} - -export const IRenderService = createDecorator<IRenderService>('RenderService'); -export interface IRenderService extends IDisposable { - serviceBrand: undefined; - - onDimensionsChange: IEvent<IRenderDimensions>; - /** - * Fires when buffer changes are rendered. This does not fire when only cursor - * or selections are rendered. - */ - onRenderedBufferChange: IEvent<{ start: number, end: number }>; - onRefreshRequest: IEvent<{ start: number, end: number }>; - - dimensions: IRenderDimensions; - - refreshRows(start: number, end: number): void; - clearTextureAtlas(): void; - resize(cols: number, rows: number): void; - changeOptions(): void; - setRenderer(renderer: IRenderer): void; - setColors(colors: IColorSet): void; - onDevicePixelRatioChange(): void; - onResize(cols: number, rows: number): void; - // TODO: Is this useful when we have onResize? - onCharSizeChanged(): void; - onBlur(): void; - onFocus(): void; - onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void; - onCursorMove(): void; - clear(): void; -} - -export const ISelectionService = createDecorator<ISelectionService>('SelectionService'); -export interface ISelectionService { - serviceBrand: undefined; - - readonly selectionText: string; - readonly hasSelection: boolean; - readonly selectionStart: [number, number] | undefined; - readonly selectionEnd: [number, number] | undefined; - - readonly onLinuxMouseSelection: IEvent<string>; - readonly onRequestRedraw: IEvent<ISelectionRequestRedrawEvent>; - readonly onRequestScrollLines: IEvent<ISelectionRequestScrollLinesEvent>; - readonly onSelectionChange: IEvent<void>; - - disable(): void; - enable(): void; - reset(): void; - setSelection(row: number, col: number, length: number): void; - selectAll(): void; - selectLines(start: number, end: number): void; - clearSelection(): void; - rightClickSelect(event: MouseEvent): void; - shouldColumnSelect(event: KeyboardEvent | MouseEvent): boolean; - shouldForceSelection(event: MouseEvent): boolean; - refresh(isLinuxMouseSelection?: boolean): void; - onMouseDown(event: MouseEvent): void; -} - -export const ISoundService = createDecorator<ISoundService>('SoundService'); -export interface ISoundService { - serviceBrand: undefined; - - playBellSound(): void; -} - - -export const ICharacterJoinerService = createDecorator<ICharacterJoinerService>('CharacterJoinerService'); -export interface ICharacterJoinerService { - serviceBrand: undefined; - - register(handler: (text: string) => [number, number][]): number; - deregister(joinerId: number): boolean; - getJoinedCharacters(row: number): [number, number][]; -} - - -export const IDecorationService = createDecorator<IDecorationService>('DecorationService'); -export interface IDecorationService extends IDisposable { - registerDecoration(decorationOptions: IDecorationOptions): IDecoration | undefined; - refresh(): void; - attachToDom(screenElement: HTMLElement, renderService: IRenderService, bufferService: IBufferService): void; -} diff --git a/node_modules/xterm/src/browser/services/SoundService.ts b/node_modules/xterm/src/browser/services/SoundService.ts deleted file mode 100644 index a3b6800..0000000 --- a/node_modules/xterm/src/browser/services/SoundService.ts +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (c) 2018 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IOptionsService } from 'common/services/Services'; -import { ISoundService } from 'browser/services/Services'; - -export class SoundService implements ISoundService { - public serviceBrand: undefined; - - private static _audioContext: AudioContext; - - public static get audioContext(): AudioContext | null { - if (!SoundService._audioContext) { - const audioContextCtor: typeof AudioContext = (window as any).AudioContext || (window as any).webkitAudioContext; - if (!audioContextCtor) { - console.warn('Web Audio API is not supported by this browser. Consider upgrading to the latest version'); - return null; - } - SoundService._audioContext = new audioContextCtor(); - } - return SoundService._audioContext; - } - - constructor( - @IOptionsService private _optionsService: IOptionsService - ) { - } - - public playBellSound(): void { - const ctx = SoundService.audioContext; - if (!ctx) { - return; - } - const bellAudioSource = ctx.createBufferSource(); - ctx.decodeAudioData(this._base64ToArrayBuffer(this._removeMimeType(this._optionsService.rawOptions.bellSound)), (buffer) => { - bellAudioSource.buffer = buffer; - bellAudioSource.connect(ctx.destination); - bellAudioSource.start(0); - }); - } - - private _base64ToArrayBuffer(base64: string): ArrayBuffer { - const binaryString = window.atob(base64); - const len = binaryString.length; - const bytes = new Uint8Array(len); - - for (let i = 0; i < len; i++) { - bytes[i] = binaryString.charCodeAt(i); - } - - return bytes.buffer; - } - - private _removeMimeType(dataURI: string): string { - // Split the input to get the mime-type and the data itself - const splitUri = dataURI.split(','); - - // Return only the data - return splitUri[1]; - } -} diff --git a/node_modules/xterm/src/common/CircularList.ts b/node_modules/xterm/src/common/CircularList.ts deleted file mode 100644 index 4d2c04e..0000000 --- a/node_modules/xterm/src/common/CircularList.ts +++ /dev/null @@ -1,239 +0,0 @@ -/** - * Copyright (c) 2016 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { ICircularList } from 'common/Types'; -import { EventEmitter, IEvent } from 'common/EventEmitter'; - -export interface IInsertEvent { - index: number; - amount: number; -} - -export interface IDeleteEvent { - index: number; - amount: number; -} - -/** - * Represents a circular list; a list with a maximum size that wraps around when push is called, - * overriding values at the start of the list. - */ -export class CircularList<T> implements ICircularList<T> { - protected _array: (T | undefined)[]; - private _startIndex: number; - private _length: number; - - public onDeleteEmitter = new EventEmitter<IDeleteEvent>(); - public get onDelete(): IEvent<IDeleteEvent> { return this.onDeleteEmitter.event; } - public onInsertEmitter = new EventEmitter<IInsertEvent>(); - public get onInsert(): IEvent<IInsertEvent> { return this.onInsertEmitter.event; } - public onTrimEmitter = new EventEmitter<number>(); - public get onTrim(): IEvent<number> { return this.onTrimEmitter.event; } - - constructor( - private _maxLength: number - ) { - this._array = new Array<T>(this._maxLength); - this._startIndex = 0; - this._length = 0; - } - - public get maxLength(): number { - return this._maxLength; - } - - public set maxLength(newMaxLength: number) { - // There was no change in maxLength, return early. - if (this._maxLength === newMaxLength) { - return; - } - - // Reconstruct array, starting at index 0. Only transfer values from the - // indexes 0 to length. - const newArray = new Array<T | undefined>(newMaxLength); - for (let i = 0; i < Math.min(newMaxLength, this.length); i++) { - newArray[i] = this._array[this._getCyclicIndex(i)]; - } - this._array = newArray; - this._maxLength = newMaxLength; - this._startIndex = 0; - } - - public get length(): number { - return this._length; - } - - public set length(newLength: number) { - if (newLength > this._length) { - for (let i = this._length; i < newLength; i++) { - this._array[i] = undefined; - } - } - this._length = newLength; - } - - /** - * Gets the value at an index. - * - * Note that for performance reasons there is no bounds checking here, the index reference is - * circular so this should always return a value and never throw. - * @param index The index of the value to get. - * @return The value corresponding to the index. - */ - public get(index: number): T | undefined { - return this._array[this._getCyclicIndex(index)]; - } - - /** - * Sets the value at an index. - * - * Note that for performance reasons there is no bounds checking here, the index reference is - * circular so this should always return a value and never throw. - * @param index The index to set. - * @param value The value to set. - */ - public set(index: number, value: T | undefined): void { - this._array[this._getCyclicIndex(index)] = value; - } - - /** - * Pushes a new value onto the list, wrapping around to the start of the array, overriding index 0 - * if the maximum length is reached. - * @param value The value to push onto the list. - */ - public push(value: T): void { - this._array[this._getCyclicIndex(this._length)] = value; - if (this._length === this._maxLength) { - this._startIndex = ++this._startIndex % this._maxLength; - this.onTrimEmitter.fire(1); - } else { - this._length++; - } - } - - /** - * Advance ringbuffer index and return current element for recycling. - * Note: The buffer must be full for this method to work. - * @throws When the buffer is not full. - */ - public recycle(): T { - if (this._length !== this._maxLength) { - throw new Error('Can only recycle when the buffer is full'); - } - this._startIndex = ++this._startIndex % this._maxLength; - this.onTrimEmitter.fire(1); - return this._array[this._getCyclicIndex(this._length - 1)]!; - } - - /** - * Ringbuffer is at max length. - */ - public get isFull(): boolean { - return this._length === this._maxLength; - } - - /** - * Removes and returns the last value on the list. - * @return The popped value. - */ - public pop(): T | undefined { - return this._array[this._getCyclicIndex(this._length-- - 1)]; - } - - /** - * Deletes and/or inserts items at a particular index (in that order). Unlike - * Array.prototype.splice, this operation does not return the deleted items as a new array in - * order to save creating a new array. Note that this operation may shift all values in the list - * in the worst case. - * @param start The index to delete and/or insert. - * @param deleteCount The number of elements to delete. - * @param items The items to insert. - */ - public splice(start: number, deleteCount: number, ...items: T[]): void { - // Delete items - if (deleteCount) { - for (let i = start; i < this._length - deleteCount; i++) { - this._array[this._getCyclicIndex(i)] = this._array[this._getCyclicIndex(i + deleteCount)]; - } - this._length -= deleteCount; - this.onDeleteEmitter.fire({ index: start, amount: deleteCount }); - } - - // Add items - for (let i = this._length - 1; i >= start; i--) { - this._array[this._getCyclicIndex(i + items.length)] = this._array[this._getCyclicIndex(i)]; - } - for (let i = 0; i < items.length; i++) { - this._array[this._getCyclicIndex(start + i)] = items[i]; - } - if (items.length) { - this.onInsertEmitter.fire({ index: start, amount: items.length }); - } - - // Adjust length as needed - if (this._length + items.length > this._maxLength) { - const countToTrim = (this._length + items.length) - this._maxLength; - this._startIndex += countToTrim; - this._length = this._maxLength; - this.onTrimEmitter.fire(countToTrim); - } else { - this._length += items.length; - } - } - - /** - * Trims a number of items from the start of the list. - * @param count The number of items to remove. - */ - public trimStart(count: number): void { - if (count > this._length) { - count = this._length; - } - this._startIndex += count; - this._length -= count; - this.onTrimEmitter.fire(count); - } - - public shiftElements(start: number, count: number, offset: number): void { - if (count <= 0) { - return; - } - if (start < 0 || start >= this._length) { - throw new Error('start argument out of range'); - } - if (start + offset < 0) { - throw new Error('Cannot shift elements in list beyond index 0'); - } - - if (offset > 0) { - for (let i = count - 1; i >= 0; i--) { - this.set(start + i + offset, this.get(start + i)); - } - const expandListBy = (start + count + offset) - this._length; - if (expandListBy > 0) { - this._length += expandListBy; - while (this._length > this._maxLength) { - this._length--; - this._startIndex++; - this.onTrimEmitter.fire(1); - } - } - } else { - for (let i = 0; i < count; i++) { - this.set(start + i + offset, this.get(start + i)); - } - } - } - - /** - * Gets the cyclic index for the specified regular index. The cyclic index can then be used on the - * backing array to get the element associated with the regular index. - * @param index The regular index. - * @returns The cyclic index. - */ - private _getCyclicIndex(index: number): number { - return (this._startIndex + index) % this._maxLength; - } -} diff --git a/node_modules/xterm/src/common/Clone.ts b/node_modules/xterm/src/common/Clone.ts deleted file mode 100644 index 37821fe..0000000 --- a/node_modules/xterm/src/common/Clone.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2016 The xterm.js authors. All rights reserved. - * @license MIT - */ - -/* - * A simple utility for cloning values - */ -export function clone<T>(val: T, depth: number = 5): T { - if (typeof val !== 'object') { - return val; - } - - // If we're cloning an array, use an array as the base, otherwise use an object - const clonedObject: any = Array.isArray(val) ? [] : {}; - - for (const key in val) { - // Recursively clone eack item unless we're at the maximum depth - clonedObject[key] = depth <= 1 ? val[key] : (val[key] && clone(val[key], depth - 1)); - } - - return clonedObject as T; -} diff --git a/node_modules/xterm/src/common/CoreTerminal.ts b/node_modules/xterm/src/common/CoreTerminal.ts deleted file mode 100644 index 12b374c..0000000 --- a/node_modules/xterm/src/common/CoreTerminal.ts +++ /dev/null @@ -1,297 +0,0 @@ -/** - * Copyright (c) 2014-2020 The xterm.js authors. All rights reserved. - * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License) - * @license MIT - * - * Originally forked from (with the author's permission): - * Fabrice Bellard's javascript vt100 for jslinux: - * http://bellard.org/jslinux/ - * Copyright (c) 2011 Fabrice Bellard - * The original design remains. The terminal itself - * has been extended to include xterm CSI codes, among - * other features. - * - * Terminal Emulation References: - * http://vt100.net/ - * http://invisible-island.net/xterm/ctlseqs/ctlseqs.txt - * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html - * http://invisible-island.net/vttest/ - * http://www.inwap.com/pdp10/ansicode.txt - * http://linux.die.net/man/4/console_codes - * http://linux.die.net/man/7/urxvt - */ - -import { Disposable } from 'common/Lifecycle'; -import { IInstantiationService, IOptionsService, IBufferService, ILogService, ICharsetService, ICoreService, ICoreMouseService, IUnicodeService, IDirtyRowService, LogLevelEnum, ITerminalOptions } from 'common/services/Services'; -import { InstantiationService } from 'common/services/InstantiationService'; -import { LogService } from 'common/services/LogService'; -import { BufferService, MINIMUM_COLS, MINIMUM_ROWS } from 'common/services/BufferService'; -import { OptionsService } from 'common/services/OptionsService'; -import { IDisposable, IBufferLine, IAttributeData, ICoreTerminal, IKeyboardEvent, IScrollEvent, ScrollSource, ITerminalOptions as IPublicTerminalOptions } from 'common/Types'; -import { CoreService } from 'common/services/CoreService'; -import { EventEmitter, IEvent, forwardEvent } from 'common/EventEmitter'; -import { CoreMouseService } from 'common/services/CoreMouseService'; -import { DirtyRowService } from 'common/services/DirtyRowService'; -import { UnicodeService } from 'common/services/UnicodeService'; -import { CharsetService } from 'common/services/CharsetService'; -import { updateWindowsModeWrappedState } from 'common/WindowsMode'; -import { IFunctionIdentifier, IParams } from 'common/parser/Types'; -import { IBufferSet } from 'common/buffer/Types'; -import { InputHandler } from 'common/InputHandler'; -import { WriteBuffer } from 'common/input/WriteBuffer'; - -// Only trigger this warning a single time per session -let hasWriteSyncWarnHappened = false; - -export abstract class CoreTerminal extends Disposable implements ICoreTerminal { - protected readonly _instantiationService: IInstantiationService; - protected readonly _bufferService: IBufferService; - protected readonly _logService: ILogService; - protected readonly _charsetService: ICharsetService; - protected readonly _dirtyRowService: IDirtyRowService; - - public readonly coreMouseService: ICoreMouseService; - public readonly coreService: ICoreService; - public readonly unicodeService: IUnicodeService; - public readonly optionsService: IOptionsService; - - protected _inputHandler: InputHandler; - private _writeBuffer: WriteBuffer; - private _windowsMode: IDisposable | undefined; - - private _onBinary = new EventEmitter<string>(); - public get onBinary(): IEvent<string> { return this._onBinary.event; } - private _onData = new EventEmitter<string>(); - public get onData(): IEvent<string> { return this._onData.event; } - protected _onLineFeed = new EventEmitter<void>(); - public get onLineFeed(): IEvent<void> { return this._onLineFeed.event; } - private _onResize = new EventEmitter<{ cols: number, rows: number }>(); - public get onResize(): IEvent<{ cols: number, rows: number }> { return this._onResize.event; } - protected _onScroll = new EventEmitter<IScrollEvent, void>(); - /** - * Internally we track the source of the scroll but this is meaningless outside the library so - * it's filtered out. - */ - protected _onScrollApi?: EventEmitter<number, void>; - public get onScroll(): IEvent<number, void> { - if (!this._onScrollApi) { - this._onScrollApi = new EventEmitter<number, void>(); - this.register(this._onScroll.event(ev => { - this._onScrollApi?.fire(ev.position); - })); - } - return this._onScrollApi.event; - } - - public get cols(): number { return this._bufferService.cols; } - public get rows(): number { return this._bufferService.rows; } - public get buffers(): IBufferSet { return this._bufferService.buffers; } - public get options(): ITerminalOptions { return this.optionsService.options; } - public set options(options: ITerminalOptions) { - for (const key in options) { - this.optionsService.options[key] = options[key]; - } - } - - constructor( - options: Partial<ITerminalOptions> - ) { - super(); - - // Setup and initialize services - this._instantiationService = new InstantiationService(); - this.optionsService = new OptionsService(options); - this._instantiationService.setService(IOptionsService, this.optionsService); - this._bufferService = this.register(this._instantiationService.createInstance(BufferService)); - this._instantiationService.setService(IBufferService, this._bufferService); - this._logService = this._instantiationService.createInstance(LogService); - this._instantiationService.setService(ILogService, this._logService); - this.coreService = this.register(this._instantiationService.createInstance(CoreService, () => this.scrollToBottom())); - this._instantiationService.setService(ICoreService, this.coreService); - this.coreMouseService = this._instantiationService.createInstance(CoreMouseService); - this._instantiationService.setService(ICoreMouseService, this.coreMouseService); - this._dirtyRowService = this._instantiationService.createInstance(DirtyRowService); - this._instantiationService.setService(IDirtyRowService, this._dirtyRowService); - this.unicodeService = this._instantiationService.createInstance(UnicodeService); - this._instantiationService.setService(IUnicodeService, this.unicodeService); - this._charsetService = this._instantiationService.createInstance(CharsetService); - this._instantiationService.setService(ICharsetService, this._charsetService); - - // Register input handler and handle/forward events - this._inputHandler = new InputHandler(this._bufferService, this._charsetService, this.coreService, this._dirtyRowService, this._logService, this.optionsService, this.coreMouseService, this.unicodeService); - this.register(forwardEvent(this._inputHandler.onLineFeed, this._onLineFeed)); - this.register(this._inputHandler); - - // Setup listeners - this.register(forwardEvent(this._bufferService.onResize, this._onResize)); - this.register(forwardEvent(this.coreService.onData, this._onData)); - this.register(forwardEvent(this.coreService.onBinary, this._onBinary)); - this.register(this.optionsService.onOptionChange(key => this._updateOptions(key))); - this.register(this._bufferService.onScroll(event => { - this._onScroll.fire({ position: this._bufferService.buffer.ydisp, source: ScrollSource.TERMINAL }); - this._dirtyRowService.markRangeDirty(this._bufferService.buffer.scrollTop, this._bufferService.buffer.scrollBottom); - })); - this.register(this._inputHandler.onScroll(event => { - this._onScroll.fire({ position: this._bufferService.buffer.ydisp, source: ScrollSource.TERMINAL }); - this._dirtyRowService.markRangeDirty(this._bufferService.buffer.scrollTop, this._bufferService.buffer.scrollBottom); - })); - - // Setup WriteBuffer - this._writeBuffer = new WriteBuffer((data, promiseResult) => this._inputHandler.parse(data, promiseResult)); - } - - public dispose(): void { - if (this._isDisposed) { - return; - } - super.dispose(); - this._windowsMode?.dispose(); - this._windowsMode = undefined; - } - - public write(data: string | Uint8Array, callback?: () => void): void { - this._writeBuffer.write(data, callback); - } - - /** - * Write data to terminal synchonously. - * - * This method is unreliable with async parser handlers, thus should not - * be used anymore. If you need blocking semantics on data input consider - * `write` with a callback instead. - * - * @deprecated Unreliable, will be removed soon. - */ - public writeSync(data: string | Uint8Array, maxSubsequentCalls?: number): void { - if (this._logService.logLevel <= LogLevelEnum.WARN && !hasWriteSyncWarnHappened) { - this._logService.warn('writeSync is unreliable and will be removed soon.'); - hasWriteSyncWarnHappened = true; - } - this._writeBuffer.writeSync(data, maxSubsequentCalls); - } - - public resize(x: number, y: number): void { - if (isNaN(x) || isNaN(y)) { - return; - } - - x = Math.max(x, MINIMUM_COLS); - y = Math.max(y, MINIMUM_ROWS); - - this._bufferService.resize(x, y); - } - - /** - * Scroll the terminal down 1 row, creating a blank line. - * @param isWrapped Whether the new line is wrapped from the previous line. - */ - public scroll(eraseAttr: IAttributeData, isWrapped: boolean = false): void { - this._bufferService.scroll(eraseAttr, isWrapped); - } - - /** - * Scroll the display of the terminal - * @param disp The number of lines to scroll down (negative scroll up). - * @param suppressScrollEvent Don't emit the scroll event as scrollLines. This is used - * to avoid unwanted events being handled by the viewport when the event was triggered from the - * viewport originally. - */ - public scrollLines(disp: number, suppressScrollEvent?: boolean, source?: ScrollSource): void { - this._bufferService.scrollLines(disp, suppressScrollEvent, source); - } - - /** - * Scroll the display of the terminal by a number of pages. - * @param pageCount The number of pages to scroll (negative scrolls up). - */ - public scrollPages(pageCount: number): void { - this._bufferService.scrollPages(pageCount); - } - - /** - * Scrolls the display of the terminal to the top. - */ - public scrollToTop(): void { - this._bufferService.scrollToTop(); - } - - /** - * Scrolls the display of the terminal to the bottom. - */ - public scrollToBottom(): void { - this._bufferService.scrollToBottom(); - } - - public scrollToLine(line: number): void { - this._bufferService.scrollToLine(line); - } - - /** Add handler for ESC escape sequence. See xterm.d.ts for details. */ - public registerEscHandler(id: IFunctionIdentifier, callback: () => boolean | Promise<boolean>): IDisposable { - return this._inputHandler.registerEscHandler(id, callback); - } - - /** Add handler for DCS escape sequence. See xterm.d.ts for details. */ - public registerDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean | Promise<boolean>): IDisposable { - return this._inputHandler.registerDcsHandler(id, callback); - } - - /** Add handler for CSI escape sequence. See xterm.d.ts for details. */ - public registerCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean | Promise<boolean>): IDisposable { - return this._inputHandler.registerCsiHandler(id, callback); - } - - /** Add handler for OSC escape sequence. See xterm.d.ts for details. */ - public registerOscHandler(ident: number, callback: (data: string) => boolean | Promise<boolean>): IDisposable { - return this._inputHandler.registerOscHandler(ident, callback); - } - - protected _setup(): void { - if (this.optionsService.rawOptions.windowsMode) { - this._enableWindowsMode(); - } - } - - public reset(): void { - this._inputHandler.reset(); - this._bufferService.reset(); - this._charsetService.reset(); - this.coreService.reset(); - this.coreMouseService.reset(); - } - - protected _updateOptions(key: string): void { - // TODO: These listeners should be owned by individual components - switch (key) { - case 'scrollback': - this.buffers.resize(this.cols, this.rows); - break; - case 'windowsMode': - if (this.optionsService.rawOptions.windowsMode) { - this._enableWindowsMode(); - } else { - this._windowsMode?.dispose(); - this._windowsMode = undefined; - } - break; - } - } - - protected _enableWindowsMode(): void { - if (!this._windowsMode) { - const disposables: IDisposable[] = []; - disposables.push(this.onLineFeed(updateWindowsModeWrappedState.bind(null, this._bufferService))); - disposables.push(this.registerCsiHandler({ final: 'H' }, () => { - updateWindowsModeWrappedState(this._bufferService); - return false; - })); - this._windowsMode = { - dispose: () => { - for (const d of disposables) { - d.dispose(); - } - } - }; - } - } -} diff --git a/node_modules/xterm/src/common/EventEmitter.ts b/node_modules/xterm/src/common/EventEmitter.ts deleted file mode 100644 index 4684809..0000000 --- a/node_modules/xterm/src/common/EventEmitter.ts +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IDisposable } from 'common/Types'; - -interface IListener<T, U = void> { - (arg1: T, arg2: U): void; -} - -export interface IEvent<T, U = void> { - (listener: (arg1: T, arg2: U) => any): IDisposable; -} - -export interface IEventEmitter<T, U = void> { - event: IEvent<T, U>; - fire(arg1: T, arg2: U): void; - dispose(): void; -} - -export class EventEmitter<T, U = void> implements IEventEmitter<T, U> { - private _listeners: IListener<T, U>[] = []; - private _event?: IEvent<T, U>; - private _disposed: boolean = false; - - public get event(): IEvent<T, U> { - if (!this._event) { - this._event = (listener: (arg1: T, arg2: U) => any) => { - this._listeners.push(listener); - const disposable = { - dispose: () => { - if (!this._disposed) { - for (let i = 0; i < this._listeners.length; i++) { - if (this._listeners[i] === listener) { - this._listeners.splice(i, 1); - return; - } - } - } - } - }; - return disposable; - }; - } - return this._event; - } - - public fire(arg1: T, arg2: U): void { - const queue: IListener<T, U>[] = []; - for (let i = 0; i < this._listeners.length; i++) { - queue.push(this._listeners[i]); - } - for (let i = 0; i < queue.length; i++) { - queue[i].call(undefined, arg1, arg2); - } - } - - public dispose(): void { - if (this._listeners) { - this._listeners.length = 0; - } - this._disposed = true; - } -} - -export function forwardEvent<T>(from: IEvent<T>, to: IEventEmitter<T>): IDisposable { - return from(e => to.fire(e)); -} diff --git a/node_modules/xterm/src/common/InputHandler.ts b/node_modules/xterm/src/common/InputHandler.ts deleted file mode 100644 index d5b8d94..0000000 --- a/node_modules/xterm/src/common/InputHandler.ts +++ /dev/null @@ -1,3230 +0,0 @@ -/** - * Copyright (c) 2014 The xterm.js authors. All rights reserved. - * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License) - * @license MIT - */ - -import { IInputHandler, IAttributeData, IDisposable, IWindowOptions, IColorEvent, IParseStack, ColorIndex, ColorRequestType } from 'common/Types'; -import { C0, C1 } from 'common/data/EscapeSequences'; -import { CHARSETS, DEFAULT_CHARSET } from 'common/data/Charsets'; -import { EscapeSequenceParser } from 'common/parser/EscapeSequenceParser'; -import { Disposable } from 'common/Lifecycle'; -import { concat } from 'common/TypedArrayUtils'; -import { StringToUtf32, stringFromCodePoint, utf32ToString, Utf8ToUtf32 } from 'common/input/TextDecoder'; -import { DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; -import { EventEmitter, IEvent } from 'common/EventEmitter'; -import { IParsingState, IDcsHandler, IEscapeSequenceParser, IParams, IFunctionIdentifier } from 'common/parser/Types'; -import { NULL_CELL_CODE, NULL_CELL_WIDTH, Attributes, FgFlags, BgFlags, Content, UnderlineStyle } from 'common/buffer/Constants'; -import { CellData } from 'common/buffer/CellData'; -import { AttributeData } from 'common/buffer/AttributeData'; -import { ICoreService, IBufferService, IOptionsService, ILogService, IDirtyRowService, ICoreMouseService, ICharsetService, IUnicodeService, LogLevelEnum } from 'common/services/Services'; -import { OscHandler } from 'common/parser/OscParser'; -import { DcsHandler } from 'common/parser/DcsParser'; -import { IBuffer } from 'common/buffer/Types'; -import { parseColor } from 'common/input/XParseColor'; - -/** - * Map collect to glevel. Used in `selectCharset`. - */ -const GLEVEL: { [key: string]: number } = { '(': 0, ')': 1, '*': 2, '+': 3, '-': 1, '.': 2 }; - -/** - * VT commands done by the parser - FIXME: move this to the parser? - */ -// @vt: #Y ESC CSI "Control Sequence Introducer" "ESC [" "Start of a CSI sequence." -// @vt: #Y ESC OSC "Operating System Command" "ESC ]" "Start of an OSC sequence." -// @vt: #Y ESC DCS "Device Control String" "ESC P" "Start of a DCS sequence." -// @vt: #Y ESC ST "String Terminator" "ESC \" "Terminator used for string type sequences." -// @vt: #Y ESC PM "Privacy Message" "ESC ^" "Start of a privacy message." -// @vt: #Y ESC APC "Application Program Command" "ESC _" "Start of an APC sequence." -// @vt: #Y C1 CSI "Control Sequence Introducer" "\x9B" "Start of a CSI sequence." -// @vt: #Y C1 OSC "Operating System Command" "\x9D" "Start of an OSC sequence." -// @vt: #Y C1 DCS "Device Control String" "\x90" "Start of a DCS sequence." -// @vt: #Y C1 ST "String Terminator" "\x9C" "Terminator used for string type sequences." -// @vt: #Y C1 PM "Privacy Message" "\x9E" "Start of a privacy message." -// @vt: #Y C1 APC "Application Program Command" "\x9F" "Start of an APC sequence." -// @vt: #Y C0 NUL "Null" "\0, \x00" "NUL is ignored." -// @vt: #Y C0 ESC "Escape" "\e, \x1B" "Start of a sequence. Cancels any other sequence." - -/** - * Document common VT features here that are currently unsupported - */ -// @vt: #N DCS SIXEL "SIXEL Graphics" "DCS Ps ; Ps ; Ps ; q Pt ST" "Draw SIXEL image starting at cursor position." -// @vt: #N OSC 1 "Set Icon Name" "OSC 1 ; Pt BEL" "Set icon name." - -/** - * Max length of the UTF32 input buffer. Real memory consumption is 4 times higher. - */ -const MAX_PARSEBUFFER_LENGTH = 131072; - -/** - * Limit length of title and icon name stacks. - */ -const STACK_LIMIT = 10; - -// map params to window option -function paramToWindowOption(n: number, opts: IWindowOptions): boolean { - if (n > 24) { - return opts.setWinLines || false; - } - switch (n) { - case 1: return !!opts.restoreWin; - case 2: return !!opts.minimizeWin; - case 3: return !!opts.setWinPosition; - case 4: return !!opts.setWinSizePixels; - case 5: return !!opts.raiseWin; - case 6: return !!opts.lowerWin; - case 7: return !!opts.refreshWin; - case 8: return !!opts.setWinSizeChars; - case 9: return !!opts.maximizeWin; - case 10: return !!opts.fullscreenWin; - case 11: return !!opts.getWinState; - case 13: return !!opts.getWinPosition; - case 14: return !!opts.getWinSizePixels; - case 15: return !!opts.getScreenSizePixels; - case 16: return !!opts.getCellSizePixels; - case 18: return !!opts.getWinSizeChars; - case 19: return !!opts.getScreenSizeChars; - case 20: return !!opts.getIconTitle; - case 21: return !!opts.getWinTitle; - case 22: return !!opts.pushTitle; - case 23: return !!opts.popTitle; - case 24: return !!opts.setWinLines; - } - return false; -} - -export enum WindowsOptionsReportType { - GET_WIN_SIZE_PIXELS = 0, - GET_CELL_SIZE_PIXELS = 1 -} - -// create a warning log if an async handler takes longer than the limit (in ms) -const SLOW_ASYNC_LIMIT = 5000; - -/** - * DCS subparser implementations - */ - -/** - * DCS $ q Pt ST - * DECRQSS (https://vt100.net/docs/vt510-rm/DECRQSS.html) - * Request Status String (DECRQSS), VT420 and up. - * Response: DECRPSS (https://vt100.net/docs/vt510-rm/DECRPSS.html) - * - * @vt: #P[See limited support below.] DCS DECRQSS "Request Selection or Setting" "DCS $ q Pt ST" "Request several terminal settings." - * Response is in the form `ESC P 1 $ r Pt ST` for valid requests, where `Pt` contains the corresponding CSI string, - * `ESC P 0 ST` for invalid requests. - * - * Supported requests and responses: - * - * | Type | Request | Response (`Pt`) | - * | -------------------------------- | ----------------- | ----------------------------------------------------- | - * | Graphic Rendition (SGR) | `DCS $ q m ST` | always reporting `0m` (currently broken) | - * | Top and Bottom Margins (DECSTBM) | `DCS $ q r ST` | `Ps ; Ps r` | - * | Cursor Style (DECSCUSR) | `DCS $ q SP q ST` | `Ps SP q` | - * | Protection Attribute (DECSCA) | `DCS $ q " q ST` | always reporting `0 " q` (DECSCA is unsupported) | - * | Conformance Level (DECSCL) | `DCS $ q " p ST` | always reporting `61 ; 1 " p` (DECSCL is unsupported) | - * - * - * TODO: - * - fix SGR report - * - either implement DECSCA or remove the report - * - either check which conformance is better suited or remove the report completely - * --> we are currently a mixture of all up to VT400 but dont follow anyone strictly - */ -class DECRQSS implements IDcsHandler { - private _data: Uint32Array = new Uint32Array(0); - - constructor( - private _bufferService: IBufferService, - private _coreService: ICoreService, - private _logService: ILogService, - private _optionsService: IOptionsService - ) { } - - public hook(params: IParams): void { - this._data = new Uint32Array(0); - } - - public put(data: Uint32Array, start: number, end: number): void { - this._data = concat(this._data, data.subarray(start, end)); - } - - public unhook(success: boolean): boolean { - if (!success) { - this._data = new Uint32Array(0); - return true; - } - const data = utf32ToString(this._data); - this._data = new Uint32Array(0); - switch (data) { - // valid: DCS 1 $ r Pt ST (xterm) - case '"q': // DECSCA - this._coreService.triggerDataEvent(`${C0.ESC}P1$r0"q${C0.ESC}\\`); - break; - case '"p': // DECSCL - this._coreService.triggerDataEvent(`${C0.ESC}P1$r61;1"p${C0.ESC}\\`); - break; - case 'r': // DECSTBM - const pt = '' + (this._bufferService.buffer.scrollTop + 1) + - ';' + (this._bufferService.buffer.scrollBottom + 1) + 'r'; - this._coreService.triggerDataEvent(`${C0.ESC}P1$r${pt}${C0.ESC}\\`); - break; - case 'm': // SGR - // TODO: report real settings instead of 0m - this._coreService.triggerDataEvent(`${C0.ESC}P1$r0m${C0.ESC}\\`); - break; - case ' q': // DECSCUSR - const STYLES: { [key: string]: number } = { 'block': 2, 'underline': 4, 'bar': 6 }; - let style = STYLES[this._optionsService.rawOptions.cursorStyle]; - style -= this._optionsService.rawOptions.cursorBlink ? 1 : 0; - this._coreService.triggerDataEvent(`${C0.ESC}P1$r${style} q${C0.ESC}\\`); - break; - default: - // invalid: DCS 0 $ r Pt ST (xterm) - this._logService.debug('Unknown DCS $q %s', data); - this._coreService.triggerDataEvent(`${C0.ESC}P0$r${C0.ESC}\\`); - } - return true; - } -} - -/** - * DCS Ps; Ps| Pt ST - * DECUDK (https://vt100.net/docs/vt510-rm/DECUDK.html) - * not supported - * - * @vt: #N DCS DECUDK "User Defined Keys" "DCS Ps ; Ps | Pt ST" "Definitions for user-defined keys." - */ - -/** - * DCS + q Pt ST (xterm) - * Request Terminfo String - * not implemented - * - * @vt: #N DCS XTGETTCAP "Request Terminfo String" "DCS + q Pt ST" "Request Terminfo String." - */ - -/** - * DCS + p Pt ST (xterm) - * Set Terminfo Data - * not supported - * - * @vt: #N DCS XTSETTCAP "Set Terminfo Data" "DCS + p Pt ST" "Set Terminfo Data." - */ - - - -/** - * The terminal's standard implementation of IInputHandler, this handles all - * input from the Parser. - * - * Refer to http://invisible-island.net/xterm/ctlseqs/ctlseqs.html to understand - * each function's header comment. - */ -export class InputHandler extends Disposable implements IInputHandler { - private _parseBuffer: Uint32Array = new Uint32Array(4096); - private _stringDecoder: StringToUtf32 = new StringToUtf32(); - private _utf8Decoder: Utf8ToUtf32 = new Utf8ToUtf32(); - private _workCell: CellData = new CellData(); - private _windowTitle = ''; - private _iconName = ''; - protected _windowTitleStack: string[] = []; - protected _iconNameStack: string[] = []; - - private _curAttrData: IAttributeData = DEFAULT_ATTR_DATA.clone(); - private _eraseAttrDataInternal: IAttributeData = DEFAULT_ATTR_DATA.clone(); - - private _activeBuffer: IBuffer; - - private _onRequestBell = new EventEmitter<void>(); - public get onRequestBell(): IEvent<void> { return this._onRequestBell.event; } - private _onRequestRefreshRows = new EventEmitter<number, number>(); - public get onRequestRefreshRows(): IEvent<number, number> { return this._onRequestRefreshRows.event; } - private _onRequestReset = new EventEmitter<void>(); - public get onRequestReset(): IEvent<void> { return this._onRequestReset.event; } - private _onRequestSendFocus = new EventEmitter<void>(); - public get onRequestSendFocus(): IEvent<void> { return this._onRequestSendFocus.event; } - private _onRequestSyncScrollBar = new EventEmitter<void>(); - public get onRequestSyncScrollBar(): IEvent<void> { return this._onRequestSyncScrollBar.event; } - private _onRequestWindowsOptionsReport = new EventEmitter<WindowsOptionsReportType>(); - public get onRequestWindowsOptionsReport(): IEvent<WindowsOptionsReportType> { return this._onRequestWindowsOptionsReport.event; } - - private _onA11yChar = new EventEmitter<string>(); - public get onA11yChar(): IEvent<string> { return this._onA11yChar.event; } - private _onA11yTab = new EventEmitter<number>(); - public get onA11yTab(): IEvent<number> { return this._onA11yTab.event; } - private _onCursorMove = new EventEmitter<void>(); - public get onCursorMove(): IEvent<void> { return this._onCursorMove.event; } - private _onLineFeed = new EventEmitter<void>(); - public get onLineFeed(): IEvent<void> { return this._onLineFeed.event; } - private _onScroll = new EventEmitter<number>(); - public get onScroll(): IEvent<number> { return this._onScroll.event; } - private _onTitleChange = new EventEmitter<string>(); - public get onTitleChange(): IEvent<string> { return this._onTitleChange.event; } - private _onColor = new EventEmitter<IColorEvent>(); - public get onColor(): IEvent<IColorEvent> { return this._onColor.event; } - - private _parseStack: IParseStack = { - paused: false, - cursorStartX: 0, - cursorStartY: 0, - decodedLength: 0, - position: 0 - }; - - constructor( - private readonly _bufferService: IBufferService, - private readonly _charsetService: ICharsetService, - private readonly _coreService: ICoreService, - private readonly _dirtyRowService: IDirtyRowService, - private readonly _logService: ILogService, - private readonly _optionsService: IOptionsService, - private readonly _coreMouseService: ICoreMouseService, - private readonly _unicodeService: IUnicodeService, - private readonly _parser: IEscapeSequenceParser = new EscapeSequenceParser() - ) { - super(); - this.register(this._parser); - - // Track properties used in performance critical code manually to avoid using slow getters - this._activeBuffer = this._bufferService.buffer; - this.register(this._bufferService.buffers.onBufferActivate(e => this._activeBuffer = e.activeBuffer)); - - /** - * custom fallback handlers - */ - this._parser.setCsiHandlerFallback((ident, params) => { - this._logService.debug('Unknown CSI code: ', { identifier: this._parser.identToString(ident), params: params.toArray() }); - }); - this._parser.setEscHandlerFallback(ident => { - this._logService.debug('Unknown ESC code: ', { identifier: this._parser.identToString(ident) }); - }); - this._parser.setExecuteHandlerFallback(code => { - this._logService.debug('Unknown EXECUTE code: ', { code }); - }); - this._parser.setOscHandlerFallback((identifier, action, data) => { - this._logService.debug('Unknown OSC code: ', { identifier, action, data }); - }); - this._parser.setDcsHandlerFallback((ident, action, payload) => { - if (action === 'HOOK') { - payload = payload.toArray(); - } - this._logService.debug('Unknown DCS code: ', { identifier: this._parser.identToString(ident), action, payload }); - }); - - /** - * print handler - */ - this._parser.setPrintHandler((data, start, end) => this.print(data, start, end)); - - /** - * CSI handler - */ - this._parser.registerCsiHandler({ final: '@' }, params => this.insertChars(params)); - this._parser.registerCsiHandler({ intermediates: ' ', final: '@' }, params => this.scrollLeft(params)); - this._parser.registerCsiHandler({ final: 'A' }, params => this.cursorUp(params)); - this._parser.registerCsiHandler({ intermediates: ' ', final: 'A' }, params => this.scrollRight(params)); - this._parser.registerCsiHandler({ final: 'B' }, params => this.cursorDown(params)); - this._parser.registerCsiHandler({ final: 'C' }, params => this.cursorForward(params)); - this._parser.registerCsiHandler({ final: 'D' }, params => this.cursorBackward(params)); - this._parser.registerCsiHandler({ final: 'E' }, params => this.cursorNextLine(params)); - this._parser.registerCsiHandler({ final: 'F' }, params => this.cursorPrecedingLine(params)); - this._parser.registerCsiHandler({ final: 'G' }, params => this.cursorCharAbsolute(params)); - this._parser.registerCsiHandler({ final: 'H' }, params => this.cursorPosition(params)); - this._parser.registerCsiHandler({ final: 'I' }, params => this.cursorForwardTab(params)); - this._parser.registerCsiHandler({ final: 'J' }, params => this.eraseInDisplay(params)); - this._parser.registerCsiHandler({ prefix: '?', final: 'J' }, params => this.eraseInDisplay(params)); - this._parser.registerCsiHandler({ final: 'K' }, params => this.eraseInLine(params)); - this._parser.registerCsiHandler({ prefix: '?', final: 'K' }, params => this.eraseInLine(params)); - this._parser.registerCsiHandler({ final: 'L' }, params => this.insertLines(params)); - this._parser.registerCsiHandler({ final: 'M' }, params => this.deleteLines(params)); - this._parser.registerCsiHandler({ final: 'P' }, params => this.deleteChars(params)); - this._parser.registerCsiHandler({ final: 'S' }, params => this.scrollUp(params)); - this._parser.registerCsiHandler({ final: 'T' }, params => this.scrollDown(params)); - this._parser.registerCsiHandler({ final: 'X' }, params => this.eraseChars(params)); - this._parser.registerCsiHandler({ final: 'Z' }, params => this.cursorBackwardTab(params)); - this._parser.registerCsiHandler({ final: '`' }, params => this.charPosAbsolute(params)); - this._parser.registerCsiHandler({ final: 'a' }, params => this.hPositionRelative(params)); - this._parser.registerCsiHandler({ final: 'b' }, params => this.repeatPrecedingCharacter(params)); - this._parser.registerCsiHandler({ final: 'c' }, params => this.sendDeviceAttributesPrimary(params)); - this._parser.registerCsiHandler({ prefix: '>', final: 'c' }, params => this.sendDeviceAttributesSecondary(params)); - this._parser.registerCsiHandler({ final: 'd' }, params => this.linePosAbsolute(params)); - this._parser.registerCsiHandler({ final: 'e' }, params => this.vPositionRelative(params)); - this._parser.registerCsiHandler({ final: 'f' }, params => this.hVPosition(params)); - this._parser.registerCsiHandler({ final: 'g' }, params => this.tabClear(params)); - this._parser.registerCsiHandler({ final: 'h' }, params => this.setMode(params)); - this._parser.registerCsiHandler({ prefix: '?', final: 'h' }, params => this.setModePrivate(params)); - this._parser.registerCsiHandler({ final: 'l' }, params => this.resetMode(params)); - this._parser.registerCsiHandler({ prefix: '?', final: 'l' }, params => this.resetModePrivate(params)); - this._parser.registerCsiHandler({ final: 'm' }, params => this.charAttributes(params)); - this._parser.registerCsiHandler({ final: 'n' }, params => this.deviceStatus(params)); - this._parser.registerCsiHandler({ prefix: '?', final: 'n' }, params => this.deviceStatusPrivate(params)); - this._parser.registerCsiHandler({ intermediates: '!', final: 'p' }, params => this.softReset(params)); - this._parser.registerCsiHandler({ intermediates: ' ', final: 'q' }, params => this.setCursorStyle(params)); - this._parser.registerCsiHandler({ final: 'r' }, params => this.setScrollRegion(params)); - this._parser.registerCsiHandler({ final: 's' }, params => this.saveCursor(params)); - this._parser.registerCsiHandler({ final: 't' }, params => this.windowOptions(params)); - this._parser.registerCsiHandler({ final: 'u' }, params => this.restoreCursor(params)); - this._parser.registerCsiHandler({ intermediates: '\'', final: '}' }, params => this.insertColumns(params)); - this._parser.registerCsiHandler({ intermediates: '\'', final: '~' }, params => this.deleteColumns(params)); - - /** - * execute handler - */ - this._parser.setExecuteHandler(C0.BEL, () => this.bell()); - this._parser.setExecuteHandler(C0.LF, () => this.lineFeed()); - this._parser.setExecuteHandler(C0.VT, () => this.lineFeed()); - this._parser.setExecuteHandler(C0.FF, () => this.lineFeed()); - this._parser.setExecuteHandler(C0.CR, () => this.carriageReturn()); - this._parser.setExecuteHandler(C0.BS, () => this.backspace()); - this._parser.setExecuteHandler(C0.HT, () => this.tab()); - this._parser.setExecuteHandler(C0.SO, () => this.shiftOut()); - this._parser.setExecuteHandler(C0.SI, () => this.shiftIn()); - // FIXME: What do to with missing? Old code just added those to print. - - this._parser.setExecuteHandler(C1.IND, () => this.index()); - this._parser.setExecuteHandler(C1.NEL, () => this.nextLine()); - this._parser.setExecuteHandler(C1.HTS, () => this.tabSet()); - - /** - * OSC handler - */ - // 0 - icon name + title - this._parser.registerOscHandler(0, new OscHandler(data => { this.setTitle(data); this.setIconName(data); return true; })); - // 1 - icon name - this._parser.registerOscHandler(1, new OscHandler(data => this.setIconName(data))); - // 2 - title - this._parser.registerOscHandler(2, new OscHandler(data => this.setTitle(data))); - // 3 - set property X in the form "prop=value" - // 4 - Change Color Number - this._parser.registerOscHandler(4, new OscHandler(data => this.setOrReportIndexedColor(data))); - // 5 - Change Special Color Number - // 6 - Enable/disable Special Color Number c - // 7 - current directory? (not in xterm spec, see https://gitlab.com/gnachman/iterm2/issues/3939) - // 10 - Change VT100 text foreground color to Pt. - this._parser.registerOscHandler(10, new OscHandler(data => this.setOrReportFgColor(data))); - // 11 - Change VT100 text background color to Pt. - this._parser.registerOscHandler(11, new OscHandler(data => this.setOrReportBgColor(data))); - // 12 - Change text cursor color to Pt. - this._parser.registerOscHandler(12, new OscHandler(data => this.setOrReportCursorColor(data))); - // 13 - Change mouse foreground color to Pt. - // 14 - Change mouse background color to Pt. - // 15 - Change Tektronix foreground color to Pt. - // 16 - Change Tektronix background color to Pt. - // 17 - Change highlight background color to Pt. - // 18 - Change Tektronix cursor color to Pt. - // 19 - Change highlight foreground color to Pt. - // 46 - Change Log File to Pt. - // 50 - Set Font to Pt. - // 51 - reserved for Emacs shell. - // 52 - Manipulate Selection Data. - // 104 ; c - Reset Color Number c. - this._parser.registerOscHandler(104, new OscHandler(data => this.restoreIndexedColor(data))); - // 105 ; c - Reset Special Color Number c. - // 106 ; c; f - Enable/disable Special Color Number c. - // 110 - Reset VT100 text foreground color. - this._parser.registerOscHandler(110, new OscHandler(data => this.restoreFgColor(data))); - // 111 - Reset VT100 text background color. - this._parser.registerOscHandler(111, new OscHandler(data => this.restoreBgColor(data))); - // 112 - Reset text cursor color. - this._parser.registerOscHandler(112, new OscHandler(data => this.restoreCursorColor(data))); - // 113 - Reset mouse foreground color. - // 114 - Reset mouse background color. - // 115 - Reset Tektronix foreground color. - // 116 - Reset Tektronix background color. - // 117 - Reset highlight color. - // 118 - Reset Tektronix cursor color. - // 119 - Reset highlight foreground color. - - /** - * ESC handlers - */ - this._parser.registerEscHandler({ final: '7' }, () => this.saveCursor()); - this._parser.registerEscHandler({ final: '8' }, () => this.restoreCursor()); - this._parser.registerEscHandler({ final: 'D' }, () => this.index()); - this._parser.registerEscHandler({ final: 'E' }, () => this.nextLine()); - this._parser.registerEscHandler({ final: 'H' }, () => this.tabSet()); - this._parser.registerEscHandler({ final: 'M' }, () => this.reverseIndex()); - this._parser.registerEscHandler({ final: '=' }, () => this.keypadApplicationMode()); - this._parser.registerEscHandler({ final: '>' }, () => this.keypadNumericMode()); - this._parser.registerEscHandler({ final: 'c' }, () => this.fullReset()); - this._parser.registerEscHandler({ final: 'n' }, () => this.setgLevel(2)); - this._parser.registerEscHandler({ final: 'o' }, () => this.setgLevel(3)); - this._parser.registerEscHandler({ final: '|' }, () => this.setgLevel(3)); - this._parser.registerEscHandler({ final: '}' }, () => this.setgLevel(2)); - this._parser.registerEscHandler({ final: '~' }, () => this.setgLevel(1)); - this._parser.registerEscHandler({ intermediates: '%', final: '@' }, () => this.selectDefaultCharset()); - this._parser.registerEscHandler({ intermediates: '%', final: 'G' }, () => this.selectDefaultCharset()); - for (const flag in CHARSETS) { - this._parser.registerEscHandler({ intermediates: '(', final: flag }, () => this.selectCharset('(' + flag)); - this._parser.registerEscHandler({ intermediates: ')', final: flag }, () => this.selectCharset(')' + flag)); - this._parser.registerEscHandler({ intermediates: '*', final: flag }, () => this.selectCharset('*' + flag)); - this._parser.registerEscHandler({ intermediates: '+', final: flag }, () => this.selectCharset('+' + flag)); - this._parser.registerEscHandler({ intermediates: '-', final: flag }, () => this.selectCharset('-' + flag)); - this._parser.registerEscHandler({ intermediates: '.', final: flag }, () => this.selectCharset('.' + flag)); - this._parser.registerEscHandler({ intermediates: '/', final: flag }, () => this.selectCharset('/' + flag)); // TODO: supported? - } - this._parser.registerEscHandler({ intermediates: '#', final: '8' }, () => this.screenAlignmentPattern()); - - /** - * error handler - */ - this._parser.setErrorHandler((state: IParsingState) => { - this._logService.error('Parsing error: ', state); - return state; - }); - - /** - * DCS handler - */ - this._parser.registerDcsHandler({ intermediates: '$', final: 'q' }, new DECRQSS(this._bufferService, this._coreService, this._logService, this._optionsService)); - } - - public dispose(): void { - super.dispose(); - } - - /** - * Async parse support. - */ - private _preserveStack(cursorStartX: number, cursorStartY: number, decodedLength: number, position: number): void { - this._parseStack.paused = true; - this._parseStack.cursorStartX = cursorStartX; - this._parseStack.cursorStartY = cursorStartY; - this._parseStack.decodedLength = decodedLength; - this._parseStack.position = position; - } - - private _logSlowResolvingAsync(p: Promise<boolean>): void { - // log a limited warning about an async handler taking too long - if (this._logService.logLevel <= LogLevelEnum.WARN) { - Promise.race([p, new Promise((res, rej) => setTimeout(() => rej('#SLOW_TIMEOUT'), SLOW_ASYNC_LIMIT))]) - .catch(err => { - if (err !== '#SLOW_TIMEOUT') { - throw err; - } - console.warn(`async parser handler taking longer than ${SLOW_ASYNC_LIMIT} ms`); - }); - } - } - - /** - * Parse call with async handler support. - * - * Whether the stack state got preserved for the next call, is indicated by the return value: - * - undefined (void): - * all handlers were sync, no stack save, continue normally with next chunk - * - Promise\<boolean\>: - * execution stopped at async handler, stack saved, continue with - * same chunk and the promise resolve value as `promiseResult` until the method returns `undefined` - * - * Note: This method should only be called by `Terminal.write` to ensure correct execution order and - * proper continuation of async parser handlers. - */ - public parse(data: string | Uint8Array, promiseResult?: boolean): void | Promise<boolean> { - let result: void | Promise<boolean>; - let cursorStartX = this._activeBuffer.x; - let cursorStartY = this._activeBuffer.y; - let start = 0; - const wasPaused = this._parseStack.paused; - - if (wasPaused) { - // assumption: _parseBuffer never mutates between async calls - if (result = this._parser.parse(this._parseBuffer, this._parseStack.decodedLength, promiseResult)) { - this._logSlowResolvingAsync(result); - return result; - } - cursorStartX = this._parseStack.cursorStartX; - cursorStartY = this._parseStack.cursorStartY; - this._parseStack.paused = false; - if (data.length > MAX_PARSEBUFFER_LENGTH) { - start = this._parseStack.position + MAX_PARSEBUFFER_LENGTH; - } - } - - // Log debug data, the log level gate is to prevent extra work in this hot path - if (this._logService.logLevel <= LogLevelEnum.DEBUG) { - this._logService.debug(`parsing data${typeof data === 'string' ? ` "${data}"` : ` "${Array.prototype.map.call(data, e => String.fromCharCode(e)).join('')}"`}`, typeof data === 'string' - ? data.split('').map(e => e.charCodeAt(0)) - : data - ); - } - - // resize input buffer if needed - if (this._parseBuffer.length < data.length) { - if (this._parseBuffer.length < MAX_PARSEBUFFER_LENGTH) { - this._parseBuffer = new Uint32Array(Math.min(data.length, MAX_PARSEBUFFER_LENGTH)); - } - } - - // Clear the dirty row service so we know which lines changed as a result of parsing - // Important: do not clear between async calls, otherwise we lost pending update information. - if (!wasPaused) { - this._dirtyRowService.clearRange(); - } - - // process big data in smaller chunks - if (data.length > MAX_PARSEBUFFER_LENGTH) { - for (let i = start; i < data.length; i += MAX_PARSEBUFFER_LENGTH) { - const end = i + MAX_PARSEBUFFER_LENGTH < data.length ? i + MAX_PARSEBUFFER_LENGTH : data.length; - const len = (typeof data === 'string') - ? this._stringDecoder.decode(data.substring(i, end), this._parseBuffer) - : this._utf8Decoder.decode(data.subarray(i, end), this._parseBuffer); - if (result = this._parser.parse(this._parseBuffer, len)) { - this._preserveStack(cursorStartX, cursorStartY, len, i); - this._logSlowResolvingAsync(result); - return result; - } - } - } else { - if (!wasPaused) { - const len = (typeof data === 'string') - ? this._stringDecoder.decode(data, this._parseBuffer) - : this._utf8Decoder.decode(data, this._parseBuffer); - if (result = this._parser.parse(this._parseBuffer, len)) { - this._preserveStack(cursorStartX, cursorStartY, len, 0); - this._logSlowResolvingAsync(result); - return result; - } - } - } - - if (this._activeBuffer.x !== cursorStartX || this._activeBuffer.y !== cursorStartY) { - this._onCursorMove.fire(); - } - - // Refresh any dirty rows accumulated as part of parsing - this._onRequestRefreshRows.fire(this._dirtyRowService.start, this._dirtyRowService.end); - } - - public print(data: Uint32Array, start: number, end: number): void { - let code: number; - let chWidth: number; - const charset = this._charsetService.charset; - const screenReaderMode = this._optionsService.rawOptions.screenReaderMode; - const cols = this._bufferService.cols; - const wraparoundMode = this._coreService.decPrivateModes.wraparound; - const insertMode = this._coreService.modes.insertMode; - const curAttr = this._curAttrData; - let bufferRow = this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y)!; - - this._dirtyRowService.markDirty(this._activeBuffer.y); - - // handle wide chars: reset start_cell-1 if we would overwrite the second cell of a wide char - if (this._activeBuffer.x && end - start > 0 && bufferRow.getWidth(this._activeBuffer.x - 1) === 2) { - bufferRow.setCellFromCodePoint(this._activeBuffer.x - 1, 0, 1, curAttr.fg, curAttr.bg, curAttr.extended); - } - - for (let pos = start; pos < end; ++pos) { - code = data[pos]; - - // calculate print space - // expensive call, therefore we save width in line buffer - chWidth = this._unicodeService.wcwidth(code); - - // get charset replacement character - // charset is only defined for ASCII, therefore we only - // search for an replacement char if code < 127 - if (code < 127 && charset) { - const ch = charset[String.fromCharCode(code)]; - if (ch) { - code = ch.charCodeAt(0); - } - } - - if (screenReaderMode) { - this._onA11yChar.fire(stringFromCodePoint(code)); - } - - // insert combining char at last cursor position - // this._activeBuffer.x should never be 0 for a combining char - // since they always follow a cell consuming char - // therefore we can test for this._activeBuffer.x to avoid overflow left - if (!chWidth && this._activeBuffer.x) { - if (!bufferRow.getWidth(this._activeBuffer.x - 1)) { - // found empty cell after fullwidth, need to go 2 cells back - // it is save to step 2 cells back here - // since an empty cell is only set by fullwidth chars - bufferRow.addCodepointToCell(this._activeBuffer.x - 2, code); - } else { - bufferRow.addCodepointToCell(this._activeBuffer.x - 1, code); - } - continue; - } - - // goto next line if ch would overflow - // NOTE: To avoid costly width checks here, - // the terminal does not allow a cols < 2. - if (this._activeBuffer.x + chWidth - 1 >= cols) { - // autowrap - DECAWM - // automatically wraps to the beginning of the next line - if (wraparoundMode) { - // clear left over cells to the right - while (this._activeBuffer.x < cols) { - bufferRow.setCellFromCodePoint(this._activeBuffer.x++, 0, 1, curAttr.fg, curAttr.bg, curAttr.extended); - } - this._activeBuffer.x = 0; - this._activeBuffer.y++; - if (this._activeBuffer.y === this._activeBuffer.scrollBottom + 1) { - this._activeBuffer.y--; - this._bufferService.scroll(this._eraseAttrData(), true); - } else { - if (this._activeBuffer.y >= this._bufferService.rows) { - this._activeBuffer.y = this._bufferService.rows - 1; - } - // The line already exists (eg. the initial viewport), mark it as a - // wrapped line - this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y)!.isWrapped = true; - } - // row changed, get it again - bufferRow = this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y)!; - } else { - this._activeBuffer.x = cols - 1; - if (chWidth === 2) { - // FIXME: check for xterm behavior - // What to do here? We got a wide char that does not fit into last cell - continue; - } - } - } - - // insert mode: move characters to right - if (insertMode) { - // right shift cells according to the width - bufferRow.insertCells(this._activeBuffer.x, chWidth, this._activeBuffer.getNullCell(curAttr), curAttr); - // test last cell - since the last cell has only room for - // a halfwidth char any fullwidth shifted there is lost - // and will be set to empty cell - if (bufferRow.getWidth(cols - 1) === 2) { - bufferRow.setCellFromCodePoint(cols - 1, NULL_CELL_CODE, NULL_CELL_WIDTH, curAttr.fg, curAttr.bg, curAttr.extended); - } - } - - // write current char to buffer and advance cursor - bufferRow.setCellFromCodePoint(this._activeBuffer.x++, code, chWidth, curAttr.fg, curAttr.bg, curAttr.extended); - - // fullwidth char - also set next cell to placeholder stub and advance cursor - // for graphemes bigger than fullwidth we can simply loop to zero - // we already made sure above, that this._activeBuffer.x + chWidth will not overflow right - if (chWidth > 0) { - while (--chWidth) { - // other than a regular empty cell a cell following a wide char has no width - bufferRow.setCellFromCodePoint(this._activeBuffer.x++, 0, 0, curAttr.fg, curAttr.bg, curAttr.extended); - } - } - } - // store last char in Parser.precedingCodepoint for REP to work correctly - // This needs to check whether: - // - fullwidth + surrogates: reset - // - combining: only base char gets carried on (bug in xterm?) - if (end - start > 0) { - bufferRow.loadCell(this._activeBuffer.x - 1, this._workCell); - if (this._workCell.getWidth() === 2 || this._workCell.getCode() > 0xFFFF) { - this._parser.precedingCodepoint = 0; - } else if (this._workCell.isCombined()) { - this._parser.precedingCodepoint = this._workCell.getChars().charCodeAt(0); - } else { - this._parser.precedingCodepoint = this._workCell.content; - } - } - - // handle wide chars: reset cell to the right if it is second cell of a wide char - if (this._activeBuffer.x < cols && end - start > 0 && bufferRow.getWidth(this._activeBuffer.x) === 0 && !bufferRow.hasContent(this._activeBuffer.x)) { - bufferRow.setCellFromCodePoint(this._activeBuffer.x, 0, 1, curAttr.fg, curAttr.bg, curAttr.extended); - } - - this._dirtyRowService.markDirty(this._activeBuffer.y); - } - - /** - * Forward registerCsiHandler from parser. - */ - public registerCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean | Promise<boolean>): IDisposable { - if (id.final === 't' && !id.prefix && !id.intermediates) { - // security: always check whether window option is allowed - return this._parser.registerCsiHandler(id, params => { - if (!paramToWindowOption(params.params[0], this._optionsService.rawOptions.windowOptions)) { - return true; - } - return callback(params); - }); - } - return this._parser.registerCsiHandler(id, callback); - } - - /** - * Forward registerDcsHandler from parser. - */ - public registerDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean | Promise<boolean>): IDisposable { - return this._parser.registerDcsHandler(id, new DcsHandler(callback)); - } - - /** - * Forward registerEscHandler from parser. - */ - public registerEscHandler(id: IFunctionIdentifier, callback: () => boolean | Promise<boolean>): IDisposable { - return this._parser.registerEscHandler(id, callback); - } - - /** - * Forward registerOscHandler from parser. - */ - public registerOscHandler(ident: number, callback: (data: string) => boolean | Promise<boolean>): IDisposable { - return this._parser.registerOscHandler(ident, new OscHandler(callback)); - } - - /** - * BEL - * Bell (Ctrl-G). - * - * @vt: #Y C0 BEL "Bell" "\a, \x07" "Ring the bell." - * The behavior of the bell is further customizable with `ITerminalOptions.bellStyle` - * and `ITerminalOptions.bellSound`. - */ - public bell(): boolean { - this._onRequestBell.fire(); - return true; - } - - /** - * LF - * Line Feed or New Line (NL). (LF is Ctrl-J). - * - * @vt: #Y C0 LF "Line Feed" "\n, \x0A" "Move the cursor one row down, scrolling if needed." - * Scrolling is restricted to scroll margins and will only happen on the bottom line. - * - * @vt: #Y C0 VT "Vertical Tabulation" "\v, \x0B" "Treated as LF." - * @vt: #Y C0 FF "Form Feed" "\f, \x0C" "Treated as LF." - */ - public lineFeed(): boolean { - this._dirtyRowService.markDirty(this._activeBuffer.y); - if (this._optionsService.rawOptions.convertEol) { - this._activeBuffer.x = 0; - } - this._activeBuffer.y++; - if (this._activeBuffer.y === this._activeBuffer.scrollBottom + 1) { - this._activeBuffer.y--; - this._bufferService.scroll(this._eraseAttrData()); - } else if (this._activeBuffer.y >= this._bufferService.rows) { - this._activeBuffer.y = this._bufferService.rows - 1; - } - // If the end of the line is hit, prevent this action from wrapping around to the next line. - if (this._activeBuffer.x >= this._bufferService.cols) { - this._activeBuffer.x--; - } - this._dirtyRowService.markDirty(this._activeBuffer.y); - - this._onLineFeed.fire(); - return true; - } - - /** - * CR - * Carriage Return (Ctrl-M). - * - * @vt: #Y C0 CR "Carriage Return" "\r, \x0D" "Move the cursor to the beginning of the row." - */ - public carriageReturn(): boolean { - this._activeBuffer.x = 0; - return true; - } - - /** - * BS - * Backspace (Ctrl-H). - * - * @vt: #Y C0 BS "Backspace" "\b, \x08" "Move the cursor one position to the left." - * By default it is not possible to move the cursor past the leftmost position. - * If `reverse wrap-around` (`CSI ? 45 h`) is set, a previous soft line wrap (DECAWM) - * can be undone with BS within the scroll margins. In that case the cursor will wrap back - * to the end of the previous row. Note that it is not possible to peek back into the scrollbuffer - * with the cursor, thus at the home position (top-leftmost cell) this has no effect. - */ - public backspace(): boolean { - // reverse wrap-around is disabled - if (!this._coreService.decPrivateModes.reverseWraparound) { - this._restrictCursor(); - if (this._activeBuffer.x > 0) { - this._activeBuffer.x--; - } - return true; - } - - // reverse wrap-around is enabled - // other than for normal operation mode, reverse wrap-around allows the cursor - // to be at x=cols to be able to address the last cell of a row by BS - this._restrictCursor(this._bufferService.cols); - - if (this._activeBuffer.x > 0) { - this._activeBuffer.x--; - } else { - /** - * reverse wrap-around handling: - * Our implementation deviates from xterm on purpose. Details: - * - only previous soft NLs can be reversed (isWrapped=true) - * - only works within scrollborders (top/bottom, left/right not yet supported) - * - cannot peek into scrollbuffer - * - any cursor movement sequence keeps working as expected - */ - if (this._activeBuffer.x === 0 - && this._activeBuffer.y > this._activeBuffer.scrollTop - && this._activeBuffer.y <= this._activeBuffer.scrollBottom - && this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y)?.isWrapped) { - this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y)!.isWrapped = false; - this._activeBuffer.y--; - this._activeBuffer.x = this._bufferService.cols - 1; - // find last taken cell - last cell can have 3 different states: - // - hasContent(true) + hasWidth(1): narrow char - we are done - // - hasWidth(0): second part of wide char - we are done - // - hasContent(false) + hasWidth(1): empty cell due to early wrapping wide char, go one cell further back - const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y)!; - if (line.hasWidth(this._activeBuffer.x) && !line.hasContent(this._activeBuffer.x)) { - this._activeBuffer.x--; - // We do this only once, since width=1 + hasContent=false currently happens only once before - // early wrapping of a wide char. - // This needs to be fixed once we support graphemes taking more than 2 cells. - } - } - } - this._restrictCursor(); - return true; - } - - /** - * TAB - * Horizontal Tab (HT) (Ctrl-I). - * - * @vt: #Y C0 HT "Horizontal Tabulation" "\t, \x09" "Move the cursor to the next character tab stop." - */ - public tab(): boolean { - if (this._activeBuffer.x >= this._bufferService.cols) { - return true; - } - const originalX = this._activeBuffer.x; - this._activeBuffer.x = this._activeBuffer.nextStop(); - if (this._optionsService.rawOptions.screenReaderMode) { - this._onA11yTab.fire(this._activeBuffer.x - originalX); - } - return true; - } - - /** - * SO - * Shift Out (Ctrl-N) -> Switch to Alternate Character Set. This invokes the - * G1 character set. - * - * @vt: #P[Only limited ISO-2022 charset support.] C0 SO "Shift Out" "\x0E" "Switch to an alternative character set." - */ - public shiftOut(): boolean { - this._charsetService.setgLevel(1); - return true; - } - - /** - * SI - * Shift In (Ctrl-O) -> Switch to Standard Character Set. This invokes the G0 - * character set (the default). - * - * @vt: #Y C0 SI "Shift In" "\x0F" "Return to regular character set after Shift Out." - */ - public shiftIn(): boolean { - this._charsetService.setgLevel(0); - return true; - } - - /** - * Restrict cursor to viewport size / scroll margin (origin mode). - */ - private _restrictCursor(maxCol: number = this._bufferService.cols - 1): void { - this._activeBuffer.x = Math.min(maxCol, Math.max(0, this._activeBuffer.x)); - this._activeBuffer.y = this._coreService.decPrivateModes.origin - ? Math.min(this._activeBuffer.scrollBottom, Math.max(this._activeBuffer.scrollTop, this._activeBuffer.y)) - : Math.min(this._bufferService.rows - 1, Math.max(0, this._activeBuffer.y)); - this._dirtyRowService.markDirty(this._activeBuffer.y); - } - - /** - * Set absolute cursor position. - */ - private _setCursor(x: number, y: number): void { - this._dirtyRowService.markDirty(this._activeBuffer.y); - if (this._coreService.decPrivateModes.origin) { - this._activeBuffer.x = x; - this._activeBuffer.y = this._activeBuffer.scrollTop + y; - } else { - this._activeBuffer.x = x; - this._activeBuffer.y = y; - } - this._restrictCursor(); - this._dirtyRowService.markDirty(this._activeBuffer.y); - } - - /** - * Set relative cursor position. - */ - private _moveCursor(x: number, y: number): void { - // for relative changes we have to make sure we are within 0 .. cols/rows - 1 - // before calculating the new position - this._restrictCursor(); - this._setCursor(this._activeBuffer.x + x, this._activeBuffer.y + y); - } - - /** - * CSI Ps A - * Cursor Up Ps Times (default = 1) (CUU). - * - * @vt: #Y CSI CUU "Cursor Up" "CSI Ps A" "Move cursor `Ps` times up (default=1)." - * If the cursor would pass the top scroll margin, it will stop there. - */ - public cursorUp(params: IParams): boolean { - // stop at scrollTop - const diffToTop = this._activeBuffer.y - this._activeBuffer.scrollTop; - if (diffToTop >= 0) { - this._moveCursor(0, -Math.min(diffToTop, params.params[0] || 1)); - } else { - this._moveCursor(0, -(params.params[0] || 1)); - } - return true; - } - - /** - * CSI Ps B - * Cursor Down Ps Times (default = 1) (CUD). - * - * @vt: #Y CSI CUD "Cursor Down" "CSI Ps B" "Move cursor `Ps` times down (default=1)." - * If the cursor would pass the bottom scroll margin, it will stop there. - */ - public cursorDown(params: IParams): boolean { - // stop at scrollBottom - const diffToBottom = this._activeBuffer.scrollBottom - this._activeBuffer.y; - if (diffToBottom >= 0) { - this._moveCursor(0, Math.min(diffToBottom, params.params[0] || 1)); - } else { - this._moveCursor(0, params.params[0] || 1); - } - return true; - } - - /** - * CSI Ps C - * Cursor Forward Ps Times (default = 1) (CUF). - * - * @vt: #Y CSI CUF "Cursor Forward" "CSI Ps C" "Move cursor `Ps` times forward (default=1)." - */ - public cursorForward(params: IParams): boolean { - this._moveCursor(params.params[0] || 1, 0); - return true; - } - - /** - * CSI Ps D - * Cursor Backward Ps Times (default = 1) (CUB). - * - * @vt: #Y CSI CUB "Cursor Backward" "CSI Ps D" "Move cursor `Ps` times backward (default=1)." - */ - public cursorBackward(params: IParams): boolean { - this._moveCursor(-(params.params[0] || 1), 0); - return true; - } - - /** - * CSI Ps E - * Cursor Next Line Ps Times (default = 1) (CNL). - * Other than cursorDown (CUD) also set the cursor to first column. - * - * @vt: #Y CSI CNL "Cursor Next Line" "CSI Ps E" "Move cursor `Ps` times down (default=1) and to the first column." - * Same as CUD, additionally places the cursor at the first column. - */ - public cursorNextLine(params: IParams): boolean { - this.cursorDown(params); - this._activeBuffer.x = 0; - return true; - } - - /** - * CSI Ps F - * Cursor Previous Line Ps Times (default = 1) (CPL). - * Other than cursorUp (CUU) also set the cursor to first column. - * - * @vt: #Y CSI CPL "Cursor Backward" "CSI Ps F" "Move cursor `Ps` times up (default=1) and to the first column." - * Same as CUU, additionally places the cursor at the first column. - */ - public cursorPrecedingLine(params: IParams): boolean { - this.cursorUp(params); - this._activeBuffer.x = 0; - return true; - } - - /** - * CSI Ps G - * Cursor Character Absolute [column] (default = [row,1]) (CHA). - * - * @vt: #Y CSI CHA "Cursor Horizontal Absolute" "CSI Ps G" "Move cursor to `Ps`-th column of the active row (default=1)." - */ - public cursorCharAbsolute(params: IParams): boolean { - this._setCursor((params.params[0] || 1) - 1, this._activeBuffer.y); - return true; - } - - /** - * CSI Ps ; Ps H - * Cursor Position [row;column] (default = [1,1]) (CUP). - * - * @vt: #Y CSI CUP "Cursor Position" "CSI Ps ; Ps H" "Set cursor to position [`Ps`, `Ps`] (default = [1, 1])." - * If ORIGIN mode is set, places the cursor to the absolute position within the scroll margins. - * If ORIGIN mode is not set, places the cursor to the absolute position within the viewport. - * Note that the coordinates are 1-based, thus the top left position starts at `1 ; 1`. - */ - public cursorPosition(params: IParams): boolean { - this._setCursor( - // col - (params.length >= 2) ? (params.params[1] || 1) - 1 : 0, - // row - (params.params[0] || 1) - 1 - ); - return true; - } - - /** - * CSI Pm ` Character Position Absolute - * [column] (default = [row,1]) (HPA). - * Currently same functionality as CHA. - * - * @vt: #Y CSI HPA "Horizontal Position Absolute" "CSI Ps ` " "Same as CHA." - */ - public charPosAbsolute(params: IParams): boolean { - this._setCursor((params.params[0] || 1) - 1, this._activeBuffer.y); - return true; - } - - /** - * CSI Pm a Character Position Relative - * [columns] (default = [row,col+1]) (HPR) - * - * @vt: #Y CSI HPR "Horizontal Position Relative" "CSI Ps a" "Same as CUF." - */ - public hPositionRelative(params: IParams): boolean { - this._moveCursor(params.params[0] || 1, 0); - return true; - } - - /** - * CSI Pm d Vertical Position Absolute (VPA) - * [row] (default = [1,column]) - * - * @vt: #Y CSI VPA "Vertical Position Absolute" "CSI Ps d" "Move cursor to `Ps`-th row (default=1)." - */ - public linePosAbsolute(params: IParams): boolean { - this._setCursor(this._activeBuffer.x, (params.params[0] || 1) - 1); - return true; - } - - /** - * CSI Pm e Vertical Position Relative (VPR) - * [rows] (default = [row+1,column]) - * reuse CSI Ps B ? - * - * @vt: #Y CSI VPR "Vertical Position Relative" "CSI Ps e" "Move cursor `Ps` times down (default=1)." - */ - public vPositionRelative(params: IParams): boolean { - this._moveCursor(0, params.params[0] || 1); - return true; - } - - /** - * CSI Ps ; Ps f - * Horizontal and Vertical Position [row;column] (default = - * [1,1]) (HVP). - * Same as CUP. - * - * @vt: #Y CSI HVP "Horizontal and Vertical Position" "CSI Ps ; Ps f" "Same as CUP." - */ - public hVPosition(params: IParams): boolean { - this.cursorPosition(params); - return true; - } - - /** - * CSI Ps g Tab Clear (TBC). - * Ps = 0 -> Clear Current Column (default). - * Ps = 3 -> Clear All. - * Potentially: - * Ps = 2 -> Clear Stops on Line. - * http://vt100.net/annarbor/aaa-ug/section6.html - * - * @vt: #Y CSI TBC "Tab Clear" "CSI Ps g" "Clear tab stops at current position (0) or all (3) (default=0)." - * Clearing tabstops off the active row (Ps = 2, VT100) is currently not supported. - */ - public tabClear(params: IParams): boolean { - const param = params.params[0]; - if (param === 0) { - delete this._activeBuffer.tabs[this._activeBuffer.x]; - } else if (param === 3) { - this._activeBuffer.tabs = {}; - } - return true; - } - - /** - * CSI Ps I - * Cursor Forward Tabulation Ps tab stops (default = 1) (CHT). - * - * @vt: #Y CSI CHT "Cursor Horizontal Tabulation" "CSI Ps I" "Move cursor `Ps` times tabs forward (default=1)." - */ - public cursorForwardTab(params: IParams): boolean { - if (this._activeBuffer.x >= this._bufferService.cols) { - return true; - } - let param = params.params[0] || 1; - while (param--) { - this._activeBuffer.x = this._activeBuffer.nextStop(); - } - return true; - } - - /** - * CSI Ps Z Cursor Backward Tabulation Ps tab stops (default = 1) (CBT). - * - * @vt: #Y CSI CBT "Cursor Backward Tabulation" "CSI Ps Z" "Move cursor `Ps` tabs backward (default=1)." - */ - public cursorBackwardTab(params: IParams): boolean { - if (this._activeBuffer.x >= this._bufferService.cols) { - return true; - } - let param = params.params[0] || 1; - - while (param--) { - this._activeBuffer.x = this._activeBuffer.prevStop(); - } - return true; - } - - - /** - * Helper method to erase cells in a terminal row. - * The cell gets replaced with the eraseChar of the terminal. - * @param y row index - * @param start first cell index to be erased - * @param end end - 1 is last erased cell - * @param cleanWrap clear the isWrapped flag - */ - private _eraseInBufferLine(y: number, start: number, end: number, clearWrap: boolean = false): void { - const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + y)!; - line.replaceCells( - start, - end, - this._activeBuffer.getNullCell(this._eraseAttrData()), - this._eraseAttrData() - ); - if (clearWrap) { - line.isWrapped = false; - } - } - - /** - * Helper method to reset cells in a terminal row. - * The cell gets replaced with the eraseChar of the terminal and the isWrapped property is set to false. - * @param y row index - */ - private _resetBufferLine(y: number): void { - const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + y)!; - line.fill(this._activeBuffer.getNullCell(this._eraseAttrData())); - this._bufferService.buffer.clearMarkers(this._activeBuffer.ybase + y); - line.isWrapped = false; - } - - /** - * CSI Ps J Erase in Display (ED). - * Ps = 0 -> Erase Below (default). - * Ps = 1 -> Erase Above. - * Ps = 2 -> Erase All. - * Ps = 3 -> Erase Saved Lines (xterm). - * CSI ? Ps J - * Erase in Display (DECSED). - * Ps = 0 -> Selective Erase Below (default). - * Ps = 1 -> Selective Erase Above. - * Ps = 2 -> Selective Erase All. - * - * @vt: #Y CSI ED "Erase In Display" "CSI Ps J" "Erase various parts of the viewport." - * Supported param values: - * - * | Ps | Effect | - * | -- | ------------------------------------------------------------ | - * | 0 | Erase from the cursor through the end of the viewport. | - * | 1 | Erase from the beginning of the viewport through the cursor. | - * | 2 | Erase complete viewport. | - * | 3 | Erase scrollback. | - * - * @vt: #P[Protection attributes are not supported.] CSI DECSED "Selective Erase In Display" "CSI ? Ps J" "Currently the same as ED." - */ - public eraseInDisplay(params: IParams): boolean { - this._restrictCursor(this._bufferService.cols); - let j; - switch (params.params[0]) { - case 0: - j = this._activeBuffer.y; - this._dirtyRowService.markDirty(j); - this._eraseInBufferLine(j++, this._activeBuffer.x, this._bufferService.cols, this._activeBuffer.x === 0); - for (; j < this._bufferService.rows; j++) { - this._resetBufferLine(j); - } - this._dirtyRowService.markDirty(j); - break; - case 1: - j = this._activeBuffer.y; - this._dirtyRowService.markDirty(j); - // Deleted front part of line and everything before. This line will no longer be wrapped. - this._eraseInBufferLine(j, 0, this._activeBuffer.x + 1, true); - if (this._activeBuffer.x + 1 >= this._bufferService.cols) { - // Deleted entire previous line. This next line can no longer be wrapped. - this._activeBuffer.lines.get(j + 1)!.isWrapped = false; - } - while (j--) { - this._resetBufferLine(j); - } - this._dirtyRowService.markDirty(0); - break; - case 2: - j = this._bufferService.rows; - this._dirtyRowService.markDirty(j - 1); - while (j--) { - this._resetBufferLine(j); - } - this._dirtyRowService.markDirty(0); - break; - case 3: - // Clear scrollback (everything not in viewport) - const scrollBackSize = this._activeBuffer.lines.length - this._bufferService.rows; - if (scrollBackSize > 0) { - this._activeBuffer.lines.trimStart(scrollBackSize); - this._activeBuffer.ybase = Math.max(this._activeBuffer.ybase - scrollBackSize, 0); - this._activeBuffer.ydisp = Math.max(this._activeBuffer.ydisp - scrollBackSize, 0); - // Force a scroll event to refresh viewport - this._onScroll.fire(0); - } - break; - } - return true; - } - - /** - * CSI Ps K Erase in Line (EL). - * Ps = 0 -> Erase to Right (default). - * Ps = 1 -> Erase to Left. - * Ps = 2 -> Erase All. - * CSI ? Ps K - * Erase in Line (DECSEL). - * Ps = 0 -> Selective Erase to Right (default). - * Ps = 1 -> Selective Erase to Left. - * Ps = 2 -> Selective Erase All. - * - * @vt: #Y CSI EL "Erase In Line" "CSI Ps K" "Erase various parts of the active row." - * Supported param values: - * - * | Ps | Effect | - * | -- | -------------------------------------------------------- | - * | 0 | Erase from the cursor through the end of the row. | - * | 1 | Erase from the beginning of the line through the cursor. | - * | 2 | Erase complete line. | - * - * @vt: #P[Protection attributes are not supported.] CSI DECSEL "Selective Erase In Line" "CSI ? Ps K" "Currently the same as EL." - */ - public eraseInLine(params: IParams): boolean { - this._restrictCursor(this._bufferService.cols); - switch (params.params[0]) { - case 0: - this._eraseInBufferLine(this._activeBuffer.y, this._activeBuffer.x, this._bufferService.cols, this._activeBuffer.x === 0); - break; - case 1: - this._eraseInBufferLine(this._activeBuffer.y, 0, this._activeBuffer.x + 1, false); - break; - case 2: - this._eraseInBufferLine(this._activeBuffer.y, 0, this._bufferService.cols, true); - break; - } - this._dirtyRowService.markDirty(this._activeBuffer.y); - return true; - } - - /** - * CSI Ps L - * Insert Ps Line(s) (default = 1) (IL). - * - * @vt: #Y CSI IL "Insert Line" "CSI Ps L" "Insert `Ps` blank lines at active row (default=1)." - * For every inserted line at the scroll top one line at the scroll bottom gets removed. - * The cursor is set to the first column. - * IL has no effect if the cursor is outside the scroll margins. - */ - public insertLines(params: IParams): boolean { - this._restrictCursor(); - let param = params.params[0] || 1; - - if (this._activeBuffer.y > this._activeBuffer.scrollBottom || this._activeBuffer.y < this._activeBuffer.scrollTop) { - return true; - } - - const row: number = this._activeBuffer.ybase + this._activeBuffer.y; - - const scrollBottomRowsOffset = this._bufferService.rows - 1 - this._activeBuffer.scrollBottom; - const scrollBottomAbsolute = this._bufferService.rows - 1 + this._activeBuffer.ybase - scrollBottomRowsOffset + 1; - while (param--) { - // test: echo -e '\e[44m\e[1L\e[0m' - // blankLine(true) - xterm/linux behavior - this._activeBuffer.lines.splice(scrollBottomAbsolute - 1, 1); - this._activeBuffer.lines.splice(row, 0, this._activeBuffer.getBlankLine(this._eraseAttrData())); - } - - this._dirtyRowService.markRangeDirty(this._activeBuffer.y, this._activeBuffer.scrollBottom); - this._activeBuffer.x = 0; // see https://vt100.net/docs/vt220-rm/chapter4.html - vt220 only? - return true; - } - - /** - * CSI Ps M - * Delete Ps Line(s) (default = 1) (DL). - * - * @vt: #Y CSI DL "Delete Line" "CSI Ps M" "Delete `Ps` lines at active row (default=1)." - * For every deleted line at the scroll top one blank line at the scroll bottom gets appended. - * The cursor is set to the first column. - * DL has no effect if the cursor is outside the scroll margins. - */ - public deleteLines(params: IParams): boolean { - this._restrictCursor(); - let param = params.params[0] || 1; - - if (this._activeBuffer.y > this._activeBuffer.scrollBottom || this._activeBuffer.y < this._activeBuffer.scrollTop) { - return true; - } - - const row: number = this._activeBuffer.ybase + this._activeBuffer.y; - - let j: number; - j = this._bufferService.rows - 1 - this._activeBuffer.scrollBottom; - j = this._bufferService.rows - 1 + this._activeBuffer.ybase - j; - while (param--) { - // test: echo -e '\e[44m\e[1M\e[0m' - // blankLine(true) - xterm/linux behavior - this._activeBuffer.lines.splice(row, 1); - this._activeBuffer.lines.splice(j, 0, this._activeBuffer.getBlankLine(this._eraseAttrData())); - } - - this._dirtyRowService.markRangeDirty(this._activeBuffer.y, this._activeBuffer.scrollBottom); - this._activeBuffer.x = 0; // see https://vt100.net/docs/vt220-rm/chapter4.html - vt220 only? - return true; - } - - /** - * CSI Ps @ - * Insert Ps (Blank) Character(s) (default = 1) (ICH). - * - * @vt: #Y CSI ICH "Insert Characters" "CSI Ps @" "Insert `Ps` (blank) characters (default = 1)." - * The ICH sequence inserts `Ps` blank characters. The cursor remains at the beginning of the blank characters. - * Text between the cursor and right margin moves to the right. Characters moved past the right margin are lost. - * - * - * FIXME: check against xterm - should not work outside of scroll margins (see VT520 manual) - */ - public insertChars(params: IParams): boolean { - this._restrictCursor(); - const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y); - if (line) { - line.insertCells( - this._activeBuffer.x, - params.params[0] || 1, - this._activeBuffer.getNullCell(this._eraseAttrData()), - this._eraseAttrData() - ); - this._dirtyRowService.markDirty(this._activeBuffer.y); - } - return true; - } - - /** - * CSI Ps P - * Delete Ps Character(s) (default = 1) (DCH). - * - * @vt: #Y CSI DCH "Delete Character" "CSI Ps P" "Delete `Ps` characters (default=1)." - * As characters are deleted, the remaining characters between the cursor and right margin move to the left. - * Character attributes move with the characters. The terminal adds blank characters at the right margin. - * - * - * FIXME: check against xterm - should not work outside of scroll margins (see VT520 manual) - */ - public deleteChars(params: IParams): boolean { - this._restrictCursor(); - const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y); - if (line) { - line.deleteCells( - this._activeBuffer.x, - params.params[0] || 1, - this._activeBuffer.getNullCell(this._eraseAttrData()), - this._eraseAttrData() - ); - this._dirtyRowService.markDirty(this._activeBuffer.y); - } - return true; - } - - /** - * CSI Ps S Scroll up Ps lines (default = 1) (SU). - * - * @vt: #Y CSI SU "Scroll Up" "CSI Ps S" "Scroll `Ps` lines up (default=1)." - * - * - * FIXME: scrolled out lines at top = 1 should add to scrollback (xterm) - */ - public scrollUp(params: IParams): boolean { - let param = params.params[0] || 1; - - while (param--) { - this._activeBuffer.lines.splice(this._activeBuffer.ybase + this._activeBuffer.scrollTop, 1); - this._activeBuffer.lines.splice(this._activeBuffer.ybase + this._activeBuffer.scrollBottom, 0, this._activeBuffer.getBlankLine(this._eraseAttrData())); - } - this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop, this._activeBuffer.scrollBottom); - return true; - } - - /** - * CSI Ps T Scroll down Ps lines (default = 1) (SD). - * - * @vt: #Y CSI SD "Scroll Down" "CSI Ps T" "Scroll `Ps` lines down (default=1)." - */ - public scrollDown(params: IParams): boolean { - let param = params.params[0] || 1; - - while (param--) { - this._activeBuffer.lines.splice(this._activeBuffer.ybase + this._activeBuffer.scrollBottom, 1); - this._activeBuffer.lines.splice(this._activeBuffer.ybase + this._activeBuffer.scrollTop, 0, this._activeBuffer.getBlankLine(DEFAULT_ATTR_DATA)); - } - this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop, this._activeBuffer.scrollBottom); - return true; - } - - /** - * CSI Ps SP @ Scroll left Ps columns (default = 1) (SL) ECMA-48 - * - * Notation: (Pn) - * Representation: CSI Pn 02/00 04/00 - * Parameter default value: Pn = 1 - * SL causes the data in the presentation component to be moved by n character positions - * if the line orientation is horizontal, or by n line positions if the line orientation - * is vertical, such that the data appear to move to the left; where n equals the value of Pn. - * The active presentation position is not affected by this control function. - * - * Supported: - * - always left shift (no line orientation setting respected) - * - * @vt: #Y CSI SL "Scroll Left" "CSI Ps SP @" "Scroll viewport `Ps` times to the left." - * SL moves the content of all lines within the scroll margins `Ps` times to the left. - * SL has no effect outside of the scroll margins. - */ - public scrollLeft(params: IParams): boolean { - if (this._activeBuffer.y > this._activeBuffer.scrollBottom || this._activeBuffer.y < this._activeBuffer.scrollTop) { - return true; - } - const param = params.params[0] || 1; - for (let y = this._activeBuffer.scrollTop; y <= this._activeBuffer.scrollBottom; ++y) { - const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + y)!; - line.deleteCells(0, param, this._activeBuffer.getNullCell(this._eraseAttrData()), this._eraseAttrData()); - line.isWrapped = false; - } - this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop, this._activeBuffer.scrollBottom); - return true; - } - - /** - * CSI Ps SP A Scroll right Ps columns (default = 1) (SR) ECMA-48 - * - * Notation: (Pn) - * Representation: CSI Pn 02/00 04/01 - * Parameter default value: Pn = 1 - * SR causes the data in the presentation component to be moved by n character positions - * if the line orientation is horizontal, or by n line positions if the line orientation - * is vertical, such that the data appear to move to the right; where n equals the value of Pn. - * The active presentation position is not affected by this control function. - * - * Supported: - * - always right shift (no line orientation setting respected) - * - * @vt: #Y CSI SR "Scroll Right" "CSI Ps SP A" "Scroll viewport `Ps` times to the right." - * SL moves the content of all lines within the scroll margins `Ps` times to the right. - * Content at the right margin is lost. - * SL has no effect outside of the scroll margins. - */ - public scrollRight(params: IParams): boolean { - if (this._activeBuffer.y > this._activeBuffer.scrollBottom || this._activeBuffer.y < this._activeBuffer.scrollTop) { - return true; - } - const param = params.params[0] || 1; - for (let y = this._activeBuffer.scrollTop; y <= this._activeBuffer.scrollBottom; ++y) { - const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + y)!; - line.insertCells(0, param, this._activeBuffer.getNullCell(this._eraseAttrData()), this._eraseAttrData()); - line.isWrapped = false; - } - this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop, this._activeBuffer.scrollBottom); - return true; - } - - /** - * CSI Pm ' } - * Insert Ps Column(s) (default = 1) (DECIC), VT420 and up. - * - * @vt: #Y CSI DECIC "Insert Columns" "CSI Ps ' }" "Insert `Ps` columns at cursor position." - * DECIC inserts `Ps` times blank columns at the cursor position for all lines with the scroll margins, - * moving content to the right. Content at the right margin is lost. - * DECIC has no effect outside the scrolling margins. - */ - public insertColumns(params: IParams): boolean { - if (this._activeBuffer.y > this._activeBuffer.scrollBottom || this._activeBuffer.y < this._activeBuffer.scrollTop) { - return true; - } - const param = params.params[0] || 1; - for (let y = this._activeBuffer.scrollTop; y <= this._activeBuffer.scrollBottom; ++y) { - const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + y)!; - line.insertCells(this._activeBuffer.x, param, this._activeBuffer.getNullCell(this._eraseAttrData()), this._eraseAttrData()); - line.isWrapped = false; - } - this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop, this._activeBuffer.scrollBottom); - return true; - } - - /** - * CSI Pm ' ~ - * Delete Ps Column(s) (default = 1) (DECDC), VT420 and up. - * - * @vt: #Y CSI DECDC "Delete Columns" "CSI Ps ' ~" "Delete `Ps` columns at cursor position." - * DECDC deletes `Ps` times columns at the cursor position for all lines with the scroll margins, - * moving content to the left. Blank columns are added at the right margin. - * DECDC has no effect outside the scrolling margins. - */ - public deleteColumns(params: IParams): boolean { - if (this._activeBuffer.y > this._activeBuffer.scrollBottom || this._activeBuffer.y < this._activeBuffer.scrollTop) { - return true; - } - const param = params.params[0] || 1; - for (let y = this._activeBuffer.scrollTop; y <= this._activeBuffer.scrollBottom; ++y) { - const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + y)!; - line.deleteCells(this._activeBuffer.x, param, this._activeBuffer.getNullCell(this._eraseAttrData()), this._eraseAttrData()); - line.isWrapped = false; - } - this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop, this._activeBuffer.scrollBottom); - return true; - } - - /** - * CSI Ps X - * Erase Ps Character(s) (default = 1) (ECH). - * - * @vt: #Y CSI ECH "Erase Character" "CSI Ps X" "Erase `Ps` characters from current cursor position to the right (default=1)." - * ED erases `Ps` characters from current cursor position to the right. - * ED works inside or outside the scrolling margins. - */ - public eraseChars(params: IParams): boolean { - this._restrictCursor(); - const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y); - if (line) { - line.replaceCells( - this._activeBuffer.x, - this._activeBuffer.x + (params.params[0] || 1), - this._activeBuffer.getNullCell(this._eraseAttrData()), - this._eraseAttrData() - ); - this._dirtyRowService.markDirty(this._activeBuffer.y); - } - return true; - } - - /** - * CSI Ps b Repeat the preceding graphic character Ps times (REP). - * From ECMA 48 (@see http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf) - * Notation: (Pn) - * Representation: CSI Pn 06/02 - * Parameter default value: Pn = 1 - * REP is used to indicate that the preceding character in the data stream, - * if it is a graphic character (represented by one or more bit combinations) including SPACE, - * is to be repeated n times, where n equals the value of Pn. - * If the character preceding REP is a control function or part of a control function, - * the effect of REP is not defined by this Standard. - * - * Since we propagate the terminal as xterm-256color we have to follow xterm's behavior: - * - fullwidth + surrogate chars are ignored - * - for combining chars only the base char gets repeated - * - text attrs are applied normally - * - wrap around is respected - * - any valid sequence resets the carried forward char - * - * Note: To get reset on a valid sequence working correctly without much runtime penalty, - * the preceding codepoint is stored on the parser in `this.print` and reset during `parser.parse`. - * - * @vt: #Y CSI REP "Repeat Preceding Character" "CSI Ps b" "Repeat preceding character `Ps` times (default=1)." - * REP repeats the previous character `Ps` times advancing the cursor, also wrapping if DECAWM is set. - * REP has no effect if the sequence does not follow a printable ASCII character - * (NOOP for any other sequence in between or NON ASCII characters). - */ - public repeatPrecedingCharacter(params: IParams): boolean { - if (!this._parser.precedingCodepoint) { - return true; - } - // call print to insert the chars and handle correct wrapping - const length = params.params[0] || 1; - const data = new Uint32Array(length); - for (let i = 0; i < length; ++i) { - data[i] = this._parser.precedingCodepoint; - } - this.print(data, 0, data.length); - return true; - } - - /** - * CSI Ps c Send Device Attributes (Primary DA). - * Ps = 0 or omitted -> request attributes from terminal. The - * response depends on the decTerminalID resource setting. - * -> CSI ? 1 ; 2 c (``VT100 with Advanced Video Option'') - * -> CSI ? 1 ; 0 c (``VT101 with No Options'') - * -> CSI ? 6 c (``VT102'') - * -> CSI ? 6 0 ; 1 ; 2 ; 6 ; 8 ; 9 ; 1 5 ; c (``VT220'') - * The VT100-style response parameters do not mean anything by - * themselves. VT220 parameters do, telling the host what fea- - * tures the terminal supports: - * Ps = 1 -> 132-columns. - * Ps = 2 -> Printer. - * Ps = 6 -> Selective erase. - * Ps = 8 -> User-defined keys. - * Ps = 9 -> National replacement character sets. - * Ps = 1 5 -> Technical characters. - * Ps = 2 2 -> ANSI color, e.g., VT525. - * Ps = 2 9 -> ANSI text locator (i.e., DEC Locator mode). - * - * @vt: #Y CSI DA1 "Primary Device Attributes" "CSI c" "Send primary device attributes." - * - * - * TODO: fix and cleanup response - */ - public sendDeviceAttributesPrimary(params: IParams): boolean { - if (params.params[0] > 0) { - return true; - } - if (this._is('xterm') || this._is('rxvt-unicode') || this._is('screen')) { - this._coreService.triggerDataEvent(C0.ESC + '[?1;2c'); - } else if (this._is('linux')) { - this._coreService.triggerDataEvent(C0.ESC + '[?6c'); - } - return true; - } - - /** - * CSI > Ps c - * Send Device Attributes (Secondary DA). - * Ps = 0 or omitted -> request the terminal's identification - * code. The response depends on the decTerminalID resource set- - * ting. It should apply only to VT220 and up, but xterm extends - * this to VT100. - * -> CSI > Pp ; Pv ; Pc c - * where Pp denotes the terminal type - * Pp = 0 -> ``VT100''. - * Pp = 1 -> ``VT220''. - * and Pv is the firmware version (for xterm, this was originally - * the XFree86 patch number, starting with 95). In a DEC termi- - * nal, Pc indicates the ROM cartridge registration number and is - * always zero. - * More information: - * xterm/charproc.c - line 2012, for more information. - * vim responds with ^[[?0c or ^[[?1c after the terminal's response (?) - * - * @vt: #Y CSI DA2 "Secondary Device Attributes" "CSI > c" "Send primary device attributes." - * - * - * TODO: fix and cleanup response - */ - public sendDeviceAttributesSecondary(params: IParams): boolean { - if (params.params[0] > 0) { - return true; - } - // xterm and urxvt - // seem to spit this - // out around ~370 times (?). - if (this._is('xterm')) { - this._coreService.triggerDataEvent(C0.ESC + '[>0;276;0c'); - } else if (this._is('rxvt-unicode')) { - this._coreService.triggerDataEvent(C0.ESC + '[>85;95;0c'); - } else if (this._is('linux')) { - // not supported by linux console. - // linux console echoes parameters. - this._coreService.triggerDataEvent(params.params[0] + 'c'); - } else if (this._is('screen')) { - this._coreService.triggerDataEvent(C0.ESC + '[>83;40003;0c'); - } - return true; - } - - /** - * Evaluate if the current terminal is the given argument. - * @param term The terminal name to evaluate - */ - private _is(term: string): boolean { - return (this._optionsService.rawOptions.termName + '').indexOf(term) === 0; - } - - /** - * CSI Pm h Set Mode (SM). - * Ps = 2 -> Keyboard Action Mode (AM). - * Ps = 4 -> Insert Mode (IRM). - * Ps = 1 2 -> Send/receive (SRM). - * Ps = 2 0 -> Automatic Newline (LNM). - * - * @vt: #P[Only IRM is supported.] CSI SM "Set Mode" "CSI Pm h" "Set various terminal modes." - * Supported param values by SM: - * - * | Param | Action | Support | - * | ----- | -------------------------------------- | ------- | - * | 2 | Keyboard Action Mode (KAM). Always on. | #N | - * | 4 | Insert Mode (IRM). | #Y | - * | 12 | Send/receive (SRM). Always off. | #N | - * | 20 | Automatic Newline (LNM). Always off. | #N | - */ - public setMode(params: IParams): boolean { - for (let i = 0; i < params.length; i++) { - switch (params.params[i]) { - case 4: - this._coreService.modes.insertMode = true; - break; - case 20: - // this._t.convertEol = true; - break; - } - } - return true; - } - - /** - * CSI ? Pm h - * DEC Private Mode Set (DECSET). - * Ps = 1 -> Application Cursor Keys (DECCKM). - * Ps = 2 -> Designate USASCII for character sets G0-G3 - * (DECANM), and set VT100 mode. - * Ps = 3 -> 132 Column Mode (DECCOLM). - * Ps = 4 -> Smooth (Slow) Scroll (DECSCLM). - * Ps = 5 -> Reverse Video (DECSCNM). - * Ps = 6 -> Origin Mode (DECOM). - * Ps = 7 -> Wraparound Mode (DECAWM). - * Ps = 8 -> Auto-repeat Keys (DECARM). - * Ps = 9 -> Send Mouse X & Y on button press. See the sec- - * tion Mouse Tracking. - * Ps = 1 0 -> Show toolbar (rxvt). - * Ps = 1 2 -> Start Blinking Cursor (att610). - * Ps = 1 8 -> Print form feed (DECPFF). - * Ps = 1 9 -> Set print extent to full screen (DECPEX). - * Ps = 2 5 -> Show Cursor (DECTCEM). - * Ps = 3 0 -> Show scrollbar (rxvt). - * Ps = 3 5 -> Enable font-shifting functions (rxvt). - * Ps = 3 8 -> Enter Tektronix Mode (DECTEK). - * Ps = 4 0 -> Allow 80 -> 132 Mode. - * Ps = 4 1 -> more(1) fix (see curses resource). - * Ps = 4 2 -> Enable Nation Replacement Character sets (DECN- - * RCM). - * Ps = 4 4 -> Turn On Margin Bell. - * Ps = 4 5 -> Reverse-wraparound Mode. - * Ps = 4 6 -> Start Logging. This is normally disabled by a - * compile-time option. - * Ps = 4 7 -> Use Alternate Screen Buffer. (This may be dis- - * abled by the titeInhibit resource). - * Ps = 6 6 -> Application keypad (DECNKM). - * Ps = 6 7 -> Backarrow key sends backspace (DECBKM). - * Ps = 1 0 0 0 -> Send Mouse X & Y on button press and - * release. See the section Mouse Tracking. - * Ps = 1 0 0 1 -> Use Hilite Mouse Tracking. - * Ps = 1 0 0 2 -> Use Cell Motion Mouse Tracking. - * Ps = 1 0 0 3 -> Use All Motion Mouse Tracking. - * Ps = 1 0 0 4 -> Send FocusIn/FocusOut events. - * Ps = 1 0 0 5 -> Enable Extended Mouse Mode. - * Ps = 1 0 1 0 -> Scroll to bottom on tty output (rxvt). - * Ps = 1 0 1 1 -> Scroll to bottom on key press (rxvt). - * Ps = 1 0 3 4 -> Interpret "meta" key, sets eighth bit. - * (enables the eightBitInput resource). - * Ps = 1 0 3 5 -> Enable special modifiers for Alt and Num- - * Lock keys. (This enables the numLock resource). - * Ps = 1 0 3 6 -> Send ESC when Meta modifies a key. (This - * enables the metaSendsEscape resource). - * Ps = 1 0 3 7 -> Send DEL from the editing-keypad Delete - * key. - * Ps = 1 0 3 9 -> Send ESC when Alt modifies a key. (This - * enables the altSendsEscape resource). - * Ps = 1 0 4 0 -> Keep selection even if not highlighted. - * (This enables the keepSelection resource). - * Ps = 1 0 4 1 -> Use the CLIPBOARD selection. (This enables - * the selectToClipboard resource). - * Ps = 1 0 4 2 -> Enable Urgency window manager hint when - * Control-G is received. (This enables the bellIsUrgent - * resource). - * Ps = 1 0 4 3 -> Enable raising of the window when Control-G - * is received. (enables the popOnBell resource). - * Ps = 1 0 4 7 -> Use Alternate Screen Buffer. (This may be - * disabled by the titeInhibit resource). - * Ps = 1 0 4 8 -> Save cursor as in DECSC. (This may be dis- - * abled by the titeInhibit resource). - * Ps = 1 0 4 9 -> Save cursor as in DECSC and use Alternate - * Screen Buffer, clearing it first. (This may be disabled by - * the titeInhibit resource). This combines the effects of the 1 - * 0 4 7 and 1 0 4 8 modes. Use this with terminfo-based - * applications rather than the 4 7 mode. - * Ps = 1 0 5 0 -> Set terminfo/termcap function-key mode. - * Ps = 1 0 5 1 -> Set Sun function-key mode. - * Ps = 1 0 5 2 -> Set HP function-key mode. - * Ps = 1 0 5 3 -> Set SCO function-key mode. - * Ps = 1 0 6 0 -> Set legacy keyboard emulation (X11R6). - * Ps = 1 0 6 1 -> Set VT220 keyboard emulation. - * Ps = 2 0 0 4 -> Set bracketed paste mode. - * Modes: - * http: *vt100.net/docs/vt220-rm/chapter4.html - * - * @vt: #P[See below for supported modes.] CSI DECSET "DEC Private Set Mode" "CSI ? Pm h" "Set various terminal attributes." - * Supported param values by DECSET: - * - * | param | Action | Support | - * | ----- | ------------------------------------------------------- | --------| - * | 1 | Application Cursor Keys (DECCKM). | #Y | - * | 2 | Designate US-ASCII for character sets G0-G3 (DECANM). | #Y | - * | 3 | 132 Column Mode (DECCOLM). | #Y | - * | 6 | Origin Mode (DECOM). | #Y | - * | 7 | Auto-wrap Mode (DECAWM). | #Y | - * | 8 | Auto-repeat Keys (DECARM). Always on. | #N | - * | 9 | X10 xterm mouse protocol. | #Y | - * | 12 | Start Blinking Cursor. | #Y | - * | 25 | Show Cursor (DECTCEM). | #Y | - * | 45 | Reverse wrap-around. | #Y | - * | 47 | Use Alternate Screen Buffer. | #Y | - * | 66 | Application keypad (DECNKM). | #Y | - * | 1000 | X11 xterm mouse protocol. | #Y | - * | 1002 | Use Cell Motion Mouse Tracking. | #Y | - * | 1003 | Use All Motion Mouse Tracking. | #Y | - * | 1004 | Send FocusIn/FocusOut events | #Y | - * | 1005 | Enable UTF-8 Mouse Mode. | #N | - * | 1006 | Enable SGR Mouse Mode. | #Y | - * | 1015 | Enable urxvt Mouse Mode. | #N | - * | 1047 | Use Alternate Screen Buffer. | #Y | - * | 1048 | Save cursor as in DECSC. | #Y | - * | 1049 | Save cursor and switch to alternate buffer clearing it. | #P[Does not clear the alternate buffer.] | - * | 2004 | Set bracketed paste mode. | #Y | - * - * - * FIXME: implement DECSCNM, 1049 should clear altbuffer - */ - public setModePrivate(params: IParams): boolean { - for (let i = 0; i < params.length; i++) { - switch (params.params[i]) { - case 1: - this._coreService.decPrivateModes.applicationCursorKeys = true; - break; - case 2: - this._charsetService.setgCharset(0, DEFAULT_CHARSET); - this._charsetService.setgCharset(1, DEFAULT_CHARSET); - this._charsetService.setgCharset(2, DEFAULT_CHARSET); - this._charsetService.setgCharset(3, DEFAULT_CHARSET); - // set VT100 mode here - break; - case 3: - /** - * DECCOLM - 132 column mode. - * This is only active if 'SetWinLines' (24) is enabled - * through `options.windowsOptions`. - */ - if (this._optionsService.rawOptions.windowOptions.setWinLines) { - this._bufferService.resize(132, this._bufferService.rows); - this._onRequestReset.fire(); - } - break; - case 6: - this._coreService.decPrivateModes.origin = true; - this._setCursor(0, 0); - break; - case 7: - this._coreService.decPrivateModes.wraparound = true; - break; - case 12: - // this.cursorBlink = true; - break; - case 45: - this._coreService.decPrivateModes.reverseWraparound = true; - break; - case 66: - this._logService.debug('Serial port requested application keypad.'); - this._coreService.decPrivateModes.applicationKeypad = true; - this._onRequestSyncScrollBar.fire(); - break; - case 9: // X10 Mouse - // no release, no motion, no wheel, no modifiers. - this._coreMouseService.activeProtocol = 'X10'; - break; - case 1000: // vt200 mouse - // no motion. - this._coreMouseService.activeProtocol = 'VT200'; - break; - case 1002: // button event mouse - this._coreMouseService.activeProtocol = 'DRAG'; - break; - case 1003: // any event mouse - // any event - sends motion events, - // even if there is no button held down. - this._coreMouseService.activeProtocol = 'ANY'; - break; - case 1004: // send focusin/focusout events - // focusin: ^[[I - // focusout: ^[[O - this._coreService.decPrivateModes.sendFocus = true; - this._onRequestSendFocus.fire(); - break; - case 1005: // utf8 ext mode mouse - removed in #2507 - this._logService.debug('DECSET 1005 not supported (see #2507)'); - break; - case 1006: // sgr ext mode mouse - this._coreMouseService.activeEncoding = 'SGR'; - break; - case 1015: // urxvt ext mode mouse - removed in #2507 - this._logService.debug('DECSET 1015 not supported (see #2507)'); - break; - case 25: // show cursor - this._coreService.isCursorHidden = false; - break; - case 1048: // alt screen cursor - this.saveCursor(); - break; - case 1049: // alt screen buffer cursor - this.saveCursor(); - // FALL-THROUGH - case 47: // alt screen buffer - case 1047: // alt screen buffer - this._bufferService.buffers.activateAltBuffer(this._eraseAttrData()); - this._coreService.isCursorInitialized = true; - this._onRequestRefreshRows.fire(0, this._bufferService.rows - 1); - this._onRequestSyncScrollBar.fire(); - break; - case 2004: // bracketed paste mode (https://cirw.in/blog/bracketed-paste) - this._coreService.decPrivateModes.bracketedPasteMode = true; - break; - } - } - return true; - } - - - /** - * CSI Pm l Reset Mode (RM). - * Ps = 2 -> Keyboard Action Mode (AM). - * Ps = 4 -> Replace Mode (IRM). - * Ps = 1 2 -> Send/receive (SRM). - * Ps = 2 0 -> Normal Linefeed (LNM). - * - * @vt: #P[Only IRM is supported.] CSI RM "Reset Mode" "CSI Pm l" "Set various terminal attributes." - * Supported param values by RM: - * - * | Param | Action | Support | - * | ----- | -------------------------------------- | ------- | - * | 2 | Keyboard Action Mode (KAM). Always on. | #N | - * | 4 | Replace Mode (IRM). (default) | #Y | - * | 12 | Send/receive (SRM). Always off. | #N | - * | 20 | Normal Linefeed (LNM). Always off. | #N | - * - * - * FIXME: why is LNM commented out? - */ - public resetMode(params: IParams): boolean { - for (let i = 0; i < params.length; i++) { - switch (params.params[i]) { - case 4: - this._coreService.modes.insertMode = false; - break; - case 20: - // this._t.convertEol = false; - break; - } - } - return true; - } - - /** - * CSI ? Pm l - * DEC Private Mode Reset (DECRST). - * Ps = 1 -> Normal Cursor Keys (DECCKM). - * Ps = 2 -> Designate VT52 mode (DECANM). - * Ps = 3 -> 80 Column Mode (DECCOLM). - * Ps = 4 -> Jump (Fast) Scroll (DECSCLM). - * Ps = 5 -> Normal Video (DECSCNM). - * Ps = 6 -> Normal Cursor Mode (DECOM). - * Ps = 7 -> No Wraparound Mode (DECAWM). - * Ps = 8 -> No Auto-repeat Keys (DECARM). - * Ps = 9 -> Don't send Mouse X & Y on button press. - * Ps = 1 0 -> Hide toolbar (rxvt). - * Ps = 1 2 -> Stop Blinking Cursor (att610). - * Ps = 1 8 -> Don't print form feed (DECPFF). - * Ps = 1 9 -> Limit print to scrolling region (DECPEX). - * Ps = 2 5 -> Hide Cursor (DECTCEM). - * Ps = 3 0 -> Don't show scrollbar (rxvt). - * Ps = 3 5 -> Disable font-shifting functions (rxvt). - * Ps = 4 0 -> Disallow 80 -> 132 Mode. - * Ps = 4 1 -> No more(1) fix (see curses resource). - * Ps = 4 2 -> Disable Nation Replacement Character sets (DEC- - * NRCM). - * Ps = 4 4 -> Turn Off Margin Bell. - * Ps = 4 5 -> No Reverse-wraparound Mode. - * Ps = 4 6 -> Stop Logging. (This is normally disabled by a - * compile-time option). - * Ps = 4 7 -> Use Normal Screen Buffer. - * Ps = 6 6 -> Numeric keypad (DECNKM). - * Ps = 6 7 -> Backarrow key sends delete (DECBKM). - * Ps = 1 0 0 0 -> Don't send Mouse X & Y on button press and - * release. See the section Mouse Tracking. - * Ps = 1 0 0 1 -> Don't use Hilite Mouse Tracking. - * Ps = 1 0 0 2 -> Don't use Cell Motion Mouse Tracking. - * Ps = 1 0 0 3 -> Don't use All Motion Mouse Tracking. - * Ps = 1 0 0 4 -> Don't send FocusIn/FocusOut events. - * Ps = 1 0 0 5 -> Disable Extended Mouse Mode. - * Ps = 1 0 1 0 -> Don't scroll to bottom on tty output - * (rxvt). - * Ps = 1 0 1 1 -> Don't scroll to bottom on key press (rxvt). - * Ps = 1 0 3 4 -> Don't interpret "meta" key. (This disables - * the eightBitInput resource). - * Ps = 1 0 3 5 -> Disable special modifiers for Alt and Num- - * Lock keys. (This disables the numLock resource). - * Ps = 1 0 3 6 -> Don't send ESC when Meta modifies a key. - * (This disables the metaSendsEscape resource). - * Ps = 1 0 3 7 -> Send VT220 Remove from the editing-keypad - * Delete key. - * Ps = 1 0 3 9 -> Don't send ESC when Alt modifies a key. - * (This disables the altSendsEscape resource). - * Ps = 1 0 4 0 -> Do not keep selection when not highlighted. - * (This disables the keepSelection resource). - * Ps = 1 0 4 1 -> Use the PRIMARY selection. (This disables - * the selectToClipboard resource). - * Ps = 1 0 4 2 -> Disable Urgency window manager hint when - * Control-G is received. (This disables the bellIsUrgent - * resource). - * Ps = 1 0 4 3 -> Disable raising of the window when Control- - * G is received. (This disables the popOnBell resource). - * Ps = 1 0 4 7 -> Use Normal Screen Buffer, clearing screen - * first if in the Alternate Screen. (This may be disabled by - * the titeInhibit resource). - * Ps = 1 0 4 8 -> Restore cursor as in DECRC. (This may be - * disabled by the titeInhibit resource). - * Ps = 1 0 4 9 -> Use Normal Screen Buffer and restore cursor - * as in DECRC. (This may be disabled by the titeInhibit - * resource). This combines the effects of the 1 0 4 7 and 1 0 - * 4 8 modes. Use this with terminfo-based applications rather - * than the 4 7 mode. - * Ps = 1 0 5 0 -> Reset terminfo/termcap function-key mode. - * Ps = 1 0 5 1 -> Reset Sun function-key mode. - * Ps = 1 0 5 2 -> Reset HP function-key mode. - * Ps = 1 0 5 3 -> Reset SCO function-key mode. - * Ps = 1 0 6 0 -> Reset legacy keyboard emulation (X11R6). - * Ps = 1 0 6 1 -> Reset keyboard emulation to Sun/PC style. - * Ps = 2 0 0 4 -> Reset bracketed paste mode. - * - * @vt: #P[See below for supported modes.] CSI DECRST "DEC Private Reset Mode" "CSI ? Pm l" "Reset various terminal attributes." - * Supported param values by DECRST: - * - * | param | Action | Support | - * | ----- | ------------------------------------------------------- | ------- | - * | 1 | Normal Cursor Keys (DECCKM). | #Y | - * | 2 | Designate VT52 mode (DECANM). | #N | - * | 3 | 80 Column Mode (DECCOLM). | #B[Switches to old column width instead of 80.] | - * | 6 | Normal Cursor Mode (DECOM). | #Y | - * | 7 | No Wraparound Mode (DECAWM). | #Y | - * | 8 | No Auto-repeat Keys (DECARM). | #N | - * | 9 | Don't send Mouse X & Y on button press. | #Y | - * | 12 | Stop Blinking Cursor. | #Y | - * | 25 | Hide Cursor (DECTCEM). | #Y | - * | 45 | No reverse wrap-around. | #Y | - * | 47 | Use Normal Screen Buffer. | #Y | - * | 66 | Numeric keypad (DECNKM). | #Y | - * | 1000 | Don't send Mouse reports. | #Y | - * | 1002 | Don't use Cell Motion Mouse Tracking. | #Y | - * | 1003 | Don't use All Motion Mouse Tracking. | #Y | - * | 1004 | Don't send FocusIn/FocusOut events. | #Y | - * | 1005 | Disable UTF-8 Mouse Mode. | #N | - * | 1006 | Disable SGR Mouse Mode. | #Y | - * | 1015 | Disable urxvt Mouse Mode. | #N | - * | 1047 | Use Normal Screen Buffer (clearing screen if in alt). | #Y | - * | 1048 | Restore cursor as in DECRC. | #Y | - * | 1049 | Use Normal Screen Buffer and restore cursor. | #Y | - * | 2004 | Reset bracketed paste mode. | #Y | - * - * - * FIXME: DECCOLM is currently broken (already fixed in window options PR) - */ - public resetModePrivate(params: IParams): boolean { - for (let i = 0; i < params.length; i++) { - switch (params.params[i]) { - case 1: - this._coreService.decPrivateModes.applicationCursorKeys = false; - break; - case 3: - /** - * DECCOLM - 80 column mode. - * This is only active if 'SetWinLines' (24) is enabled - * through `options.windowsOptions`. - */ - if (this._optionsService.rawOptions.windowOptions.setWinLines) { - this._bufferService.resize(80, this._bufferService.rows); - this._onRequestReset.fire(); - } - break; - case 6: - this._coreService.decPrivateModes.origin = false; - this._setCursor(0, 0); - break; - case 7: - this._coreService.decPrivateModes.wraparound = false; - break; - case 12: - // this.cursorBlink = false; - break; - case 45: - this._coreService.decPrivateModes.reverseWraparound = false; - break; - case 66: - this._logService.debug('Switching back to normal keypad.'); - this._coreService.decPrivateModes.applicationKeypad = false; - this._onRequestSyncScrollBar.fire(); - break; - case 9: // X10 Mouse - case 1000: // vt200 mouse - case 1002: // button event mouse - case 1003: // any event mouse - this._coreMouseService.activeProtocol = 'NONE'; - break; - case 1004: // send focusin/focusout events - this._coreService.decPrivateModes.sendFocus = false; - break; - case 1005: // utf8 ext mode mouse - removed in #2507 - this._logService.debug('DECRST 1005 not supported (see #2507)'); - break; - case 1006: // sgr ext mode mouse - this._coreMouseService.activeEncoding = 'DEFAULT'; - break; - case 1015: // urxvt ext mode mouse - removed in #2507 - this._logService.debug('DECRST 1015 not supported (see #2507)'); - break; - case 25: // hide cursor - this._coreService.isCursorHidden = true; - break; - case 1048: // alt screen cursor - this.restoreCursor(); - break; - case 1049: // alt screen buffer cursor - // FALL-THROUGH - case 47: // normal screen buffer - case 1047: // normal screen buffer - clearing it first - // Ensure the selection manager has the correct buffer - this._bufferService.buffers.activateNormalBuffer(); - if (params.params[i] === 1049) { - this.restoreCursor(); - } - this._coreService.isCursorInitialized = true; - this._onRequestRefreshRows.fire(0, this._bufferService.rows - 1); - this._onRequestSyncScrollBar.fire(); - break; - case 2004: // bracketed paste mode (https://cirw.in/blog/bracketed-paste) - this._coreService.decPrivateModes.bracketedPasteMode = false; - break; - } - } - return true; - } - - /** - * Helper to write color information packed with color mode. - */ - private _updateAttrColor(color: number, mode: number, c1: number, c2: number, c3: number): number { - if (mode === 2) { - color |= Attributes.CM_RGB; - color &= ~Attributes.RGB_MASK; - color |= AttributeData.fromColorRGB([c1, c2, c3]); - } else if (mode === 5) { - color &= ~(Attributes.CM_MASK | Attributes.PCOLOR_MASK); - color |= Attributes.CM_P256 | (c1 & 0xff); - } - return color; - } - - /** - * Helper to extract and apply color params/subparams. - * Returns advance for params index. - */ - private _extractColor(params: IParams, pos: number, attr: IAttributeData): number { - // normalize params - // meaning: [target, CM, ign, val, val, val] - // RGB : [ 38/48, 2, ign, r, g, b] - // P256 : [ 38/48, 5, ign, v, ign, ign] - const accu = [0, 0, -1, 0, 0, 0]; - - // alignment placeholder for non color space sequences - let cSpace = 0; - - // return advance we took in params - let advance = 0; - - do { - accu[advance + cSpace] = params.params[pos + advance]; - if (params.hasSubParams(pos + advance)) { - const subparams = params.getSubParams(pos + advance)!; - let i = 0; - do { - if (accu[1] === 5) { - cSpace = 1; - } - accu[advance + i + 1 + cSpace] = subparams[i]; - } while (++i < subparams.length && i + advance + 1 + cSpace < accu.length); - break; - } - // exit early if can decide color mode with semicolons - if ((accu[1] === 5 && advance + cSpace >= 2) - || (accu[1] === 2 && advance + cSpace >= 5)) { - break; - } - // offset colorSpace slot for semicolon mode - if (accu[1]) { - cSpace = 1; - } - } while (++advance + pos < params.length && advance + cSpace < accu.length); - - // set default values to 0 - for (let i = 2; i < accu.length; ++i) { - if (accu[i] === -1) { - accu[i] = 0; - } - } - - // apply colors - switch (accu[0]) { - case 38: - attr.fg = this._updateAttrColor(attr.fg, accu[1], accu[3], accu[4], accu[5]); - break; - case 48: - attr.bg = this._updateAttrColor(attr.bg, accu[1], accu[3], accu[4], accu[5]); - break; - case 58: - attr.extended = attr.extended.clone(); - attr.extended.underlineColor = this._updateAttrColor(attr.extended.underlineColor, accu[1], accu[3], accu[4], accu[5]); - } - - return advance; - } - - /** - * SGR 4 subparams: - * 4:0 - equal to SGR 24 (turn off all underline) - * 4:1 - equal to SGR 4 (single underline) - * 4:2 - equal to SGR 21 (double underline) - * 4:3 - curly underline - * 4:4 - dotted underline - * 4:5 - dashed underline - */ - private _processUnderline(style: number, attr: IAttributeData): void { - // treat extended attrs as immutable, thus always clone from old one - // this is needed since the buffer only holds references to it - attr.extended = attr.extended.clone(); - - // default to 1 == single underline - if (!~style || style > 5) { - style = 1; - } - attr.extended.underlineStyle = style; - attr.fg |= FgFlags.UNDERLINE; - - // 0 deactivates underline - if (style === 0) { - attr.fg &= ~FgFlags.UNDERLINE; - } - - // update HAS_EXTENDED in BG - attr.updateExtended(); - } - - /** - * CSI Pm m Character Attributes (SGR). - * - * @vt: #P[See below for supported attributes.] CSI SGR "Select Graphic Rendition" "CSI Pm m" "Set/Reset various text attributes." - * SGR selects one or more character attributes at the same time. Multiple params (up to 32) - * are applied in order from left to right. The changed attributes are applied to all new - * characters received. If you move characters in the viewport by scrolling or any other means, - * then the attributes move with the characters. - * - * Supported param values by SGR: - * - * | Param | Meaning | Support | - * | --------- | -------------------------------------------------------- | ------- | - * | 0 | Normal (default). Resets any other preceding SGR. | #Y | - * | 1 | Bold. (also see `options.drawBoldTextInBrightColors`) | #Y | - * | 2 | Faint, decreased intensity. | #Y | - * | 3 | Italic. | #Y | - * | 4 | Underlined (see below for style support). | #Y | - * | 5 | Slowly blinking. | #N | - * | 6 | Rapidly blinking. | #N | - * | 7 | Inverse. Flips foreground and background color. | #Y | - * | 8 | Invisible (hidden). | #Y | - * | 9 | Crossed-out characters (strikethrough). | #Y | - * | 21 | Doubly underlined. | #P[Currently outputs a single underline.] | - * | 22 | Normal (neither bold nor faint). | #Y | - * | 23 | No italic. | #Y | - * | 24 | Not underlined. | #Y | - * | 25 | Steady (not blinking). | #Y | - * | 27 | Positive (not inverse). | #Y | - * | 28 | Visible (not hidden). | #Y | - * | 29 | Not Crossed-out (strikethrough). | #Y | - * | 30 | Foreground color: Black. | #Y | - * | 31 | Foreground color: Red. | #Y | - * | 32 | Foreground color: Green. | #Y | - * | 33 | Foreground color: Yellow. | #Y | - * | 34 | Foreground color: Blue. | #Y | - * | 35 | Foreground color: Magenta. | #Y | - * | 36 | Foreground color: Cyan. | #Y | - * | 37 | Foreground color: White. | #Y | - * | 38 | Foreground color: Extended color. | #P[Support for RGB and indexed colors, see below.] | - * | 39 | Foreground color: Default (original). | #Y | - * | 40 | Background color: Black. | #Y | - * | 41 | Background color: Red. | #Y | - * | 42 | Background color: Green. | #Y | - * | 43 | Background color: Yellow. | #Y | - * | 44 | Background color: Blue. | #Y | - * | 45 | Background color: Magenta. | #Y | - * | 46 | Background color: Cyan. | #Y | - * | 47 | Background color: White. | #Y | - * | 48 | Background color: Extended color. | #P[Support for RGB and indexed colors, see below.] | - * | 49 | Background color: Default (original). | #Y | - * | 90 - 97 | Bright foreground color (analogous to 30 - 37). | #Y | - * | 100 - 107 | Bright background color (analogous to 40 - 47). | #Y | - * - * Underline supports subparams to denote the style in the form `4 : x`: - * - * | x | Meaning | Support | - * | ------ | ------------------------------------------------------------- | ------- | - * | 0 | No underline. Same as `SGR 24 m`. | #Y | - * | 1 | Single underline. Same as `SGR 4 m`. | #Y | - * | 2 | Double underline. | #P[Currently outputs a single underline.] | - * | 3 | Curly underline. | #P[Currently outputs a single underline.] | - * | 4 | Dotted underline. | #P[Currently outputs a single underline.] | - * | 5 | Dashed underline. | #P[Currently outputs a single underline.] | - * | other | Single underline. Same as `SGR 4 m`. | #Y | - * - * Extended colors are supported for foreground (Ps=38) and background (Ps=48) as follows: - * - * | Ps + 1 | Meaning | Support | - * | ------ | ------------------------------------------------------------- | ------- | - * | 0 | Implementation defined. | #N | - * | 1 | Transparent. | #N | - * | 2 | RGB color as `Ps ; 2 ; R ; G ; B` or `Ps : 2 : : R : G : B`. | #Y | - * | 3 | CMY color. | #N | - * | 4 | CMYK color. | #N | - * | 5 | Indexed (256 colors) as `Ps ; 5 ; INDEX` or `Ps : 5 : INDEX`. | #Y | - * - * - * FIXME: blinking is implemented in attrs, but not working in renderers? - * FIXME: remove dead branch for p=100 - */ - public charAttributes(params: IParams): boolean { - // Optimize a single SGR0. - if (params.length === 1 && params.params[0] === 0) { - this._curAttrData.fg = DEFAULT_ATTR_DATA.fg; - this._curAttrData.bg = DEFAULT_ATTR_DATA.bg; - return true; - } - - const l = params.length; - let p; - const attr = this._curAttrData; - - for (let i = 0; i < l; i++) { - p = params.params[i]; - if (p >= 30 && p <= 37) { - // fg color 8 - attr.fg &= ~(Attributes.CM_MASK | Attributes.PCOLOR_MASK); - attr.fg |= Attributes.CM_P16 | (p - 30); - } else if (p >= 40 && p <= 47) { - // bg color 8 - attr.bg &= ~(Attributes.CM_MASK | Attributes.PCOLOR_MASK); - attr.bg |= Attributes.CM_P16 | (p - 40); - } else if (p >= 90 && p <= 97) { - // fg color 16 - attr.fg &= ~(Attributes.CM_MASK | Attributes.PCOLOR_MASK); - attr.fg |= Attributes.CM_P16 | (p - 90) | 8; - } else if (p >= 100 && p <= 107) { - // bg color 16 - attr.bg &= ~(Attributes.CM_MASK | Attributes.PCOLOR_MASK); - attr.bg |= Attributes.CM_P16 | (p - 100) | 8; - } else if (p === 0) { - // default - attr.fg = DEFAULT_ATTR_DATA.fg; - attr.bg = DEFAULT_ATTR_DATA.bg; - } else if (p === 1) { - // bold text - attr.fg |= FgFlags.BOLD; - } else if (p === 3) { - // italic text - attr.bg |= BgFlags.ITALIC; - } else if (p === 4) { - // underlined text - attr.fg |= FgFlags.UNDERLINE; - this._processUnderline(params.hasSubParams(i) ? params.getSubParams(i)![0] : UnderlineStyle.SINGLE, attr); - } else if (p === 5) { - // blink - attr.fg |= FgFlags.BLINK; - } else if (p === 7) { - // inverse and positive - // test with: echo -e '\e[31m\e[42mhello\e[7mworld\e[27mhi\e[m' - attr.fg |= FgFlags.INVERSE; - } else if (p === 8) { - // invisible - attr.fg |= FgFlags.INVISIBLE; - } else if (p === 9) { - // strikethrough - attr.fg |= FgFlags.STRIKETHROUGH; - } else if (p === 2) { - // dimmed text - attr.bg |= BgFlags.DIM; - } else if (p === 21) { - // double underline - this._processUnderline(UnderlineStyle.DOUBLE, attr); - } else if (p === 22) { - // not bold nor faint - attr.fg &= ~FgFlags.BOLD; - attr.bg &= ~BgFlags.DIM; - } else if (p === 23) { - // not italic - attr.bg &= ~BgFlags.ITALIC; - } else if (p === 24) { - // not underlined - attr.fg &= ~FgFlags.UNDERLINE; - } else if (p === 25) { - // not blink - attr.fg &= ~FgFlags.BLINK; - } else if (p === 27) { - // not inverse - attr.fg &= ~FgFlags.INVERSE; - } else if (p === 28) { - // not invisible - attr.fg &= ~FgFlags.INVISIBLE; - } else if (p === 29) { - // not strikethrough - attr.fg &= ~FgFlags.STRIKETHROUGH; - } else if (p === 39) { - // reset fg - attr.fg &= ~(Attributes.CM_MASK | Attributes.RGB_MASK); - attr.fg |= DEFAULT_ATTR_DATA.fg & (Attributes.PCOLOR_MASK | Attributes.RGB_MASK); - } else if (p === 49) { - // reset bg - attr.bg &= ~(Attributes.CM_MASK | Attributes.RGB_MASK); - attr.bg |= DEFAULT_ATTR_DATA.bg & (Attributes.PCOLOR_MASK | Attributes.RGB_MASK); - } else if (p === 38 || p === 48 || p === 58) { - // fg color 256 and RGB - i += this._extractColor(params, i, attr); - } else if (p === 59) { - attr.extended = attr.extended.clone(); - attr.extended.underlineColor = -1; - attr.updateExtended(); - } else if (p === 100) { // FIXME: dead branch, p=100 already handled above! - // reset fg/bg - attr.fg &= ~(Attributes.CM_MASK | Attributes.RGB_MASK); - attr.fg |= DEFAULT_ATTR_DATA.fg & (Attributes.PCOLOR_MASK | Attributes.RGB_MASK); - attr.bg &= ~(Attributes.CM_MASK | Attributes.RGB_MASK); - attr.bg |= DEFAULT_ATTR_DATA.bg & (Attributes.PCOLOR_MASK | Attributes.RGB_MASK); - } else { - this._logService.debug('Unknown SGR attribute: %d.', p); - } - } - return true; - } - - /** - * CSI Ps n Device Status Report (DSR). - * Ps = 5 -> Status Report. Result (``OK'') is - * CSI 0 n - * Ps = 6 -> Report Cursor Position (CPR) [row;column]. - * Result is - * CSI r ; c R - * CSI ? Ps n - * Device Status Report (DSR, DEC-specific). - * Ps = 6 -> Report Cursor Position (CPR) [row;column] as CSI - * ? r ; c R (assumes page is zero). - * Ps = 1 5 -> Report Printer status as CSI ? 1 0 n (ready). - * or CSI ? 1 1 n (not ready). - * Ps = 2 5 -> Report UDK status as CSI ? 2 0 n (unlocked) - * or CSI ? 2 1 n (locked). - * Ps = 2 6 -> Report Keyboard status as - * CSI ? 2 7 ; 1 ; 0 ; 0 n (North American). - * The last two parameters apply to VT400 & up, and denote key- - * board ready and LK01 respectively. - * Ps = 5 3 -> Report Locator status as - * CSI ? 5 3 n Locator available, if compiled-in, or - * CSI ? 5 0 n No Locator, if not. - * - * @vt: #Y CSI DSR "Device Status Report" "CSI Ps n" "Request cursor position (CPR) with `Ps` = 6." - */ - public deviceStatus(params: IParams): boolean { - switch (params.params[0]) { - case 5: - // status report - this._coreService.triggerDataEvent(`${C0.ESC}[0n`); - break; - case 6: - // cursor position - const y = this._activeBuffer.y + 1; - const x = this._activeBuffer.x + 1; - this._coreService.triggerDataEvent(`${C0.ESC}[${y};${x}R`); - break; - } - return true; - } - - // @vt: #P[Only CPR is supported.] CSI DECDSR "DEC Device Status Report" "CSI ? Ps n" "Only CPR is supported (same as DSR)." - public deviceStatusPrivate(params: IParams): boolean { - // modern xterm doesnt seem to - // respond to any of these except ?6, 6, and 5 - switch (params.params[0]) { - case 6: - // cursor position - const y = this._activeBuffer.y + 1; - const x = this._activeBuffer.x + 1; - this._coreService.triggerDataEvent(`${C0.ESC}[?${y};${x}R`); - break; - case 15: - // no printer - // this.handler(C0.ESC + '[?11n'); - break; - case 25: - // dont support user defined keys - // this.handler(C0.ESC + '[?21n'); - break; - case 26: - // north american keyboard - // this.handler(C0.ESC + '[?27;1;0;0n'); - break; - case 53: - // no dec locator/mouse - // this.handler(C0.ESC + '[?50n'); - break; - } - return true; - } - - /** - * CSI ! p Soft terminal reset (DECSTR). - * http://vt100.net/docs/vt220-rm/table4-10.html - * - * @vt: #Y CSI DECSTR "Soft Terminal Reset" "CSI ! p" "Reset several terminal attributes to initial state." - * There are two terminal reset sequences - RIS and DECSTR. While RIS performs almost a full terminal bootstrap, - * DECSTR only resets certain attributes. For most needs DECSTR should be sufficient. - * - * The following terminal attributes are reset to default values: - * - IRM is reset (dafault = false) - * - scroll margins are reset (default = viewport size) - * - erase attributes are reset to default - * - charsets are reset - * - DECSC data is reset to initial values - * - DECOM is reset to absolute mode - * - * - * FIXME: there are several more attributes missing (see VT520 manual) - */ - public softReset(params: IParams): boolean { - this._coreService.isCursorHidden = false; - this._onRequestSyncScrollBar.fire(); - this._activeBuffer.scrollTop = 0; - this._activeBuffer.scrollBottom = this._bufferService.rows - 1; - this._curAttrData = DEFAULT_ATTR_DATA.clone(); - this._coreService.reset(); - this._charsetService.reset(); - - // reset DECSC data - this._activeBuffer.savedX = 0; - this._activeBuffer.savedY = this._activeBuffer.ybase; - this._activeBuffer.savedCurAttrData.fg = this._curAttrData.fg; - this._activeBuffer.savedCurAttrData.bg = this._curAttrData.bg; - this._activeBuffer.savedCharset = this._charsetService.charset; - - // reset DECOM - this._coreService.decPrivateModes.origin = false; - return true; - } - - /** - * CSI Ps SP q Set cursor style (DECSCUSR, VT520). - * Ps = 0 -> blinking block. - * Ps = 1 -> blinking block (default). - * Ps = 2 -> steady block. - * Ps = 3 -> blinking underline. - * Ps = 4 -> steady underline. - * Ps = 5 -> blinking bar (xterm). - * Ps = 6 -> steady bar (xterm). - * - * @vt: #Y CSI DECSCUSR "Set Cursor Style" "CSI Ps SP q" "Set cursor style." - * Supported cursor styles: - * - empty, 0 or 1: steady block - * - 2: blink block - * - 3: steady underline - * - 4: blink underline - * - 5: steady bar - * - 6: blink bar - */ - public setCursorStyle(params: IParams): boolean { - const param = params.params[0] || 1; - switch (param) { - case 1: - case 2: - this._optionsService.options.cursorStyle = 'block'; - break; - case 3: - case 4: - this._optionsService.options.cursorStyle = 'underline'; - break; - case 5: - case 6: - this._optionsService.options.cursorStyle = 'bar'; - break; - } - const isBlinking = param % 2 === 1; - this._optionsService.options.cursorBlink = isBlinking; - return true; - } - - /** - * CSI Ps ; Ps r - * Set Scrolling Region [top;bottom] (default = full size of win- - * dow) (DECSTBM). - * - * @vt: #Y CSI DECSTBM "Set Top and Bottom Margin" "CSI Ps ; Ps r" "Set top and bottom margins of the viewport [top;bottom] (default = viewport size)." - */ - public setScrollRegion(params: IParams): boolean { - const top = params.params[0] || 1; - let bottom: number; - - if (params.length < 2 || (bottom = params.params[1]) > this._bufferService.rows || bottom === 0) { - bottom = this._bufferService.rows; - } - - if (bottom > top) { - this._activeBuffer.scrollTop = top - 1; - this._activeBuffer.scrollBottom = bottom - 1; - this._setCursor(0, 0); - } - return true; - } - - /** - * CSI Ps ; Ps ; Ps t - Various window manipulations and reports (xterm) - * - * Note: Only those listed below are supported. All others are left to integrators and - * need special treatment based on the embedding environment. - * - * Ps = 1 4 supported - * Report xterm text area size in pixels. - * Result is CSI 4 ; height ; width t - * Ps = 14 ; 2 not implemented - * Ps = 16 supported - * Report xterm character cell size in pixels. - * Result is CSI 6 ; height ; width t - * Ps = 18 supported - * Report the size of the text area in characters. - * Result is CSI 8 ; height ; width t - * Ps = 20 supported - * Report xterm window's icon label. - * Result is OSC L label ST - * Ps = 21 supported - * Report xterm window's title. - * Result is OSC l label ST - * Ps = 22 ; 0 -> Save xterm icon and window title on stack. supported - * Ps = 22 ; 1 -> Save xterm icon title on stack. supported - * Ps = 22 ; 2 -> Save xterm window title on stack. supported - * Ps = 23 ; 0 -> Restore xterm icon and window title from stack. supported - * Ps = 23 ; 1 -> Restore xterm icon title from stack. supported - * Ps = 23 ; 2 -> Restore xterm window title from stack. supported - * Ps >= 24 not implemented - */ - public windowOptions(params: IParams): boolean { - if (!paramToWindowOption(params.params[0], this._optionsService.rawOptions.windowOptions)) { - return true; - } - const second = (params.length > 1) ? params.params[1] : 0; - switch (params.params[0]) { - case 14: // GetWinSizePixels, returns CSI 4 ; height ; width t - if (second !== 2) { - this._onRequestWindowsOptionsReport.fire(WindowsOptionsReportType.GET_WIN_SIZE_PIXELS); - } - break; - case 16: // GetCellSizePixels, returns CSI 6 ; height ; width t - this._onRequestWindowsOptionsReport.fire(WindowsOptionsReportType.GET_CELL_SIZE_PIXELS); - break; - case 18: // GetWinSizeChars, returns CSI 8 ; height ; width t - if (this._bufferService) { - this._coreService.triggerDataEvent(`${C0.ESC}[8;${this._bufferService.rows};${this._bufferService.cols}t`); - } - break; - case 22: // PushTitle - if (second === 0 || second === 2) { - this._windowTitleStack.push(this._windowTitle); - if (this._windowTitleStack.length > STACK_LIMIT) { - this._windowTitleStack.shift(); - } - } - if (second === 0 || second === 1) { - this._iconNameStack.push(this._iconName); - if (this._iconNameStack.length > STACK_LIMIT) { - this._iconNameStack.shift(); - } - } - break; - case 23: // PopTitle - if (second === 0 || second === 2) { - if (this._windowTitleStack.length) { - this.setTitle(this._windowTitleStack.pop()!); - } - } - if (second === 0 || second === 1) { - if (this._iconNameStack.length) { - this.setIconName(this._iconNameStack.pop()!); - } - } - break; - } - return true; - } - - - /** - * CSI s - * ESC 7 - * Save cursor (ANSI.SYS). - * - * @vt: #P[TODO...] CSI SCOSC "Save Cursor" "CSI s" "Save cursor position, charmap and text attributes." - * @vt: #Y ESC SC "Save Cursor" "ESC 7" "Save cursor position, charmap and text attributes." - */ - public saveCursor(params?: IParams): boolean { - this._activeBuffer.savedX = this._activeBuffer.x; - this._activeBuffer.savedY = this._activeBuffer.ybase + this._activeBuffer.y; - this._activeBuffer.savedCurAttrData.fg = this._curAttrData.fg; - this._activeBuffer.savedCurAttrData.bg = this._curAttrData.bg; - this._activeBuffer.savedCharset = this._charsetService.charset; - return true; - } - - - /** - * CSI u - * ESC 8 - * Restore cursor (ANSI.SYS). - * - * @vt: #P[TODO...] CSI SCORC "Restore Cursor" "CSI u" "Restore cursor position, charmap and text attributes." - * @vt: #Y ESC RC "Restore Cursor" "ESC 8" "Restore cursor position, charmap and text attributes." - */ - public restoreCursor(params?: IParams): boolean { - this._activeBuffer.x = this._activeBuffer.savedX || 0; - this._activeBuffer.y = Math.max(this._activeBuffer.savedY - this._activeBuffer.ybase, 0); - this._curAttrData.fg = this._activeBuffer.savedCurAttrData.fg; - this._curAttrData.bg = this._activeBuffer.savedCurAttrData.bg; - this._charsetService.charset = (this as any)._savedCharset; - if (this._activeBuffer.savedCharset) { - this._charsetService.charset = this._activeBuffer.savedCharset; - } - this._restrictCursor(); - return true; - } - - - /** - * OSC 2; <data> ST (set window title) - * Proxy to set window title. - * - * @vt: #P[Icon name is not exposed.] OSC 0 "Set Windows Title and Icon Name" "OSC 0 ; Pt BEL" "Set window title and icon name." - * Icon name is not supported. For Window Title see below. - * - * @vt: #Y OSC 2 "Set Windows Title" "OSC 2 ; Pt BEL" "Set window title." - * xterm.js does not manipulate the title directly, instead exposes changes via the event `Terminal.onTitleChange`. - */ - public setTitle(data: string): boolean { - this._windowTitle = data; - this._onTitleChange.fire(data); - return true; - } - - /** - * OSC 1; <data> ST - * Note: Icon name is not exposed. - */ - public setIconName(data: string): boolean { - this._iconName = data; - return true; - } - - /** - * OSC 4; <num> ; <text> ST (set ANSI color <num> to <text>) - * - * @vt: #Y OSC 4 "Set ANSI color" "OSC 4 ; c ; spec BEL" "Change color number `c` to the color specified by `spec`." - * `c` is the color index between 0 and 255. The color format of `spec` is derived from `XParseColor` (see OSC 10 for supported formats). - * There may be multipe `c ; spec` pairs present in the same instruction. - * If `spec` contains `?` the terminal returns a sequence with the currently set color. - */ - public setOrReportIndexedColor(data: string): boolean { - const event: IColorEvent = []; - const slots = data.split(';'); - while (slots.length > 1) { - const idx = slots.shift() as string; - const spec = slots.shift() as string; - if (/^\d+$/.exec(idx)) { - const index = parseInt(idx); - if (0 <= index && index < 256) { - if (spec === '?') { - event.push({ type: ColorRequestType.REPORT, index }); - } else { - const color = parseColor(spec); - if (color) { - event.push({ type: ColorRequestType.SET, index, color }); - } - } - } - } - } - if (event.length) { - this._onColor.fire(event); - } - return true; - } - - // special colors - OSC 10 | 11 | 12 - private _specialColors = [ColorIndex.FOREGROUND, ColorIndex.BACKGROUND, ColorIndex.CURSOR]; - - /** - * Apply colors requests for special colors in OSC 10 | 11 | 12. - * Since these commands are stacking from multiple parameters, - * we handle them in a loop with an entry offset to `_specialColors`. - */ - private _setOrReportSpecialColor(data: string, offset: number): boolean { - const slots = data.split(';'); - for (let i = 0; i < slots.length; ++i, ++offset) { - if (offset >= this._specialColors.length) break; - if (slots[i] === '?') { - this._onColor.fire([{ type: ColorRequestType.REPORT, index: this._specialColors[offset] }]); - } else { - const color = parseColor(slots[i]); - if (color) { - this._onColor.fire([{ type: ColorRequestType.SET, index: this._specialColors[offset], color }]); - } - } - } - return true; - } - - /** - * OSC 10 ; <xcolor name>|<?> ST - set or query default foreground color - * - * @vt: #Y OSC 10 "Set or query default foreground color" "OSC 10 ; Pt BEL" "Set or query default foreground color." - * To set the color, the following color specification formats are supported: - * - `rgb:<red>/<green>/<blue>` for `<red>, <green>, <blue>` in `h | hh | hhh | hhhh`, where - * `h` is a single hexadecimal digit (case insignificant). The different widths scale - * from 4 bit (`h`) to 16 bit (`hhhh`) and get converted to 8 bit (`hh`). - * - `#RGB` - 4 bits per channel, expanded to `#R0G0B0` - * - `#RRGGBB` - 8 bits per channel - * - `#RRRGGGBBB` - 12 bits per channel, truncated to `#RRGGBB` - * - `#RRRRGGGGBBBB` - 16 bits per channel, truncated to `#RRGGBB` - * - * **Note:** X11 named colors are currently unsupported. - * - * If `Pt` contains `?` instead of a color specification, the terminal - * returns a sequence with the current default foreground color - * (use that sequence to restore the color after changes). - * - * **Note:** Other than xterm, xterm.js does not support OSC 12 - 19. - * Therefore stacking multiple `Pt` separated by `;` only works for the first two entries. - */ - public setOrReportFgColor(data: string): boolean { - return this._setOrReportSpecialColor(data, 0); - } - - /** - * OSC 11 ; <xcolor name>|<?> ST - set or query default background color - * - * @vt: #Y OSC 11 "Set or query default background color" "OSC 11 ; Pt BEL" "Same as OSC 10, but for default background." - */ - public setOrReportBgColor(data: string): boolean { - return this._setOrReportSpecialColor(data, 1); - } - - /** - * OSC 12 ; <xcolor name>|<?> ST - set or query default cursor color - * - * @vt: #Y OSC 12 "Set or query default cursor color" "OSC 12 ; Pt BEL" "Same as OSC 10, but for default cursor color." - */ - public setOrReportCursorColor(data: string): boolean { - return this._setOrReportSpecialColor(data, 2); - } - - /** - * OSC 104 ; <num> ST - restore ANSI color <num> - * - * @vt: #Y OSC 104 "Reset ANSI color" "OSC 104 ; c BEL" "Reset color number `c` to themed color." - * `c` is the color index between 0 and 255. This function restores the default color for `c` as - * specified by the loaded theme. Any number of `c` parameters may be given. - * If no parameters are given, the entire indexed color table will be reset. - */ - public restoreIndexedColor(data: string): boolean { - if (!data) { - this._onColor.fire([{ type: ColorRequestType.RESTORE }]); - return true; - } - const event: IColorEvent = []; - const slots = data.split(';'); - for (let i = 0; i < slots.length; ++i) { - if (/^\d+$/.exec(slots[i])) { - const index = parseInt(slots[i]); - if (0 <= index && index < 256) { - event.push({ type: ColorRequestType.RESTORE, index }); - } - } - } - if (event.length) { - this._onColor.fire(event); - } - return true; - } - - /** - * OSC 110 ST - restore default foreground color - * - * @vt: #Y OSC 110 "Restore default foreground color" "OSC 110 BEL" "Restore default foreground to themed color." - */ - public restoreFgColor(data: string): boolean { - this._onColor.fire([{ type: ColorRequestType.RESTORE, index: ColorIndex.FOREGROUND }]); - return true; - } - - /** - * OSC 111 ST - restore default background color - * - * @vt: #Y OSC 111 "Restore default background color" "OSC 111 BEL" "Restore default background to themed color." - */ - public restoreBgColor(data: string): boolean { - this._onColor.fire([{ type: ColorRequestType.RESTORE, index: ColorIndex.BACKGROUND }]); - return true; - } - - /** - * OSC 112 ST - restore default cursor color - * - * @vt: #Y OSC 112 "Restore default cursor color" "OSC 112 BEL" "Restore default cursor to themed color." - */ - public restoreCursorColor(data: string): boolean { - this._onColor.fire([{ type: ColorRequestType.RESTORE, index: ColorIndex.CURSOR }]); - return true; - } - - /** - * ESC E - * C1.NEL - * DEC mnemonic: NEL (https://vt100.net/docs/vt510-rm/NEL) - * Moves cursor to first position on next line. - * - * @vt: #Y C1 NEL "Next Line" "\x85" "Move the cursor to the beginning of the next row." - * @vt: #Y ESC NEL "Next Line" "ESC E" "Move the cursor to the beginning of the next row." - */ - public nextLine(): boolean { - this._activeBuffer.x = 0; - this.index(); - return true; - } - - /** - * ESC = - * DEC mnemonic: DECKPAM (https://vt100.net/docs/vt510-rm/DECKPAM.html) - * Enables the numeric keypad to send application sequences to the host. - */ - public keypadApplicationMode(): boolean { - this._logService.debug('Serial port requested application keypad.'); - this._coreService.decPrivateModes.applicationKeypad = true; - this._onRequestSyncScrollBar.fire(); - return true; - } - - /** - * ESC > - * DEC mnemonic: DECKPNM (https://vt100.net/docs/vt510-rm/DECKPNM.html) - * Enables the keypad to send numeric characters to the host. - */ - public keypadNumericMode(): boolean { - this._logService.debug('Switching back to normal keypad.'); - this._coreService.decPrivateModes.applicationKeypad = false; - this._onRequestSyncScrollBar.fire(); - return true; - } - - /** - * ESC % @ - * ESC % G - * Select default character set. UTF-8 is not supported (string are unicode anyways) - * therefore ESC % G does the same. - */ - public selectDefaultCharset(): boolean { - this._charsetService.setgLevel(0); - this._charsetService.setgCharset(0, DEFAULT_CHARSET); // US (default) - return true; - } - - /** - * ESC ( C - * Designate G0 Character Set, VT100, ISO 2022. - * ESC ) C - * Designate G1 Character Set (ISO 2022, VT100). - * ESC * C - * Designate G2 Character Set (ISO 2022, VT220). - * ESC + C - * Designate G3 Character Set (ISO 2022, VT220). - * ESC - C - * Designate G1 Character Set (VT300). - * ESC . C - * Designate G2 Character Set (VT300). - * ESC / C - * Designate G3 Character Set (VT300). C = A -> ISO Latin-1 Supplemental. - Supported? - */ - public selectCharset(collectAndFlag: string): boolean { - if (collectAndFlag.length !== 2) { - this.selectDefaultCharset(); - return true; - } - if (collectAndFlag[0] === '/') { - return true; // TODO: Is this supported? - } - this._charsetService.setgCharset(GLEVEL[collectAndFlag[0]], CHARSETS[collectAndFlag[1]] || DEFAULT_CHARSET); - return true; - } - - /** - * ESC D - * C1.IND - * DEC mnemonic: IND (https://vt100.net/docs/vt510-rm/IND.html) - * Moves the cursor down one line in the same column. - * - * @vt: #Y C1 IND "Index" "\x84" "Move the cursor one line down scrolling if needed." - * @vt: #Y ESC IND "Index" "ESC D" "Move the cursor one line down scrolling if needed." - */ - public index(): boolean { - this._restrictCursor(); - this._activeBuffer.y++; - if (this._activeBuffer.y === this._activeBuffer.scrollBottom + 1) { - this._activeBuffer.y--; - this._bufferService.scroll(this._eraseAttrData()); - } else if (this._activeBuffer.y >= this._bufferService.rows) { - this._activeBuffer.y = this._bufferService.rows - 1; - } - this._restrictCursor(); - return true; - } - - /** - * ESC H - * C1.HTS - * DEC mnemonic: HTS (https://vt100.net/docs/vt510-rm/HTS.html) - * Sets a horizontal tab stop at the column position indicated by - * the value of the active column when the terminal receives an HTS. - * - * @vt: #Y C1 HTS "Horizontal Tabulation Set" "\x88" "Places a tab stop at the current cursor position." - * @vt: #Y ESC HTS "Horizontal Tabulation Set" "ESC H" "Places a tab stop at the current cursor position." - */ - public tabSet(): boolean { - this._activeBuffer.tabs[this._activeBuffer.x] = true; - return true; - } - - /** - * ESC M - * C1.RI - * DEC mnemonic: HTS - * Moves the cursor up one line in the same column. If the cursor is at the top margin, - * the page scrolls down. - * - * @vt: #Y ESC IR "Reverse Index" "ESC M" "Move the cursor one line up scrolling if needed." - */ - public reverseIndex(): boolean { - this._restrictCursor(); - if (this._activeBuffer.y === this._activeBuffer.scrollTop) { - // possibly move the code below to term.reverseScroll(); - // test: echo -ne '\e[1;1H\e[44m\eM\e[0m' - // blankLine(true) is xterm/linux behavior - const scrollRegionHeight = this._activeBuffer.scrollBottom - this._activeBuffer.scrollTop; - this._activeBuffer.lines.shiftElements(this._activeBuffer.ybase + this._activeBuffer.y, scrollRegionHeight, 1); - this._activeBuffer.lines.set(this._activeBuffer.ybase + this._activeBuffer.y, this._activeBuffer.getBlankLine(this._eraseAttrData())); - this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop, this._activeBuffer.scrollBottom); - } else { - this._activeBuffer.y--; - this._restrictCursor(); // quickfix to not run out of bounds - } - return true; - } - - /** - * ESC c - * DEC mnemonic: RIS (https://vt100.net/docs/vt510-rm/RIS.html) - * Reset to initial state. - */ - public fullReset(): boolean { - this._parser.reset(); - this._onRequestReset.fire(); - return true; - } - - public reset(): void { - this._curAttrData = DEFAULT_ATTR_DATA.clone(); - this._eraseAttrDataInternal = DEFAULT_ATTR_DATA.clone(); - } - - /** - * back_color_erase feature for xterm. - */ - private _eraseAttrData(): IAttributeData { - this._eraseAttrDataInternal.bg &= ~(Attributes.CM_MASK | 0xFFFFFF); - this._eraseAttrDataInternal.bg |= this._curAttrData.bg & ~0xFC000000; - return this._eraseAttrDataInternal; - } - - /** - * ESC n - * ESC o - * ESC | - * ESC } - * ESC ~ - * DEC mnemonic: LS (https://vt100.net/docs/vt510-rm/LS.html) - * When you use a locking shift, the character set remains in GL or GR until - * you use another locking shift. (partly supported) - */ - public setgLevel(level: number): boolean { - this._charsetService.setgLevel(level); - return true; - } - - /** - * ESC # 8 - * DEC mnemonic: DECALN (https://vt100.net/docs/vt510-rm/DECALN.html) - * This control function fills the complete screen area with - * a test pattern (E) used for adjusting screen alignment. - * - * @vt: #Y ESC DECALN "Screen Alignment Pattern" "ESC # 8" "Fill viewport with a test pattern (E)." - */ - public screenAlignmentPattern(): boolean { - // prepare cell data - const cell = new CellData(); - cell.content = 1 << Content.WIDTH_SHIFT | 'E'.charCodeAt(0); - cell.fg = this._curAttrData.fg; - cell.bg = this._curAttrData.bg; - - - this._setCursor(0, 0); - for (let yOffset = 0; yOffset < this._bufferService.rows; ++yOffset) { - const row = this._activeBuffer.ybase + this._activeBuffer.y + yOffset; - const line = this._activeBuffer.lines.get(row); - if (line) { - line.fill(cell); - line.isWrapped = false; - } - } - this._dirtyRowService.markAllDirty(); - this._setCursor(0, 0); - return true; - } -} diff --git a/node_modules/xterm/src/common/Lifecycle.ts b/node_modules/xterm/src/common/Lifecycle.ts deleted file mode 100644 index 56bcfdc..0000000 --- a/node_modules/xterm/src/common/Lifecycle.ts +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Copyright (c) 2018 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IDisposable } from 'common/Types'; - -/** - * A base class that can be extended to provide convenience methods for managing the lifecycle of an - * object and its components. - */ -export abstract class Disposable implements IDisposable { - protected _disposables: IDisposable[] = []; - protected _isDisposed: boolean = false; - - constructor() { - } - - /** - * Disposes the object, triggering the `dispose` method on all registered IDisposables. - */ - public dispose(): void { - this._isDisposed = true; - for (const d of this._disposables) { - d.dispose(); - } - this._disposables.length = 0; - } - - /** - * Registers a disposable object. - * @param d The disposable to register. - * @returns The disposable. - */ - public register<T extends IDisposable>(d: T): T { - this._disposables.push(d); - return d; - } - - /** - * Unregisters a disposable object if it has been registered, if not do - * nothing. - * @param d The disposable to unregister. - */ - public unregister<T extends IDisposable>(d: T): void { - const index = this._disposables.indexOf(d); - if (index !== -1) { - this._disposables.splice(index, 1); - } - } -} - -/** - * Dispose of all disposables in an array and set its length to 0. - */ -export function disposeArray(disposables: IDisposable[]): void { - for (const d of disposables) { - d.dispose(); - } - disposables.length = 0; -} - -/** - * Creates a disposable that will dispose of an array of disposables when disposed. - */ -export function getDisposeArrayDisposable(array: IDisposable[]): IDisposable { - return { dispose: () => disposeArray(array) }; -} diff --git a/node_modules/xterm/src/common/Platform.ts b/node_modules/xterm/src/common/Platform.ts deleted file mode 100644 index 7b823b1..0000000 --- a/node_modules/xterm/src/common/Platform.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2016 The xterm.js authors. All rights reserved. - * @license MIT - */ - -interface INavigator { - userAgent: string; - language: string; - platform: string; -} - -// We're declaring a navigator global here as we expect it in all runtimes (node and browser), but -// we want this module to live in common. -declare const navigator: INavigator; - -const isNode = (typeof navigator === 'undefined') ? true : false; -const userAgent = (isNode) ? 'node' : navigator.userAgent; -const platform = (isNode) ? 'node' : navigator.platform; - -export const isFirefox = userAgent.includes('Firefox'); -export const isLegacyEdge = userAgent.includes('Edge'); -export const isSafari = /^((?!chrome|android).)*safari/i.test(userAgent); - -// Find the users platform. We use this to interpret the meta key -// and ISO third level shifts. -// http://stackoverflow.com/q/19877924/577598 -export const isMac = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'].includes(platform); -export const isIpad = platform === 'iPad'; -export const isIphone = platform === 'iPhone'; -export const isWindows = ['Windows', 'Win16', 'Win32', 'WinCE'].includes(platform); -export const isLinux = platform.indexOf('Linux') >= 0; diff --git a/node_modules/xterm/src/common/TypedArrayUtils.ts b/node_modules/xterm/src/common/TypedArrayUtils.ts deleted file mode 100644 index 158c717..0000000 --- a/node_modules/xterm/src/common/TypedArrayUtils.ts +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (c) 2018 The xterm.js authors. All rights reserved. - * @license MIT - */ - -export type TypedArray = Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Int8Array | Int16Array | Int32Array | Float32Array | Float64Array; - - -/** - * polyfill for TypedArray.fill - * This is needed to support .fill in all safari versions and IE 11. - */ -export function fill<T extends TypedArray>(array: T, value: number, start?: number, end?: number): T { - // all modern engines that support .fill - if (array.fill) { - return array.fill(value, start, end) as T; - } - return fillFallback(array, value, start, end); -} - -export function fillFallback<T extends TypedArray>(array: T, value: number, start: number = 0, end: number = array.length): T { - // safari and IE 11 - // since IE 11 does not support Array.prototype.fill either - // we cannot use the suggested polyfill from MDN - // instead we simply fall back to looping - if (start >= array.length) { - return array; - } - start = (array.length + start) % array.length; - if (end >= array.length) { - end = array.length; - } else { - end = (array.length + end) % array.length; - } - for (let i = start; i < end; ++i) { - array[i] = value; - } - return array; -} - -/** - * Concat two typed arrays `a` and `b`. - * Returns a new typed array. - */ -export function concat<T extends TypedArray>(a: T, b: T): T { - const result = new (a.constructor as any)(a.length + b.length); - result.set(a); - result.set(b, a.length); - return result; -} diff --git a/node_modules/xterm/src/common/Types.d.ts b/node_modules/xterm/src/common/Types.d.ts deleted file mode 100644 index fee426e..0000000 --- a/node_modules/xterm/src/common/Types.d.ts +++ /dev/null @@ -1,483 +0,0 @@ -/** - * Copyright (c) 2018 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IFunctionIdentifier, ITerminalOptions as IPublicTerminalOptions } from 'xterm'; -import { IEvent, IEventEmitter } from 'common/EventEmitter'; -import { IDeleteEvent, IInsertEvent } from 'common/CircularList'; -import { IParams } from 'common/parser/Types'; -import { ICoreMouseService, ICoreService, IOptionsService, IUnicodeService } from 'common/services/Services'; -import { IBufferSet } from 'common/buffer/Types'; - -export interface ICoreTerminal { - coreMouseService: ICoreMouseService; - coreService: ICoreService; - optionsService: IOptionsService; - unicodeService: IUnicodeService; - buffers: IBufferSet; - options: ITerminalOptions; - registerCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean | Promise<boolean>): IDisposable; - registerDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean | Promise<boolean>): IDisposable; - registerEscHandler(id: IFunctionIdentifier, callback: () => boolean | Promise<boolean>): IDisposable; - registerOscHandler(ident: number, callback: (data: string) => boolean | Promise<boolean>): IDisposable; -} - -export interface IDisposable { - dispose(): void; -} - -// TODO: The options that are not in the public API should be reviewed -export interface ITerminalOptions extends IPublicTerminalOptions { - [key: string]: any; - cancelEvents?: boolean; - convertEol?: boolean; - termName?: string; -} - -export type XtermListener = (...args: any[]) => void; - -/** - * A keyboard event interface which does not depend on the DOM, KeyboardEvent implicitly extends - * this event. - */ -export interface IKeyboardEvent { - altKey: boolean; - ctrlKey: boolean; - shiftKey: boolean; - metaKey: boolean; - /** @deprecated See KeyboardEvent.keyCode */ - keyCode: number; - key: string; - type: string; -} - -export interface IScrollEvent { - position: number; - source: ScrollSource; -} - -export const enum ScrollSource { - TERMINAL, - VIEWPORT, -} - -export interface ICircularList<T> { - length: number; - maxLength: number; - isFull: boolean; - - onDeleteEmitter: IEventEmitter<IDeleteEvent>; - onDelete: IEvent<IDeleteEvent>; - onInsertEmitter: IEventEmitter<IInsertEvent>; - onInsert: IEvent<IInsertEvent>; - onTrimEmitter: IEventEmitter<number>; - onTrim: IEvent<number>; - - get(index: number): T | undefined; - set(index: number, value: T): void; - push(value: T): void; - recycle(): T; - pop(): T | undefined; - splice(start: number, deleteCount: number, ...items: T[]): void; - trimStart(count: number): void; - shiftElements(start: number, count: number, offset: number): void; -} - -export const enum KeyboardResultType { - SEND_KEY, - SELECT_ALL, - PAGE_UP, - PAGE_DOWN -} - -export interface IKeyboardResult { - type: KeyboardResultType; - cancel: boolean; - key: string | undefined; -} - -export interface ICharset { - [key: string]: string | undefined; -} - -export type CharData = [number, string, number, number]; -export type IColorRGB = [number, number, number]; - -export interface IExtendedAttrs { - underlineStyle: number; - underlineColor: number; - clone(): IExtendedAttrs; - isEmpty(): boolean; -} - -/** Attribute data */ -export interface IAttributeData { - fg: number; - bg: number; - extended: IExtendedAttrs; - - clone(): IAttributeData; - - // flags - isInverse(): number; - isBold(): number; - isUnderline(): number; - isBlink(): number; - isInvisible(): number; - isItalic(): number; - isDim(): number; - isStrikethrough(): number; - - // color modes - getFgColorMode(): number; - getBgColorMode(): number; - isFgRGB(): boolean; - isBgRGB(): boolean; - isFgPalette(): boolean; - isBgPalette(): boolean; - isFgDefault(): boolean; - isBgDefault(): boolean; - isAttributeDefault(): boolean; - - // colors - getFgColor(): number; - getBgColor(): number; - - // extended attrs - hasExtendedAttrs(): number; - updateExtended(): void; - getUnderlineColor(): number; - getUnderlineColorMode(): number; - isUnderlineColorRGB(): boolean; - isUnderlineColorPalette(): boolean; - isUnderlineColorDefault(): boolean; - getUnderlineStyle(): number; -} - -/** Cell data */ -export interface ICellData extends IAttributeData { - content: number; - combinedData: string; - isCombined(): number; - getWidth(): number; - getChars(): string; - getCode(): number; - setFromCharData(value: CharData): void; - getAsCharData(): CharData; -} - -/** - * Interface for a line in the terminal buffer. - */ -export interface IBufferLine { - length: number; - isWrapped: boolean; - get(index: number): CharData; - set(index: number, value: CharData): void; - loadCell(index: number, cell: ICellData): ICellData; - setCell(index: number, cell: ICellData): void; - setCellFromCodePoint(index: number, codePoint: number, width: number, fg: number, bg: number, eAttrs: IExtendedAttrs): void; - addCodepointToCell(index: number, codePoint: number): void; - insertCells(pos: number, n: number, ch: ICellData, eraseAttr?: IAttributeData): void; - deleteCells(pos: number, n: number, fill: ICellData, eraseAttr?: IAttributeData): void; - replaceCells(start: number, end: number, fill: ICellData, eraseAttr?: IAttributeData): void; - resize(cols: number, fill: ICellData): void; - fill(fillCellData: ICellData): void; - copyFrom(line: IBufferLine): void; - clone(): IBufferLine; - getTrimmedLength(): number; - translateToString(trimRight?: boolean, startCol?: number, endCol?: number): string; - - /* direct access to cell attrs */ - getWidth(index: number): number; - hasWidth(index: number): number; - getFg(index: number): number; - getBg(index: number): number; - hasContent(index: number): number; - getCodePoint(index: number): number; - isCombined(index: number): number; - getString(index: number): string; -} - -export interface IMarker extends IDisposable { - readonly id: number; - readonly isDisposed: boolean; - readonly line: number; - onDispose: IEvent<void>; -} -export interface IModes { - insertMode: boolean; -} - -export interface IDecPrivateModes { - applicationCursorKeys: boolean; - applicationKeypad: boolean; - bracketedPasteMode: boolean; - origin: boolean; - reverseWraparound: boolean; - sendFocus: boolean; - wraparound: boolean; // defaults: xterm - true, vt100 - false -} - -export interface IRowRange { - start: number; - end: number; -} - -/** - * Interface for mouse events in the core. - */ -export const enum CoreMouseButton { - LEFT = 0, - MIDDLE = 1, - RIGHT = 2, - NONE = 3, - WHEEL = 4, - // additional buttons 1..8 - // untested! - AUX1 = 8, - AUX2 = 9, - AUX3 = 10, - AUX4 = 11, - AUX5 = 12, - AUX6 = 13, - AUX7 = 14, - AUX8 = 15 -} - -export const enum CoreMouseAction { - UP = 0, // buttons, wheel - DOWN = 1, // buttons, wheel - LEFT = 2, // wheel only - RIGHT = 3, // wheel only - MOVE = 32 // buttons only -} - -export interface ICoreMouseEvent { - /** column (zero based). */ - col: number; - /** row (zero based). */ - row: number; - /** - * Button the action occured. Due to restrictions of the tracking protocols - * it is not possible to report multiple buttons at once. - * Wheel is treated as a button. - * There are invalid combinations of buttons and actions possible - * (like move + wheel), those are silently ignored by the CoreMouseService. - */ - button: CoreMouseButton; - action: CoreMouseAction; - /** - * Modifier states. - * Protocols will add/ignore those based on specific restrictions. - */ - ctrl?: boolean; - alt?: boolean; - shift?: boolean; -} - -/** - * CoreMouseEventType - * To be reported to the browser component which events a mouse - * protocol wants to be catched and forwarded as an ICoreMouseEvent - * to CoreMouseService. - */ -export const enum CoreMouseEventType { - NONE = 0, - /** any mousedown event */ - DOWN = 1, - /** any mouseup event */ - UP = 2, - /** any mousemove event while a button is held */ - DRAG = 4, - /** any mousemove event without a button */ - MOVE = 8, - /** any wheel event */ - WHEEL = 16 -} - -/** - * Mouse protocol interface. - * A mouse protocol can be registered and activated at the CoreMouseService. - * `events` should contain a list of needed events as a hint for the browser component - * to install/remove the appropriate event handlers. - * `restrict` applies further protocol specific restrictions like not allowed - * modifiers or filtering invalid event types. - */ -export interface ICoreMouseProtocol { - events: CoreMouseEventType; - restrict: (e: ICoreMouseEvent) => boolean; -} - -/** - * CoreMouseEncoding - * The tracking encoding can be registered and activated at the CoreMouseService. - * If a ICoreMouseEvent passes all procotol restrictions it will be encoded - * with the active encoding and sent out. - * Note: Returning an empty string will supress sending a mouse report, - * which can be used to skip creating falsey reports in limited encodings - * (DEFAULT only supports up to 223 1-based as coord value). - */ -export type CoreMouseEncoding = (event: ICoreMouseEvent) => string; - -/** - * windowOptions - */ -export interface IWindowOptions { - restoreWin?: boolean; - minimizeWin?: boolean; - setWinPosition?: boolean; - setWinSizePixels?: boolean; - raiseWin?: boolean; - lowerWin?: boolean; - refreshWin?: boolean; - setWinSizeChars?: boolean; - maximizeWin?: boolean; - fullscreenWin?: boolean; - getWinState?: boolean; - getWinPosition?: boolean; - getWinSizePixels?: boolean; - getScreenSizePixels?: boolean; - getCellSizePixels?: boolean; - getWinSizeChars?: boolean; - getScreenSizeChars?: boolean; - getIconTitle?: boolean; - getWinTitle?: boolean; - pushTitle?: boolean; - popTitle?: boolean; - setWinLines?: boolean; -} - -// color events from common, used for OSC 4/10/11/12 and 104/110/111/112 -export const enum ColorRequestType { - REPORT = 0, - SET = 1, - RESTORE = 2 -} -export const enum ColorIndex { - FOREGROUND = 256, - BACKGROUND = 257, - CURSOR = 258 -} -export interface IColorReportRequest { - type: ColorRequestType.REPORT; - index: ColorIndex; -} -export interface IColorSetRequest { - type: ColorRequestType.SET; - index: ColorIndex; - color: IColorRGB; -} -export interface IColorRestoreRequest { - type: ColorRequestType.RESTORE; - index?: ColorIndex; -} -export type IColorEvent = (IColorReportRequest | IColorSetRequest | IColorRestoreRequest)[]; - - -/** - * Calls the parser and handles actions generated by the parser. - */ -export interface IInputHandler { - onTitleChange: IEvent<string>; - - parse(data: string | Uint8Array, promiseResult?: boolean): void | Promise<boolean>; - print(data: Uint32Array, start: number, end: number): void; - registerCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean | Promise<boolean>): IDisposable; - registerDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean | Promise<boolean>): IDisposable; - registerEscHandler(id: IFunctionIdentifier, callback: () => boolean | Promise<boolean>): IDisposable; - registerOscHandler(ident: number, callback: (data: string) => boolean | Promise<boolean>): IDisposable; - - /** C0 BEL */ bell(): boolean; - /** C0 LF */ lineFeed(): boolean; - /** C0 CR */ carriageReturn(): boolean; - /** C0 BS */ backspace(): boolean; - /** C0 HT */ tab(): boolean; - /** C0 SO */ shiftOut(): boolean; - /** C0 SI */ shiftIn(): boolean; - - /** CSI @ */ insertChars(params: IParams): boolean; - /** CSI SP @ */ scrollLeft(params: IParams): boolean; - /** CSI A */ cursorUp(params: IParams): boolean; - /** CSI SP A */ scrollRight(params: IParams): boolean; - /** CSI B */ cursorDown(params: IParams): boolean; - /** CSI C */ cursorForward(params: IParams): boolean; - /** CSI D */ cursorBackward(params: IParams): boolean; - /** CSI E */ cursorNextLine(params: IParams): boolean; - /** CSI F */ cursorPrecedingLine(params: IParams): boolean; - /** CSI G */ cursorCharAbsolute(params: IParams): boolean; - /** CSI H */ cursorPosition(params: IParams): boolean; - /** CSI I */ cursorForwardTab(params: IParams): boolean; - /** CSI J */ eraseInDisplay(params: IParams): boolean; - /** CSI K */ eraseInLine(params: IParams): boolean; - /** CSI L */ insertLines(params: IParams): boolean; - /** CSI M */ deleteLines(params: IParams): boolean; - /** CSI P */ deleteChars(params: IParams): boolean; - /** CSI S */ scrollUp(params: IParams): boolean; - /** CSI T */ scrollDown(params: IParams, collect?: string): boolean; - /** CSI X */ eraseChars(params: IParams): boolean; - /** CSI Z */ cursorBackwardTab(params: IParams): boolean; - /** CSI ` */ charPosAbsolute(params: IParams): boolean; - /** CSI a */ hPositionRelative(params: IParams): boolean; - /** CSI b */ repeatPrecedingCharacter(params: IParams): boolean; - /** CSI c */ sendDeviceAttributesPrimary(params: IParams): boolean; - /** CSI > c */ sendDeviceAttributesSecondary(params: IParams): boolean; - /** CSI d */ linePosAbsolute(params: IParams): boolean; - /** CSI e */ vPositionRelative(params: IParams): boolean; - /** CSI f */ hVPosition(params: IParams): boolean; - /** CSI g */ tabClear(params: IParams): boolean; - /** CSI h */ setMode(params: IParams, collect?: string): boolean; - /** CSI l */ resetMode(params: IParams, collect?: string): boolean; - /** CSI m */ charAttributes(params: IParams): boolean; - /** CSI n */ deviceStatus(params: IParams, collect?: string): boolean; - /** CSI p */ softReset(params: IParams, collect?: string): boolean; - /** CSI q */ setCursorStyle(params: IParams, collect?: string): boolean; - /** CSI r */ setScrollRegion(params: IParams, collect?: string): boolean; - /** CSI s */ saveCursor(params: IParams): boolean; - /** CSI u */ restoreCursor(params: IParams): boolean; - /** CSI ' } */ insertColumns(params: IParams): boolean; - /** CSI ' ~ */ deleteColumns(params: IParams): boolean; - - /** OSC 0 - OSC 2 */ setTitle(data: string): boolean; - /** OSC 4 */ setOrReportIndexedColor(data: string): boolean; - /** OSC 10 */ setOrReportFgColor(data: string): boolean; - /** OSC 11 */ setOrReportBgColor(data: string): boolean; - /** OSC 12 */ setOrReportCursorColor(data: string): boolean; - /** OSC 104 */ restoreIndexedColor(data: string): boolean; - /** OSC 110 */ restoreFgColor(data: string): boolean; - /** OSC 111 */ restoreBgColor(data: string): boolean; - /** OSC 112 */ restoreCursorColor(data: string): boolean; - - /** ESC E */ nextLine(): boolean; - /** ESC = */ keypadApplicationMode(): boolean; - /** ESC > */ keypadNumericMode(): boolean; - /** ESC % G - ESC % @ */ selectDefaultCharset(): boolean; - /** ESC ( C - ESC ) C - ESC * C - ESC + C - ESC - C - ESC . C - ESC / C */ selectCharset(collectAndFlag: string): boolean; - /** ESC D */ index(): boolean; - /** ESC H */ tabSet(): boolean; - /** ESC M */ reverseIndex(): boolean; - /** ESC c */ fullReset(): boolean; - /** ESC n - ESC o - ESC | - ESC } - ESC ~ */ setgLevel(level: number): boolean; - /** ESC # 8 */ screenAlignmentPattern(): boolean; -} - -interface IParseStack { - paused: boolean; - cursorStartX: number; - cursorStartY: number; - decodedLength: number; - position: number; -} diff --git a/node_modules/xterm/src/common/WindowsMode.ts b/node_modules/xterm/src/common/WindowsMode.ts deleted file mode 100644 index 7cff094..0000000 --- a/node_modules/xterm/src/common/WindowsMode.ts +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { CHAR_DATA_CODE_INDEX, NULL_CELL_CODE, WHITESPACE_CELL_CODE } from 'common/buffer/Constants'; -import { IBufferService } from 'common/services/Services'; - -export function updateWindowsModeWrappedState(bufferService: IBufferService): void { - // Winpty does not support wraparound mode which means that lines will never - // be marked as wrapped. This causes issues for things like copying a line - // retaining the wrapped new line characters or if consumers are listening - // in on the data stream. - // - // The workaround for this is to listen to every incoming line feed and mark - // the line as wrapped if the last character in the previous line is not a - // space. This is certainly not without its problems, but generally on - // Windows when text reaches the end of the terminal it's likely going to be - // wrapped. - const line = bufferService.buffer.lines.get(bufferService.buffer.ybase + bufferService.buffer.y - 1); - const lastChar = line?.get(bufferService.cols - 1); - - const nextLine = bufferService.buffer.lines.get(bufferService.buffer.ybase + bufferService.buffer.y); - if (nextLine && lastChar) { - nextLine.isWrapped = (lastChar[CHAR_DATA_CODE_INDEX] !== NULL_CELL_CODE && lastChar[CHAR_DATA_CODE_INDEX] !== WHITESPACE_CELL_CODE); - } -} diff --git a/node_modules/xterm/src/common/buffer/AttributeData.ts b/node_modules/xterm/src/common/buffer/AttributeData.ts deleted file mode 100644 index 43d378e..0000000 --- a/node_modules/xterm/src/common/buffer/AttributeData.ts +++ /dev/null @@ -1,148 +0,0 @@ -/** - * Copyright (c) 2018 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IAttributeData, IColorRGB, IExtendedAttrs } from 'common/Types'; -import { Attributes, FgFlags, BgFlags, UnderlineStyle } from 'common/buffer/Constants'; - -export class AttributeData implements IAttributeData { - public static toColorRGB(value: number): IColorRGB { - return [ - value >>> Attributes.RED_SHIFT & 255, - value >>> Attributes.GREEN_SHIFT & 255, - value & 255 - ]; - } - - public static fromColorRGB(value: IColorRGB): number { - return (value[0] & 255) << Attributes.RED_SHIFT | (value[1] & 255) << Attributes.GREEN_SHIFT | value[2] & 255; - } - - public clone(): IAttributeData { - const newObj = new AttributeData(); - newObj.fg = this.fg; - newObj.bg = this.bg; - newObj.extended = this.extended.clone(); - return newObj; - } - - // data - public fg = 0; - public bg = 0; - public extended = new ExtendedAttrs(); - - // flags - public isInverse(): number { return this.fg & FgFlags.INVERSE; } - public isBold(): number { return this.fg & FgFlags.BOLD; } - public isUnderline(): number { return this.fg & FgFlags.UNDERLINE; } - public isBlink(): number { return this.fg & FgFlags.BLINK; } - public isInvisible(): number { return this.fg & FgFlags.INVISIBLE; } - public isItalic(): number { return this.bg & BgFlags.ITALIC; } - public isDim(): number { return this.bg & BgFlags.DIM; } - public isStrikethrough(): number { return this.fg & FgFlags.STRIKETHROUGH; } - - // color modes - public getFgColorMode(): number { return this.fg & Attributes.CM_MASK; } - public getBgColorMode(): number { return this.bg & Attributes.CM_MASK; } - public isFgRGB(): boolean { return (this.fg & Attributes.CM_MASK) === Attributes.CM_RGB; } - public isBgRGB(): boolean { return (this.bg & Attributes.CM_MASK) === Attributes.CM_RGB; } - public isFgPalette(): boolean { return (this.fg & Attributes.CM_MASK) === Attributes.CM_P16 || (this.fg & Attributes.CM_MASK) === Attributes.CM_P256; } - public isBgPalette(): boolean { return (this.bg & Attributes.CM_MASK) === Attributes.CM_P16 || (this.bg & Attributes.CM_MASK) === Attributes.CM_P256; } - public isFgDefault(): boolean { return (this.fg & Attributes.CM_MASK) === 0; } - public isBgDefault(): boolean { return (this.bg & Attributes.CM_MASK) === 0; } - public isAttributeDefault(): boolean { return this.fg === 0 && this.bg === 0; } - - // colors - public getFgColor(): number { - switch (this.fg & Attributes.CM_MASK) { - case Attributes.CM_P16: - case Attributes.CM_P256: return this.fg & Attributes.PCOLOR_MASK; - case Attributes.CM_RGB: return this.fg & Attributes.RGB_MASK; - default: return -1; // CM_DEFAULT defaults to -1 - } - } - public getBgColor(): number { - switch (this.bg & Attributes.CM_MASK) { - case Attributes.CM_P16: - case Attributes.CM_P256: return this.bg & Attributes.PCOLOR_MASK; - case Attributes.CM_RGB: return this.bg & Attributes.RGB_MASK; - default: return -1; // CM_DEFAULT defaults to -1 - } - } - - // extended attrs - public hasExtendedAttrs(): number { - return this.bg & BgFlags.HAS_EXTENDED; - } - public updateExtended(): void { - if (this.extended.isEmpty()) { - this.bg &= ~BgFlags.HAS_EXTENDED; - } else { - this.bg |= BgFlags.HAS_EXTENDED; - } - } - public getUnderlineColor(): number { - if ((this.bg & BgFlags.HAS_EXTENDED) && ~this.extended.underlineColor) { - switch (this.extended.underlineColor & Attributes.CM_MASK) { - case Attributes.CM_P16: - case Attributes.CM_P256: return this.extended.underlineColor & Attributes.PCOLOR_MASK; - case Attributes.CM_RGB: return this.extended.underlineColor & Attributes.RGB_MASK; - default: return this.getFgColor(); - } - } - return this.getFgColor(); - } - public getUnderlineColorMode(): number { - return (this.bg & BgFlags.HAS_EXTENDED) && ~this.extended.underlineColor - ? this.extended.underlineColor & Attributes.CM_MASK - : this.getFgColorMode(); - } - public isUnderlineColorRGB(): boolean { - return (this.bg & BgFlags.HAS_EXTENDED) && ~this.extended.underlineColor - ? (this.extended.underlineColor & Attributes.CM_MASK) === Attributes.CM_RGB - : this.isFgRGB(); - } - public isUnderlineColorPalette(): boolean { - return (this.bg & BgFlags.HAS_EXTENDED) && ~this.extended.underlineColor - ? (this.extended.underlineColor & Attributes.CM_MASK) === Attributes.CM_P16 - || (this.extended.underlineColor & Attributes.CM_MASK) === Attributes.CM_P256 - : this.isFgPalette(); - } - public isUnderlineColorDefault(): boolean { - return (this.bg & BgFlags.HAS_EXTENDED) && ~this.extended.underlineColor - ? (this.extended.underlineColor & Attributes.CM_MASK) === 0 - : this.isFgDefault(); - } - public getUnderlineStyle(): UnderlineStyle { - return this.fg & FgFlags.UNDERLINE - ? (this.bg & BgFlags.HAS_EXTENDED ? this.extended.underlineStyle : UnderlineStyle.SINGLE) - : UnderlineStyle.NONE; - } -} - - -/** - * Extended attributes for a cell. - * Holds information about different underline styles and color. - */ -export class ExtendedAttrs implements IExtendedAttrs { - constructor( - // underline style, NONE is empty - public underlineStyle: UnderlineStyle = UnderlineStyle.NONE, - // underline color, -1 is empty (same as FG) - public underlineColor: number = -1 - ) {} - - public clone(): IExtendedAttrs { - return new ExtendedAttrs(this.underlineStyle, this.underlineColor); - } - - /** - * Convenient method to indicate whether the object holds no additional information, - * that needs to be persistant in the buffer. - */ - public isEmpty(): boolean { - return this.underlineStyle === UnderlineStyle.NONE; - } -} diff --git a/node_modules/xterm/src/common/buffer/Buffer.ts b/node_modules/xterm/src/common/buffer/Buffer.ts deleted file mode 100644 index 7596fef..0000000 --- a/node_modules/xterm/src/common/buffer/Buffer.ts +++ /dev/null @@ -1,702 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { CircularList, IInsertEvent } from 'common/CircularList'; -import { IBuffer, BufferIndex, IBufferStringIterator, IBufferStringIteratorResult } from 'common/buffer/Types'; -import { IBufferLine, ICellData, IAttributeData, ICharset } from 'common/Types'; -import { BufferLine, DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; -import { CellData } from 'common/buffer/CellData'; -import { NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_WIDTH, WHITESPACE_CELL_CODE, CHAR_DATA_WIDTH_INDEX, CHAR_DATA_CHAR_INDEX } from 'common/buffer/Constants'; -import { reflowLargerApplyNewLayout, reflowLargerCreateNewLayout, reflowLargerGetLinesToRemove, reflowSmallerGetNewLineLengths, getWrappedLineTrimmedLength } from 'common/buffer/BufferReflow'; -import { Marker } from 'common/buffer/Marker'; -import { IOptionsService, IBufferService } from 'common/services/Services'; -import { DEFAULT_CHARSET } from 'common/data/Charsets'; -import { ExtendedAttrs } from 'common/buffer/AttributeData'; - -export const MAX_BUFFER_SIZE = 4294967295; // 2^32 - 1 - -/** - * This class represents a terminal buffer (an internal state of the terminal), where the - * following information is stored (in high-level): - * - text content of this particular buffer - * - cursor position - * - scroll position - */ -export class Buffer implements IBuffer { - public lines: CircularList<IBufferLine>; - public ydisp: number = 0; - public ybase: number = 0; - public y: number = 0; - public x: number = 0; - public scrollBottom: number; - public scrollTop: number; - // TODO: Type me - public tabs: any; - public savedY: number = 0; - public savedX: number = 0; - public savedCurAttrData = DEFAULT_ATTR_DATA.clone(); - public savedCharset: ICharset | undefined = DEFAULT_CHARSET; - public markers: Marker[] = []; - private _nullCell: ICellData = CellData.fromCharData([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]); - private _whitespaceCell: ICellData = CellData.fromCharData([0, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_WIDTH, WHITESPACE_CELL_CODE]); - private _cols: number; - private _rows: number; - private _isClearing: boolean = false; - - constructor( - private _hasScrollback: boolean, - private _optionsService: IOptionsService, - private _bufferService: IBufferService - ) { - this._cols = this._bufferService.cols; - this._rows = this._bufferService.rows; - this.lines = new CircularList<IBufferLine>(this._getCorrectBufferLength(this._rows)); - this.scrollTop = 0; - this.scrollBottom = this._rows - 1; - this.setupTabStops(); - } - - public getNullCell(attr?: IAttributeData): ICellData { - if (attr) { - this._nullCell.fg = attr.fg; - this._nullCell.bg = attr.bg; - this._nullCell.extended = attr.extended; - } else { - this._nullCell.fg = 0; - this._nullCell.bg = 0; - this._nullCell.extended = new ExtendedAttrs(); - } - return this._nullCell; - } - - public getWhitespaceCell(attr?: IAttributeData): ICellData { - if (attr) { - this._whitespaceCell.fg = attr.fg; - this._whitespaceCell.bg = attr.bg; - this._whitespaceCell.extended = attr.extended; - } else { - this._whitespaceCell.fg = 0; - this._whitespaceCell.bg = 0; - this._whitespaceCell.extended = new ExtendedAttrs(); - } - return this._whitespaceCell; - } - - public getBlankLine(attr: IAttributeData, isWrapped?: boolean): IBufferLine { - return new BufferLine(this._bufferService.cols, this.getNullCell(attr), isWrapped); - } - - public get hasScrollback(): boolean { - return this._hasScrollback && this.lines.maxLength > this._rows; - } - - public get isCursorInViewport(): boolean { - const absoluteY = this.ybase + this.y; - const relativeY = absoluteY - this.ydisp; - return (relativeY >= 0 && relativeY < this._rows); - } - - /** - * Gets the correct buffer length based on the rows provided, the terminal's - * scrollback and whether this buffer is flagged to have scrollback or not. - * @param rows The terminal rows to use in the calculation. - */ - private _getCorrectBufferLength(rows: number): number { - if (!this._hasScrollback) { - return rows; - } - - const correctBufferLength = rows + this._optionsService.rawOptions.scrollback; - - return correctBufferLength > MAX_BUFFER_SIZE ? MAX_BUFFER_SIZE : correctBufferLength; - } - - /** - * Fills the buffer's viewport with blank lines. - */ - public fillViewportRows(fillAttr?: IAttributeData): void { - if (this.lines.length === 0) { - if (fillAttr === undefined) { - fillAttr = DEFAULT_ATTR_DATA; - } - let i = this._rows; - while (i--) { - this.lines.push(this.getBlankLine(fillAttr)); - } - } - } - - /** - * Clears the buffer to it's initial state, discarding all previous data. - */ - public clear(): void { - this.ydisp = 0; - this.ybase = 0; - this.y = 0; - this.x = 0; - this.lines = new CircularList<IBufferLine>(this._getCorrectBufferLength(this._rows)); - this.scrollTop = 0; - this.scrollBottom = this._rows - 1; - this.setupTabStops(); - } - - /** - * Resizes the buffer, adjusting its data accordingly. - * @param newCols The new number of columns. - * @param newRows The new number of rows. - */ - public resize(newCols: number, newRows: number): void { - // store reference to null cell with default attrs - const nullCell = this.getNullCell(DEFAULT_ATTR_DATA); - - // Increase max length if needed before adjustments to allow space to fill - // as required. - const newMaxLength = this._getCorrectBufferLength(newRows); - if (newMaxLength > this.lines.maxLength) { - this.lines.maxLength = newMaxLength; - } - - // The following adjustments should only happen if the buffer has been - // initialized/filled. - if (this.lines.length > 0) { - // Deal with columns increasing (reducing needs to happen after reflow) - if (this._cols < newCols) { - for (let i = 0; i < this.lines.length; i++) { - this.lines.get(i)!.resize(newCols, nullCell); - } - } - - // Resize rows in both directions as needed - let addToY = 0; - if (this._rows < newRows) { - for (let y = this._rows; y < newRows; y++) { - if (this.lines.length < newRows + this.ybase) { - if (this._optionsService.rawOptions.windowsMode) { - // Just add the new missing rows on Windows as conpty reprints the screen with it's - // view of the world. Once a line enters scrollback for conpty it remains there - this.lines.push(new BufferLine(newCols, nullCell)); - } else { - if (this.ybase > 0 && this.lines.length <= this.ybase + this.y + addToY + 1) { - // There is room above the buffer and there are no empty elements below the line, - // scroll up - this.ybase--; - addToY++; - if (this.ydisp > 0) { - // Viewport is at the top of the buffer, must increase downwards - this.ydisp--; - } - } else { - // Add a blank line if there is no buffer left at the top to scroll to, or if there - // are blank lines after the cursor - this.lines.push(new BufferLine(newCols, nullCell)); - } - } - } - } - } else { // (this._rows >= newRows) - for (let y = this._rows; y > newRows; y--) { - if (this.lines.length > newRows + this.ybase) { - if (this.lines.length > this.ybase + this.y + 1) { - // The line is a blank line below the cursor, remove it - this.lines.pop(); - } else { - // The line is the cursor, scroll down - this.ybase++; - this.ydisp++; - } - } - } - } - - // Reduce max length if needed after adjustments, this is done after as it - // would otherwise cut data from the bottom of the buffer. - if (newMaxLength < this.lines.maxLength) { - // Trim from the top of the buffer and adjust ybase and ydisp. - const amountToTrim = this.lines.length - newMaxLength; - if (amountToTrim > 0) { - this.lines.trimStart(amountToTrim); - this.ybase = Math.max(this.ybase - amountToTrim, 0); - this.ydisp = Math.max(this.ydisp - amountToTrim, 0); - this.savedY = Math.max(this.savedY - amountToTrim, 0); - } - this.lines.maxLength = newMaxLength; - } - - // Make sure that the cursor stays on screen - this.x = Math.min(this.x, newCols - 1); - this.y = Math.min(this.y, newRows - 1); - if (addToY) { - this.y += addToY; - } - this.savedX = Math.min(this.savedX, newCols - 1); - - this.scrollTop = 0; - } - - this.scrollBottom = newRows - 1; - - if (this._isReflowEnabled) { - this._reflow(newCols, newRows); - - // Trim the end of the line off if cols shrunk - if (this._cols > newCols) { - for (let i = 0; i < this.lines.length; i++) { - this.lines.get(i)!.resize(newCols, nullCell); - } - } - } - - this._cols = newCols; - this._rows = newRows; - } - - private get _isReflowEnabled(): boolean { - return this._hasScrollback && !this._optionsService.rawOptions.windowsMode; - } - - private _reflow(newCols: number, newRows: number): void { - if (this._cols === newCols) { - return; - } - - // Iterate through rows, ignore the last one as it cannot be wrapped - if (newCols > this._cols) { - this._reflowLarger(newCols, newRows); - } else { - this._reflowSmaller(newCols, newRows); - } - } - - private _reflowLarger(newCols: number, newRows: number): void { - const toRemove: number[] = reflowLargerGetLinesToRemove(this.lines, this._cols, newCols, this.ybase + this.y, this.getNullCell(DEFAULT_ATTR_DATA)); - if (toRemove.length > 0) { - const newLayoutResult = reflowLargerCreateNewLayout(this.lines, toRemove); - reflowLargerApplyNewLayout(this.lines, newLayoutResult.layout); - this._reflowLargerAdjustViewport(newCols, newRows, newLayoutResult.countRemoved); - } - } - - private _reflowLargerAdjustViewport(newCols: number, newRows: number, countRemoved: number): void { - const nullCell = this.getNullCell(DEFAULT_ATTR_DATA); - // Adjust viewport based on number of items removed - let viewportAdjustments = countRemoved; - while (viewportAdjustments-- > 0) { - if (this.ybase === 0) { - if (this.y > 0) { - this.y--; - } - if (this.lines.length < newRows) { - // Add an extra row at the bottom of the viewport - this.lines.push(new BufferLine(newCols, nullCell)); - } - } else { - if (this.ydisp === this.ybase) { - this.ydisp--; - } - this.ybase--; - } - } - this.savedY = Math.max(this.savedY - countRemoved, 0); - } - - private _reflowSmaller(newCols: number, newRows: number): void { - const nullCell = this.getNullCell(DEFAULT_ATTR_DATA); - // Gather all BufferLines that need to be inserted into the Buffer here so that they can be - // batched up and only committed once - const toInsert = []; - let countToInsert = 0; - // Go backwards as many lines may be trimmed and this will avoid considering them - for (let y = this.lines.length - 1; y >= 0; y--) { - // Check whether this line is a problem - let nextLine = this.lines.get(y) as BufferLine; - if (!nextLine || !nextLine.isWrapped && nextLine.getTrimmedLength() <= newCols) { - continue; - } - - // Gather wrapped lines and adjust y to be the starting line - const wrappedLines: BufferLine[] = [nextLine]; - while (nextLine.isWrapped && y > 0) { - nextLine = this.lines.get(--y) as BufferLine; - wrappedLines.unshift(nextLine); - } - - // If these lines contain the cursor don't touch them, the program will handle fixing up - // wrapped lines with the cursor - const absoluteY = this.ybase + this.y; - if (absoluteY >= y && absoluteY < y + wrappedLines.length) { - continue; - } - - const lastLineLength = wrappedLines[wrappedLines.length - 1].getTrimmedLength(); - const destLineLengths = reflowSmallerGetNewLineLengths(wrappedLines, this._cols, newCols); - const linesToAdd = destLineLengths.length - wrappedLines.length; - let trimmedLines: number; - if (this.ybase === 0 && this.y !== this.lines.length - 1) { - // If the top section of the buffer is not yet filled - trimmedLines = Math.max(0, this.y - this.lines.maxLength + linesToAdd); - } else { - trimmedLines = Math.max(0, this.lines.length - this.lines.maxLength + linesToAdd); - } - - // Add the new lines - const newLines: BufferLine[] = []; - for (let i = 0; i < linesToAdd; i++) { - const newLine = this.getBlankLine(DEFAULT_ATTR_DATA, true) as BufferLine; - newLines.push(newLine); - } - if (newLines.length > 0) { - toInsert.push({ - // countToInsert here gets the actual index, taking into account other inserted items. - // using this we can iterate through the list forwards - start: y + wrappedLines.length + countToInsert, - newLines - }); - countToInsert += newLines.length; - } - wrappedLines.push(...newLines); - - // Copy buffer data to new locations, this needs to happen backwards to do in-place - let destLineIndex = destLineLengths.length - 1; // Math.floor(cellsNeeded / newCols); - let destCol = destLineLengths[destLineIndex]; // cellsNeeded % newCols; - if (destCol === 0) { - destLineIndex--; - destCol = destLineLengths[destLineIndex]; - } - let srcLineIndex = wrappedLines.length - linesToAdd - 1; - let srcCol = lastLineLength; - while (srcLineIndex >= 0) { - const cellsToCopy = Math.min(srcCol, destCol); - if (wrappedLines[destLineIndex] === undefined) { - // Sanity check that the line exists, this has been known to fail for an unknown reason - // which would stop the reflow from happening if an exception would throw. - break; - } - wrappedLines[destLineIndex].copyCellsFrom(wrappedLines[srcLineIndex], srcCol - cellsToCopy, destCol - cellsToCopy, cellsToCopy, true); - destCol -= cellsToCopy; - if (destCol === 0) { - destLineIndex--; - destCol = destLineLengths[destLineIndex]; - } - srcCol -= cellsToCopy; - if (srcCol === 0) { - srcLineIndex--; - const wrappedLinesIndex = Math.max(srcLineIndex, 0); - srcCol = getWrappedLineTrimmedLength(wrappedLines, wrappedLinesIndex, this._cols); - } - } - - // Null out the end of the line ends if a wide character wrapped to the following line - for (let i = 0; i < wrappedLines.length; i++) { - if (destLineLengths[i] < newCols) { - wrappedLines[i].setCell(destLineLengths[i], nullCell); - } - } - - // Adjust viewport as needed - let viewportAdjustments = linesToAdd - trimmedLines; - while (viewportAdjustments-- > 0) { - if (this.ybase === 0) { - if (this.y < newRows - 1) { - this.y++; - this.lines.pop(); - } else { - this.ybase++; - this.ydisp++; - } - } else { - // Ensure ybase does not exceed its maximum value - if (this.ybase < Math.min(this.lines.maxLength, this.lines.length + countToInsert) - newRows) { - if (this.ybase === this.ydisp) { - this.ydisp++; - } - this.ybase++; - } - } - } - this.savedY = Math.min(this.savedY + linesToAdd, this.ybase + newRows - 1); - } - - // Rearrange lines in the buffer if there are any insertions, this is done at the end rather - // than earlier so that it's a single O(n) pass through the buffer, instead of O(n^2) from many - // costly calls to CircularList.splice. - if (toInsert.length > 0) { - // Record buffer insert events and then play them back backwards so that the indexes are - // correct - const insertEvents: IInsertEvent[] = []; - - // Record original lines so they don't get overridden when we rearrange the list - const originalLines: BufferLine[] = []; - for (let i = 0; i < this.lines.length; i++) { - originalLines.push(this.lines.get(i) as BufferLine); - } - const originalLinesLength = this.lines.length; - - let originalLineIndex = originalLinesLength - 1; - let nextToInsertIndex = 0; - let nextToInsert = toInsert[nextToInsertIndex]; - this.lines.length = Math.min(this.lines.maxLength, this.lines.length + countToInsert); - let countInsertedSoFar = 0; - for (let i = Math.min(this.lines.maxLength - 1, originalLinesLength + countToInsert - 1); i >= 0; i--) { - if (nextToInsert && nextToInsert.start > originalLineIndex + countInsertedSoFar) { - // Insert extra lines here, adjusting i as needed - for (let nextI = nextToInsert.newLines.length - 1; nextI >= 0; nextI--) { - this.lines.set(i--, nextToInsert.newLines[nextI]); - } - i++; - - // Create insert events for later - insertEvents.push({ - index: originalLineIndex + 1, - amount: nextToInsert.newLines.length - }); - - countInsertedSoFar += nextToInsert.newLines.length; - nextToInsert = toInsert[++nextToInsertIndex]; - } else { - this.lines.set(i, originalLines[originalLineIndex--]); - } - } - - // Update markers - let insertCountEmitted = 0; - for (let i = insertEvents.length - 1; i >= 0; i--) { - insertEvents[i].index += insertCountEmitted; - this.lines.onInsertEmitter.fire(insertEvents[i]); - insertCountEmitted += insertEvents[i].amount; - } - const amountToTrim = Math.max(0, originalLinesLength + countToInsert - this.lines.maxLength); - if (amountToTrim > 0) { - this.lines.onTrimEmitter.fire(amountToTrim); - } - } - } - - // private _reflowSmallerGetLinesNeeded() - - /** - * Translates a string index back to a BufferIndex. - * To get the correct buffer position the string must start at `startCol` 0 - * (default in translateBufferLineToString). - * The method also works on wrapped line strings given rows were not trimmed. - * The method operates on the CharData string length, there are no - * additional content or boundary checks. Therefore the string and the buffer - * should not be altered in between. - * TODO: respect trim flag after fixing #1685 - * @param lineIndex line index the string was retrieved from - * @param stringIndex index within the string - * @param startCol column offset the string was retrieved from - */ - public stringIndexToBufferIndex(lineIndex: number, stringIndex: number, trimRight: boolean = false): BufferIndex { - while (stringIndex) { - const line = this.lines.get(lineIndex); - if (!line) { - return [-1, -1]; - } - const length = (trimRight) ? line.getTrimmedLength() : line.length; - for (let i = 0; i < length; ++i) { - if (line.get(i)[CHAR_DATA_WIDTH_INDEX]) { - // empty cells report a string length of 0, but get replaced - // with a whitespace in translateToString, thus replace with 1 - stringIndex -= line.get(i)[CHAR_DATA_CHAR_INDEX].length || 1; - } - if (stringIndex < 0) { - return [lineIndex, i]; - } - } - lineIndex++; - } - return [lineIndex, 0]; - } - - /** - * Translates a buffer line to a string, with optional start and end columns. - * Wide characters will count as two columns in the resulting string. This - * function is useful for getting the actual text underneath the raw selection - * position. - * @param line The line being translated. - * @param trimRight Whether to trim whitespace to the right. - * @param startCol The column to start at. - * @param endCol The column to end at. - */ - public translateBufferLineToString(lineIndex: number, trimRight: boolean, startCol: number = 0, endCol?: number): string { - const line = this.lines.get(lineIndex); - if (!line) { - return ''; - } - return line.translateToString(trimRight, startCol, endCol); - } - - public getWrappedRangeForLine(y: number): { first: number, last: number } { - let first = y; - let last = y; - // Scan upwards for wrapped lines - while (first > 0 && this.lines.get(first)!.isWrapped) { - first--; - } - // Scan downwards for wrapped lines - while (last + 1 < this.lines.length && this.lines.get(last + 1)!.isWrapped) { - last++; - } - return { first, last }; - } - - /** - * Setup the tab stops. - * @param i The index to start setting up tab stops from. - */ - public setupTabStops(i?: number): void { - if (i !== null && i !== undefined) { - if (!this.tabs[i]) { - i = this.prevStop(i); - } - } else { - this.tabs = {}; - i = 0; - } - - for (; i < this._cols; i += this._optionsService.rawOptions.tabStopWidth) { - this.tabs[i] = true; - } - } - - /** - * Move the cursor to the previous tab stop from the given position (default is current). - * @param x The position to move the cursor to the previous tab stop. - */ - public prevStop(x?: number): number { - if (x === null || x === undefined) { - x = this.x; - } - while (!this.tabs[--x] && x > 0); - return x >= this._cols ? this._cols - 1 : x < 0 ? 0 : x; - } - - /** - * Move the cursor one tab stop forward from the given position (default is current). - * @param x The position to move the cursor one tab stop forward. - */ - public nextStop(x?: number): number { - if (x === null || x === undefined) { - x = this.x; - } - while (!this.tabs[++x] && x < this._cols); - return x >= this._cols ? this._cols - 1 : x < 0 ? 0 : x; - } - - public clearMarkers(y?: number): void { - this._isClearing = true; - if (y !== undefined) { - for (let i = 0; i < this.markers.length; i++) { - if (this.markers[i].line === y) { - this.markers[i].dispose(); - this.markers.splice(i--, 1); - } - } - } else { - for (const marker of this.markers) { - marker.dispose(); - } - this.markers = []; - } - this._isClearing = false; - } - - public addMarker(y: number): Marker { - const marker = new Marker(y); - this.markers.push(marker); - marker.register(this.lines.onTrim(amount => { - marker.line -= amount; - // The marker should be disposed when the line is trimmed from the buffer - if (marker.line < 0) { - marker.dispose(); - } - })); - marker.register(this.lines.onInsert(event => { - if (marker.line >= event.index) { - marker.line += event.amount; - } - })); - marker.register(this.lines.onDelete(event => { - // Delete the marker if it's within the range - if (marker.line >= event.index && marker.line < event.index + event.amount) { - marker.dispose(); - } - - // Shift the marker if it's after the deleted range - if (marker.line > event.index) { - marker.line -= event.amount; - } - })); - marker.register(marker.onDispose(() => this._removeMarker(marker))); - return marker; - } - - private _removeMarker(marker: Marker): void { - if (!this._isClearing) { - this.markers.splice(this.markers.indexOf(marker), 1); - } - } - - public iterator(trimRight: boolean, startIndex?: number, endIndex?: number, startOverscan?: number, endOverscan?: number): IBufferStringIterator { - return new BufferStringIterator(this, trimRight, startIndex, endIndex, startOverscan, endOverscan); - } -} - -/** - * Iterator to get unwrapped content strings from the buffer. - * The iterator returns at least the string data between the borders - * `startIndex` and `endIndex` (exclusive) and will expand the lines - * by `startOverscan` to the top and by `endOverscan` to the bottom, - * if no new line was found in between. - * It will never read/return string data beyond `startIndex - startOverscan` - * or `endIndex + endOverscan`. Therefore the first and last line might be truncated. - * It is possible to always get the full string for the first and last line as well - * by setting the overscan values to the actual buffer length. This not recommended - * since it might return the whole buffer within a single string in a worst case scenario. - */ -export class BufferStringIterator implements IBufferStringIterator { - private _current: number; - - constructor ( - private _buffer: IBuffer, - private _trimRight: boolean, - private _startIndex: number = 0, - private _endIndex: number = _buffer.lines.length, - private _startOverscan: number = 0, - private _endOverscan: number = 0 - ) { - if (this._startIndex < 0) { - this._startIndex = 0; - } - if (this._endIndex > this._buffer.lines.length) { - this._endIndex = this._buffer.lines.length; - } - this._current = this._startIndex; - } - - public hasNext(): boolean { - return this._current < this._endIndex; - } - - public next(): IBufferStringIteratorResult { - const range = this._buffer.getWrappedRangeForLine(this._current); - // limit search window to overscan value at both borders - if (range.first < this._startIndex - this._startOverscan) { - range.first = this._startIndex - this._startOverscan; - } - if (range.last > this._endIndex + this._endOverscan) { - range.last = this._endIndex + this._endOverscan; - } - // limit to current buffer length - range.first = Math.max(range.first, 0); - range.last = Math.min(range.last, this._buffer.lines.length); - let content = ''; - for (let i = range.first; i <= range.last; ++i) { - content += this._buffer.translateBufferLineToString(i, this._trimRight); - } - this._current = range.last + 1; - return { range, content }; - } -} diff --git a/node_modules/xterm/src/common/buffer/BufferLine.ts b/node_modules/xterm/src/common/buffer/BufferLine.ts deleted file mode 100644 index f0bf4fc..0000000 --- a/node_modules/xterm/src/common/buffer/BufferLine.ts +++ /dev/null @@ -1,441 +0,0 @@ -/** - * Copyright (c) 2018 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { CharData, IBufferLine, ICellData, IAttributeData, IExtendedAttrs } from 'common/Types'; -import { stringFromCodePoint } from 'common/input/TextDecoder'; -import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, CHAR_DATA_ATTR_INDEX, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE, WHITESPACE_CELL_CHAR, Content, BgFlags } from 'common/buffer/Constants'; -import { CellData } from 'common/buffer/CellData'; -import { AttributeData, ExtendedAttrs } from 'common/buffer/AttributeData'; - -/** - * buffer memory layout: - * - * | uint32_t | uint32_t | uint32_t | - * | `content` | `FG` | `BG` | - * | wcwidth(2) comb(1) codepoint(21) | flags(8) R(8) G(8) B(8) | flags(8) R(8) G(8) B(8) | - */ - - -/** typed array slots taken by one cell */ -const CELL_SIZE = 3; - -/** - * Cell member indices. - * - * Direct access: - * `content = data[column * CELL_SIZE + Cell.CONTENT];` - * `fg = data[column * CELL_SIZE + Cell.FG];` - * `bg = data[column * CELL_SIZE + Cell.BG];` - */ -const enum Cell { - CONTENT = 0, - FG = 1, // currently simply holds all known attrs - BG = 2 // currently unused -} - -export const DEFAULT_ATTR_DATA = Object.freeze(new AttributeData()); - -/** - * Typed array based bufferline implementation. - * - * There are 2 ways to insert data into the cell buffer: - * - `setCellFromCodepoint` + `addCodepointToCell` - * Use these for data that is already UTF32. - * Used during normal input in `InputHandler` for faster buffer access. - * - `setCell` - * This method takes a CellData object and stores the data in the buffer. - * Use `CellData.fromCharData` to create the CellData object (e.g. from JS string). - * - * To retrieve data from the buffer use either one of the primitive methods - * (if only one particular value is needed) or `loadCell`. For `loadCell` in a loop - * memory allocs / GC pressure can be greatly reduced by reusing the CellData object. - */ -export class BufferLine implements IBufferLine { - protected _data: Uint32Array; - protected _combined: {[index: number]: string} = {}; - protected _extendedAttrs: {[index: number]: ExtendedAttrs} = {}; - public length: number; - - constructor(cols: number, fillCellData?: ICellData, public isWrapped: boolean = false) { - this._data = new Uint32Array(cols * CELL_SIZE); - const cell = fillCellData || CellData.fromCharData([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]); - for (let i = 0; i < cols; ++i) { - this.setCell(i, cell); - } - this.length = cols; - } - - /** - * Get cell data CharData. - * @deprecated - */ - public get(index: number): CharData { - const content = this._data[index * CELL_SIZE + Cell.CONTENT]; - const cp = content & Content.CODEPOINT_MASK; - return [ - this._data[index * CELL_SIZE + Cell.FG], - (content & Content.IS_COMBINED_MASK) - ? this._combined[index] - : (cp) ? stringFromCodePoint(cp) : '', - content >> Content.WIDTH_SHIFT, - (content & Content.IS_COMBINED_MASK) - ? this._combined[index].charCodeAt(this._combined[index].length - 1) - : cp - ]; - } - - /** - * Set cell data from CharData. - * @deprecated - */ - public set(index: number, value: CharData): void { - this._data[index * CELL_SIZE + Cell.FG] = value[CHAR_DATA_ATTR_INDEX]; - if (value[CHAR_DATA_CHAR_INDEX].length > 1) { - this._combined[index] = value[1]; - this._data[index * CELL_SIZE + Cell.CONTENT] = index | Content.IS_COMBINED_MASK | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT); - } else { - this._data[index * CELL_SIZE + Cell.CONTENT] = value[CHAR_DATA_CHAR_INDEX].charCodeAt(0) | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT); - } - } - - /** - * primitive getters - * use these when only one value is needed, otherwise use `loadCell` - */ - public getWidth(index: number): number { - return this._data[index * CELL_SIZE + Cell.CONTENT] >> Content.WIDTH_SHIFT; - } - - /** Test whether content has width. */ - public hasWidth(index: number): number { - return this._data[index * CELL_SIZE + Cell.CONTENT] & Content.WIDTH_MASK; - } - - /** Get FG cell component. */ - public getFg(index: number): number { - return this._data[index * CELL_SIZE + Cell.FG]; - } - - /** Get BG cell component. */ - public getBg(index: number): number { - return this._data[index * CELL_SIZE + Cell.BG]; - } - - /** - * Test whether contains any chars. - * Basically an empty has no content, but other cells might differ in FG/BG - * from real empty cells. - * */ - public hasContent(index: number): number { - return this._data[index * CELL_SIZE + Cell.CONTENT] & Content.HAS_CONTENT_MASK; - } - - /** - * Get codepoint of the cell. - * To be in line with `code` in CharData this either returns - * a single UTF32 codepoint or the last codepoint of a combined string. - */ - public getCodePoint(index: number): number { - const content = this._data[index * CELL_SIZE + Cell.CONTENT]; - if (content & Content.IS_COMBINED_MASK) { - return this._combined[index].charCodeAt(this._combined[index].length - 1); - } - return content & Content.CODEPOINT_MASK; - } - - /** Test whether the cell contains a combined string. */ - public isCombined(index: number): number { - return this._data[index * CELL_SIZE + Cell.CONTENT] & Content.IS_COMBINED_MASK; - } - - /** Returns the string content of the cell. */ - public getString(index: number): string { - const content = this._data[index * CELL_SIZE + Cell.CONTENT]; - if (content & Content.IS_COMBINED_MASK) { - return this._combined[index]; - } - if (content & Content.CODEPOINT_MASK) { - return stringFromCodePoint(content & Content.CODEPOINT_MASK); - } - // return empty string for empty cells - return ''; - } - - /** - * Load data at `index` into `cell`. This is used to access cells in a way that's more friendly - * to GC as it significantly reduced the amount of new objects/references needed. - */ - public loadCell(index: number, cell: ICellData): ICellData { - const startIndex = index * CELL_SIZE; - cell.content = this._data[startIndex + Cell.CONTENT]; - cell.fg = this._data[startIndex + Cell.FG]; - cell.bg = this._data[startIndex + Cell.BG]; - if (cell.content & Content.IS_COMBINED_MASK) { - cell.combinedData = this._combined[index]; - } - if (cell.bg & BgFlags.HAS_EXTENDED) { - cell.extended = this._extendedAttrs[index]; - } - return cell; - } - - /** - * Set data at `index` to `cell`. - */ - public setCell(index: number, cell: ICellData): void { - if (cell.content & Content.IS_COMBINED_MASK) { - this._combined[index] = cell.combinedData; - } - if (cell.bg & BgFlags.HAS_EXTENDED) { - this._extendedAttrs[index] = cell.extended; - } - this._data[index * CELL_SIZE + Cell.CONTENT] = cell.content; - this._data[index * CELL_SIZE + Cell.FG] = cell.fg; - this._data[index * CELL_SIZE + Cell.BG] = cell.bg; - } - - /** - * Set cell data from input handler. - * Since the input handler see the incoming chars as UTF32 codepoints, - * it gets an optimized access method. - */ - public setCellFromCodePoint(index: number, codePoint: number, width: number, fg: number, bg: number, eAttrs: IExtendedAttrs): void { - if (bg & BgFlags.HAS_EXTENDED) { - this._extendedAttrs[index] = eAttrs; - } - this._data[index * CELL_SIZE + Cell.CONTENT] = codePoint | (width << Content.WIDTH_SHIFT); - this._data[index * CELL_SIZE + Cell.FG] = fg; - this._data[index * CELL_SIZE + Cell.BG] = bg; - } - - /** - * Add a codepoint to a cell from input handler. - * During input stage combining chars with a width of 0 follow and stack - * onto a leading char. Since we already set the attrs - * by the previous `setDataFromCodePoint` call, we can omit it here. - */ - public addCodepointToCell(index: number, codePoint: number): void { - let content = this._data[index * CELL_SIZE + Cell.CONTENT]; - if (content & Content.IS_COMBINED_MASK) { - // we already have a combined string, simply add - this._combined[index] += stringFromCodePoint(codePoint); - } else { - if (content & Content.CODEPOINT_MASK) { - // normal case for combining chars: - // - move current leading char + new one into combined string - // - set combined flag - this._combined[index] = stringFromCodePoint(content & Content.CODEPOINT_MASK) + stringFromCodePoint(codePoint); - content &= ~Content.CODEPOINT_MASK; // set codepoint in buffer to 0 - content |= Content.IS_COMBINED_MASK; - } else { - // should not happen - we actually have no data in the cell yet - // simply set the data in the cell buffer with a width of 1 - content = codePoint | (1 << Content.WIDTH_SHIFT); - } - this._data[index * CELL_SIZE + Cell.CONTENT] = content; - } - } - - public insertCells(pos: number, n: number, fillCellData: ICellData, eraseAttr?: IAttributeData): void { - pos %= this.length; - - // handle fullwidth at pos: reset cell one to the left if pos is second cell of a wide char - if (pos && this.getWidth(pos - 1) === 2) { - this.setCellFromCodePoint(pos - 1, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs()); - } - - if (n < this.length - pos) { - const cell = new CellData(); - for (let i = this.length - pos - n - 1; i >= 0; --i) { - this.setCell(pos + n + i, this.loadCell(pos + i, cell)); - } - for (let i = 0; i < n; ++i) { - this.setCell(pos + i, fillCellData); - } - } else { - for (let i = pos; i < this.length; ++i) { - this.setCell(i, fillCellData); - } - } - - // handle fullwidth at line end: reset last cell if it is first cell of a wide char - if (this.getWidth(this.length - 1) === 2) { - this.setCellFromCodePoint(this.length - 1, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs()); - } - } - - public deleteCells(pos: number, n: number, fillCellData: ICellData, eraseAttr?: IAttributeData): void { - pos %= this.length; - if (n < this.length - pos) { - const cell = new CellData(); - for (let i = 0; i < this.length - pos - n; ++i) { - this.setCell(pos + i, this.loadCell(pos + n + i, cell)); - } - for (let i = this.length - n; i < this.length; ++i) { - this.setCell(i, fillCellData); - } - } else { - for (let i = pos; i < this.length; ++i) { - this.setCell(i, fillCellData); - } - } - - // handle fullwidth at pos: - // - reset pos-1 if wide char - // - reset pos if width==0 (previous second cell of a wide char) - if (pos && this.getWidth(pos - 1) === 2) { - this.setCellFromCodePoint(pos - 1, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs()); - } - if (this.getWidth(pos) === 0 && !this.hasContent(pos)) { - this.setCellFromCodePoint(pos, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs()); - } - } - - public replaceCells(start: number, end: number, fillCellData: ICellData, eraseAttr?: IAttributeData): void { - // handle fullwidth at start: reset cell one to the left if start is second cell of a wide char - if (start && this.getWidth(start - 1) === 2) { - this.setCellFromCodePoint(start - 1, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs()); - } - // handle fullwidth at last cell + 1: reset to empty cell if it is second part of a wide char - if (end < this.length && this.getWidth(end - 1) === 2) { - this.setCellFromCodePoint(end, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs()); - } - - while (start < end && start < this.length) { - this.setCell(start++, fillCellData); - } - } - - public resize(cols: number, fillCellData: ICellData): void { - if (cols === this.length) { - return; - } - if (cols > this.length) { - const data = new Uint32Array(cols * CELL_SIZE); - if (this.length) { - if (cols * CELL_SIZE < this._data.length) { - data.set(this._data.subarray(0, cols * CELL_SIZE)); - } else { - data.set(this._data); - } - } - this._data = data; - for (let i = this.length; i < cols; ++i) { - this.setCell(i, fillCellData); - } - } else { - if (cols) { - const data = new Uint32Array(cols * CELL_SIZE); - data.set(this._data.subarray(0, cols * CELL_SIZE)); - this._data = data; - // Remove any cut off combined data, FIXME: repeat this for extended attrs - const keys = Object.keys(this._combined); - for (let i = 0; i < keys.length; i++) { - const key = parseInt(keys[i], 10); - if (key >= cols) { - delete this._combined[key]; - } - } - } else { - this._data = new Uint32Array(0); - this._combined = {}; - } - } - this.length = cols; - } - - /** fill a line with fillCharData */ - public fill(fillCellData: ICellData): void { - this._combined = {}; - this._extendedAttrs = {}; - for (let i = 0; i < this.length; ++i) { - this.setCell(i, fillCellData); - } - } - - /** alter to a full copy of line */ - public copyFrom(line: BufferLine): void { - if (this.length !== line.length) { - this._data = new Uint32Array(line._data); - } else { - // use high speed copy if lengths are equal - this._data.set(line._data); - } - this.length = line.length; - this._combined = {}; - for (const el in line._combined) { - this._combined[el] = line._combined[el]; - } - this._extendedAttrs = {}; - for (const el in line._extendedAttrs) { - this._extendedAttrs[el] = line._extendedAttrs[el]; - } - this.isWrapped = line.isWrapped; - } - - /** create a new clone */ - public clone(): IBufferLine { - const newLine = new BufferLine(0); - newLine._data = new Uint32Array(this._data); - newLine.length = this.length; - for (const el in this._combined) { - newLine._combined[el] = this._combined[el]; - } - for (const el in this._extendedAttrs) { - newLine._extendedAttrs[el] = this._extendedAttrs[el]; - } - newLine.isWrapped = this.isWrapped; - return newLine; - } - - public getTrimmedLength(): number { - for (let i = this.length - 1; i >= 0; --i) { - if ((this._data[i * CELL_SIZE + Cell.CONTENT] & Content.HAS_CONTENT_MASK)) { - return i + (this._data[i * CELL_SIZE + Cell.CONTENT] >> Content.WIDTH_SHIFT); - } - } - return 0; - } - - public copyCellsFrom(src: BufferLine, srcCol: number, destCol: number, length: number, applyInReverse: boolean): void { - const srcData = src._data; - if (applyInReverse) { - for (let cell = length - 1; cell >= 0; cell--) { - for (let i = 0; i < CELL_SIZE; i++) { - this._data[(destCol + cell) * CELL_SIZE + i] = srcData[(srcCol + cell) * CELL_SIZE + i]; - } - } - } else { - for (let cell = 0; cell < length; cell++) { - for (let i = 0; i < CELL_SIZE; i++) { - this._data[(destCol + cell) * CELL_SIZE + i] = srcData[(srcCol + cell) * CELL_SIZE + i]; - } - } - } - - // Move any combined data over as needed, FIXME: repeat for extended attrs - const srcCombinedKeys = Object.keys(src._combined); - for (let i = 0; i < srcCombinedKeys.length; i++) { - const key = parseInt(srcCombinedKeys[i], 10); - if (key >= srcCol) { - this._combined[key - srcCol + destCol] = src._combined[key]; - } - } - } - - public translateToString(trimRight: boolean = false, startCol: number = 0, endCol: number = this.length): string { - if (trimRight) { - endCol = Math.min(endCol, this.getTrimmedLength()); - } - let result = ''; - while (startCol < endCol) { - const content = this._data[startCol * CELL_SIZE + Cell.CONTENT]; - const cp = content & Content.CODEPOINT_MASK; - result += (content & Content.IS_COMBINED_MASK) ? this._combined[startCol] : (cp) ? stringFromCodePoint(cp) : WHITESPACE_CELL_CHAR; - startCol += (content >> Content.WIDTH_SHIFT) || 1; // always advance by 1 - } - return result; - } -} diff --git a/node_modules/xterm/src/common/buffer/BufferRange.ts b/node_modules/xterm/src/common/buffer/BufferRange.ts deleted file mode 100644 index a49cf48..0000000 --- a/node_modules/xterm/src/common/buffer/BufferRange.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Copyright (c) 2021 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IBufferRange } from 'xterm'; - -export function getRangeLength(range: IBufferRange, bufferCols: number): number { - if (range.start.y > range.end.y) { - throw new Error(`Buffer range end (${range.end.x}, ${range.end.y}) cannot be before start (${range.start.x}, ${range.start.y})`); - } - return bufferCols * (range.end.y - range.start.y) + (range.end.x - range.start.x + 1); -} diff --git a/node_modules/xterm/src/common/buffer/BufferReflow.ts b/node_modules/xterm/src/common/buffer/BufferReflow.ts deleted file mode 100644 index ece9a96..0000000 --- a/node_modules/xterm/src/common/buffer/BufferReflow.ts +++ /dev/null @@ -1,220 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { BufferLine } from 'common/buffer/BufferLine'; -import { CircularList } from 'common/CircularList'; -import { IBufferLine, ICellData } from 'common/Types'; - -export interface INewLayoutResult { - layout: number[]; - countRemoved: number; -} - -/** - * Evaluates and returns indexes to be removed after a reflow larger occurs. Lines will be removed - * when a wrapped line unwraps. - * @param lines The buffer lines. - * @param newCols The columns after resize. - */ -export function reflowLargerGetLinesToRemove(lines: CircularList<IBufferLine>, oldCols: number, newCols: number, bufferAbsoluteY: number, nullCell: ICellData): number[] { - // Gather all BufferLines that need to be removed from the Buffer here so that they can be - // batched up and only committed once - const toRemove: number[] = []; - - for (let y = 0; y < lines.length - 1; y++) { - // Check if this row is wrapped - let i = y; - let nextLine = lines.get(++i) as BufferLine; - if (!nextLine.isWrapped) { - continue; - } - - // Check how many lines it's wrapped for - const wrappedLines: BufferLine[] = [lines.get(y) as BufferLine]; - while (i < lines.length && nextLine.isWrapped) { - wrappedLines.push(nextLine); - nextLine = lines.get(++i) as BufferLine; - } - - // If these lines contain the cursor don't touch them, the program will handle fixing up wrapped - // lines with the cursor - if (bufferAbsoluteY >= y && bufferAbsoluteY < i) { - y += wrappedLines.length - 1; - continue; - } - - // Copy buffer data to new locations - let destLineIndex = 0; - let destCol = getWrappedLineTrimmedLength(wrappedLines, destLineIndex, oldCols); - let srcLineIndex = 1; - let srcCol = 0; - while (srcLineIndex < wrappedLines.length) { - const srcTrimmedTineLength = getWrappedLineTrimmedLength(wrappedLines, srcLineIndex, oldCols); - const srcRemainingCells = srcTrimmedTineLength - srcCol; - const destRemainingCells = newCols - destCol; - const cellsToCopy = Math.min(srcRemainingCells, destRemainingCells); - - wrappedLines[destLineIndex].copyCellsFrom(wrappedLines[srcLineIndex], srcCol, destCol, cellsToCopy, false); - - destCol += cellsToCopy; - if (destCol === newCols) { - destLineIndex++; - destCol = 0; - } - srcCol += cellsToCopy; - if (srcCol === srcTrimmedTineLength) { - srcLineIndex++; - srcCol = 0; - } - - // Make sure the last cell isn't wide, if it is copy it to the current dest - if (destCol === 0 && destLineIndex !== 0) { - if (wrappedLines[destLineIndex - 1].getWidth(newCols - 1) === 2) { - wrappedLines[destLineIndex].copyCellsFrom(wrappedLines[destLineIndex - 1], newCols - 1, destCol++, 1, false); - // Null out the end of the last row - wrappedLines[destLineIndex - 1].setCell(newCols - 1, nullCell); - } - } - } - - // Clear out remaining cells or fragments could remain; - wrappedLines[destLineIndex].replaceCells(destCol, newCols, nullCell); - - // Work backwards and remove any rows at the end that only contain null cells - let countToRemove = 0; - for (let i = wrappedLines.length - 1; i > 0; i--) { - if (i > destLineIndex || wrappedLines[i].getTrimmedLength() === 0) { - countToRemove++; - } else { - break; - } - } - - if (countToRemove > 0) { - toRemove.push(y + wrappedLines.length - countToRemove); // index - toRemove.push(countToRemove); - } - - y += wrappedLines.length - 1; - } - return toRemove; -} - -/** - * Creates and return the new layout for lines given an array of indexes to be removed. - * @param lines The buffer lines. - * @param toRemove The indexes to remove. - */ -export function reflowLargerCreateNewLayout(lines: CircularList<IBufferLine>, toRemove: number[]): INewLayoutResult { - const layout: number[] = []; - // First iterate through the list and get the actual indexes to use for rows - let nextToRemoveIndex = 0; - let nextToRemoveStart = toRemove[nextToRemoveIndex]; - let countRemovedSoFar = 0; - for (let i = 0; i < lines.length; i++) { - if (nextToRemoveStart === i) { - const countToRemove = toRemove[++nextToRemoveIndex]; - - // Tell markers that there was a deletion - lines.onDeleteEmitter.fire({ - index: i - countRemovedSoFar, - amount: countToRemove - }); - - i += countToRemove - 1; - countRemovedSoFar += countToRemove; - nextToRemoveStart = toRemove[++nextToRemoveIndex]; - } else { - layout.push(i); - } - } - return { - layout, - countRemoved: countRemovedSoFar - }; -} - -/** - * Applies a new layout to the buffer. This essentially does the same as many splice calls but it's - * done all at once in a single iteration through the list since splice is very expensive. - * @param lines The buffer lines. - * @param newLayout The new layout to apply. - */ -export function reflowLargerApplyNewLayout(lines: CircularList<IBufferLine>, newLayout: number[]): void { - // Record original lines so they don't get overridden when we rearrange the list - const newLayoutLines: BufferLine[] = []; - for (let i = 0; i < newLayout.length; i++) { - newLayoutLines.push(lines.get(newLayout[i]) as BufferLine); - } - - // Rearrange the list - for (let i = 0; i < newLayoutLines.length; i++) { - lines.set(i, newLayoutLines[i]); - } - lines.length = newLayout.length; -} - -/** - * Gets the new line lengths for a given wrapped line. The purpose of this function it to pre- - * compute the wrapping points since wide characters may need to be wrapped onto the following line. - * This function will return an array of numbers of where each line wraps to, the resulting array - * will only contain the values `newCols` (when the line does not end with a wide character) and - * `newCols - 1` (when the line does end with a wide character), except for the last value which - * will contain the remaining items to fill the line. - * - * Calling this with a `newCols` value of `1` will lock up. - * - * @param wrappedLines The wrapped lines to evaluate. - * @param oldCols The columns before resize. - * @param newCols The columns after resize. - */ -export function reflowSmallerGetNewLineLengths(wrappedLines: BufferLine[], oldCols: number, newCols: number): number[] { - const newLineLengths: number[] = []; - const cellsNeeded = wrappedLines.map((l, i) => getWrappedLineTrimmedLength(wrappedLines, i, oldCols)).reduce((p, c) => p + c); - - // Use srcCol and srcLine to find the new wrapping point, use that to get the cellsAvailable and - // linesNeeded - let srcCol = 0; - let srcLine = 0; - let cellsAvailable = 0; - while (cellsAvailable < cellsNeeded) { - if (cellsNeeded - cellsAvailable < newCols) { - // Add the final line and exit the loop - newLineLengths.push(cellsNeeded - cellsAvailable); - break; - } - srcCol += newCols; - const oldTrimmedLength = getWrappedLineTrimmedLength(wrappedLines, srcLine, oldCols); - if (srcCol > oldTrimmedLength) { - srcCol -= oldTrimmedLength; - srcLine++; - } - const endsWithWide = wrappedLines[srcLine].getWidth(srcCol - 1) === 2; - if (endsWithWide) { - srcCol--; - } - const lineLength = endsWithWide ? newCols - 1 : newCols; - newLineLengths.push(lineLength); - cellsAvailable += lineLength; - } - - return newLineLengths; -} - -export function getWrappedLineTrimmedLength(lines: BufferLine[], i: number, cols: number): number { - // If this is the last row in the wrapped line, get the actual trimmed length - if (i === lines.length - 1) { - return lines[i].getTrimmedLength(); - } - // Detect whether the following line starts with a wide character and the end of the current line - // is null, if so then we can be pretty sure the null character should be excluded from the line - // length] - const endsInNull = !(lines[i].hasContent(cols - 1)) && lines[i].getWidth(cols - 1) === 1; - const followingLineStartsWithWide = lines[i + 1].getWidth(0) === 2; - if (endsInNull && followingLineStartsWithWide) { - return cols - 1; - } - return cols; -} diff --git a/node_modules/xterm/src/common/buffer/BufferSet.ts b/node_modules/xterm/src/common/buffer/BufferSet.ts deleted file mode 100644 index de220e8..0000000 --- a/node_modules/xterm/src/common/buffer/BufferSet.ts +++ /dev/null @@ -1,131 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IBuffer, IBufferSet } from 'common/buffer/Types'; -import { IAttributeData } from 'common/Types'; -import { Buffer } from 'common/buffer/Buffer'; -import { EventEmitter, IEvent } from 'common/EventEmitter'; -import { IOptionsService, IBufferService } from 'common/services/Services'; -import { Disposable } from 'common/Lifecycle'; - -/** - * The BufferSet represents the set of two buffers used by xterm terminals (normal and alt) and - * provides also utilities for working with them. - */ -export class BufferSet extends Disposable implements IBufferSet { - private _normal!: Buffer; - private _alt!: Buffer; - private _activeBuffer!: Buffer; - - private _onBufferActivate = this.register(new EventEmitter<{activeBuffer: IBuffer, inactiveBuffer: IBuffer}>()); - public get onBufferActivate(): IEvent<{activeBuffer: IBuffer, inactiveBuffer: IBuffer}> { return this._onBufferActivate.event; } - - /** - * Create a new BufferSet for the given terminal. - * @param _terminal - The terminal the BufferSet will belong to - */ - constructor( - private readonly _optionsService: IOptionsService, - private readonly _bufferService: IBufferService - ) { - super(); - this.reset(); - } - - public reset(): void { - this._normal = new Buffer(true, this._optionsService, this._bufferService); - this._normal.fillViewportRows(); - - // The alt buffer should never have scrollback. - // See http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer - this._alt = new Buffer(false, this._optionsService, this._bufferService); - this._activeBuffer = this._normal; - this._onBufferActivate.fire({ - activeBuffer: this._normal, - inactiveBuffer: this._alt - }); - - this.setupTabStops(); - } - - /** - * Returns the alt Buffer of the BufferSet - */ - public get alt(): Buffer { - return this._alt; - } - - /** - * Returns the normal Buffer of the BufferSet - */ - public get active(): Buffer { - return this._activeBuffer; - } - - /** - * Returns the currently active Buffer of the BufferSet - */ - public get normal(): Buffer { - return this._normal; - } - - /** - * Sets the normal Buffer of the BufferSet as its currently active Buffer - */ - public activateNormalBuffer(): void { - if (this._activeBuffer === this._normal) { - return; - } - this._normal.x = this._alt.x; - this._normal.y = this._alt.y; - // The alt buffer should always be cleared when we switch to the normal - // buffer. This frees up memory since the alt buffer should always be new - // when activated. - this._alt.clear(); - this._activeBuffer = this._normal; - this._onBufferActivate.fire({ - activeBuffer: this._normal, - inactiveBuffer: this._alt - }); - } - - /** - * Sets the alt Buffer of the BufferSet as its currently active Buffer - */ - public activateAltBuffer(fillAttr?: IAttributeData): void { - if (this._activeBuffer === this._alt) { - return; - } - // Since the alt buffer is always cleared when the normal buffer is - // activated, we want to fill it when switching to it. - this._alt.fillViewportRows(fillAttr); - this._alt.x = this._normal.x; - this._alt.y = this._normal.y; - this._activeBuffer = this._alt; - this._onBufferActivate.fire({ - activeBuffer: this._alt, - inactiveBuffer: this._normal - }); - } - - /** - * Resizes both normal and alt buffers, adjusting their data accordingly. - * @param newCols The new number of columns. - * @param newRows The new number of rows. - */ - public resize(newCols: number, newRows: number): void { - this._normal.resize(newCols, newRows); - this._alt.resize(newCols, newRows); - } - - /** - * Setup the tab stops. - * @param i The index to start setting up tab stops from. - */ - public setupTabStops(i?: number): void { - this._normal.setupTabStops(i); - this._alt.setupTabStops(i); - } -} diff --git a/node_modules/xterm/src/common/buffer/CellData.ts b/node_modules/xterm/src/common/buffer/CellData.ts deleted file mode 100644 index a87b579..0000000 --- a/node_modules/xterm/src/common/buffer/CellData.ts +++ /dev/null @@ -1,94 +0,0 @@ -/** - * Copyright (c) 2018 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { CharData, ICellData, IExtendedAttrs } from 'common/Types'; -import { stringFromCodePoint } from 'common/input/TextDecoder'; -import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, CHAR_DATA_ATTR_INDEX, Content } from 'common/buffer/Constants'; -import { AttributeData, ExtendedAttrs } from 'common/buffer/AttributeData'; - -/** - * CellData - represents a single Cell in the terminal buffer. - */ -export class CellData extends AttributeData implements ICellData { - /** Helper to create CellData from CharData. */ - public static fromCharData(value: CharData): CellData { - const obj = new CellData(); - obj.setFromCharData(value); - return obj; - } - /** Primitives from terminal buffer. */ - public content = 0; - public fg = 0; - public bg = 0; - public extended: IExtendedAttrs = new ExtendedAttrs(); - public combinedData = ''; - /** Whether cell contains a combined string. */ - public isCombined(): number { - return this.content & Content.IS_COMBINED_MASK; - } - /** Width of the cell. */ - public getWidth(): number { - return this.content >> Content.WIDTH_SHIFT; - } - /** JS string of the content. */ - public getChars(): string { - if (this.content & Content.IS_COMBINED_MASK) { - return this.combinedData; - } - if (this.content & Content.CODEPOINT_MASK) { - return stringFromCodePoint(this.content & Content.CODEPOINT_MASK); - } - return ''; - } - /** - * Codepoint of cell - * Note this returns the UTF32 codepoint of single chars, - * if content is a combined string it returns the codepoint - * of the last char in string to be in line with code in CharData. - * */ - public getCode(): number { - return (this.isCombined()) - ? this.combinedData.charCodeAt(this.combinedData.length - 1) - : this.content & Content.CODEPOINT_MASK; - } - /** Set data from CharData */ - public setFromCharData(value: CharData): void { - this.fg = value[CHAR_DATA_ATTR_INDEX]; - this.bg = 0; - let combined = false; - // surrogates and combined strings need special treatment - if (value[CHAR_DATA_CHAR_INDEX].length > 2) { - combined = true; - } - else if (value[CHAR_DATA_CHAR_INDEX].length === 2) { - const code = value[CHAR_DATA_CHAR_INDEX].charCodeAt(0); - // if the 2-char string is a surrogate create single codepoint - // everything else is combined - if (0xD800 <= code && code <= 0xDBFF) { - const second = value[CHAR_DATA_CHAR_INDEX].charCodeAt(1); - if (0xDC00 <= second && second <= 0xDFFF) { - this.content = ((code - 0xD800) * 0x400 + second - 0xDC00 + 0x10000) | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT); - } - else { - combined = true; - } - } - else { - combined = true; - } - } - else { - this.content = value[CHAR_DATA_CHAR_INDEX].charCodeAt(0) | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT); - } - if (combined) { - this.combinedData = value[CHAR_DATA_CHAR_INDEX]; - this.content = Content.IS_COMBINED_MASK | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT); - } - } - /** Get data as CharData. */ - public getAsCharData(): CharData { - return [this.fg, this.getChars(), this.getWidth(), this.getCode()]; - } -} diff --git a/node_modules/xterm/src/common/buffer/Constants.ts b/node_modules/xterm/src/common/buffer/Constants.ts deleted file mode 100644 index a2c1b88..0000000 --- a/node_modules/xterm/src/common/buffer/Constants.ts +++ /dev/null @@ -1,139 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -export const DEFAULT_COLOR = 256; -export const DEFAULT_ATTR = (0 << 18) | (DEFAULT_COLOR << 9) | (256 << 0); - -export const CHAR_DATA_ATTR_INDEX = 0; -export const CHAR_DATA_CHAR_INDEX = 1; -export const CHAR_DATA_WIDTH_INDEX = 2; -export const CHAR_DATA_CODE_INDEX = 3; - -/** - * Null cell - a real empty cell (containing nothing). - * Note that code should always be 0 for a null cell as - * several test condition of the buffer line rely on this. - */ -export const NULL_CELL_CHAR = ''; -export const NULL_CELL_WIDTH = 1; -export const NULL_CELL_CODE = 0; - -/** - * Whitespace cell. - * This is meant as a replacement for empty cells when needed - * during rendering lines to preserve correct aligment. - */ -export const WHITESPACE_CELL_CHAR = ' '; -export const WHITESPACE_CELL_WIDTH = 1; -export const WHITESPACE_CELL_CODE = 32; - -/** - * Bitmasks for accessing data in `content`. - */ -export const enum Content { - /** - * bit 1..21 codepoint, max allowed in UTF32 is 0x10FFFF (21 bits taken) - * read: `codepoint = content & Content.codepointMask;` - * write: `content |= codepoint & Content.codepointMask;` - * shortcut if precondition `codepoint <= 0x10FFFF` is met: - * `content |= codepoint;` - */ - CODEPOINT_MASK = 0x1FFFFF, - - /** - * bit 22 flag indication whether a cell contains combined content - * read: `isCombined = content & Content.isCombined;` - * set: `content |= Content.isCombined;` - * clear: `content &= ~Content.isCombined;` - */ - IS_COMBINED_MASK = 0x200000, // 1 << 21 - - /** - * bit 1..22 mask to check whether a cell contains any string data - * we need to check for codepoint and isCombined bits to see - * whether a cell contains anything - * read: `isEmpty = !(content & Content.hasContent)` - */ - HAS_CONTENT_MASK = 0x3FFFFF, - - /** - * bit 23..24 wcwidth value of cell, takes 2 bits (ranges from 0..2) - * read: `width = (content & Content.widthMask) >> Content.widthShift;` - * `hasWidth = content & Content.widthMask;` - * as long as wcwidth is highest value in `content`: - * `width = content >> Content.widthShift;` - * write: `content |= (width << Content.widthShift) & Content.widthMask;` - * shortcut if precondition `0 <= width <= 3` is met: - * `content |= width << Content.widthShift;` - */ - WIDTH_MASK = 0xC00000, // 3 << 22 - WIDTH_SHIFT = 22 -} - -export const enum Attributes { - /** - * bit 1..8 blue in RGB, color in P256 and P16 - */ - BLUE_MASK = 0xFF, - BLUE_SHIFT = 0, - PCOLOR_MASK = 0xFF, - PCOLOR_SHIFT = 0, - - /** - * bit 9..16 green in RGB - */ - GREEN_MASK = 0xFF00, - GREEN_SHIFT = 8, - - /** - * bit 17..24 red in RGB - */ - RED_MASK = 0xFF0000, - RED_SHIFT = 16, - - /** - * bit 25..26 color mode: DEFAULT (0) | P16 (1) | P256 (2) | RGB (3) - */ - CM_MASK = 0x3000000, - CM_DEFAULT = 0, - CM_P16 = 0x1000000, - CM_P256 = 0x2000000, - CM_RGB = 0x3000000, - - /** - * bit 1..24 RGB room - */ - RGB_MASK = 0xFFFFFF -} - -export const enum FgFlags { - /** - * bit 27..32 - */ - INVERSE = 0x4000000, - BOLD = 0x8000000, - UNDERLINE = 0x10000000, - BLINK = 0x20000000, - INVISIBLE = 0x40000000, - STRIKETHROUGH = 0x80000000, -} - -export const enum BgFlags { - /** - * bit 27..32 (upper 3 unused) - */ - ITALIC = 0x4000000, - DIM = 0x8000000, - HAS_EXTENDED = 0x10000000 -} - -export const enum UnderlineStyle { - NONE = 0, - SINGLE = 1, - DOUBLE = 2, - CURLY = 3, - DOTTED = 4, - DASHED = 5 -} diff --git a/node_modules/xterm/src/common/buffer/Marker.ts b/node_modules/xterm/src/common/buffer/Marker.ts deleted file mode 100644 index 72c4085..0000000 --- a/node_modules/xterm/src/common/buffer/Marker.ts +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2018 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { EventEmitter, IEvent } from 'common/EventEmitter'; -import { Disposable } from 'common/Lifecycle'; -import { IMarker } from 'common/Types'; - -export class Marker extends Disposable implements IMarker { - private static _nextId = 1; - - private _id: number = Marker._nextId++; - public isDisposed: boolean = false; - - public get id(): number { return this._id; } - - private _onDispose = new EventEmitter<void>(); - public get onDispose(): IEvent<void> { return this._onDispose.event; } - - constructor( - public line: number - ) { - super(); - } - - public dispose(): void { - if (this.isDisposed) { - return; - } - this.isDisposed = true; - this.line = -1; - // Emit before super.dispose such that dispose listeners get a change to react - this._onDispose.fire(); - super.dispose(); - } -} diff --git a/node_modules/xterm/src/common/buffer/Types.d.ts b/node_modules/xterm/src/common/buffer/Types.d.ts deleted file mode 100644 index 36b70b7..0000000 --- a/node_modules/xterm/src/common/buffer/Types.d.ts +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IAttributeData, ICircularList, IBufferLine, ICellData, IMarker, ICharset, IDisposable } from 'common/Types'; -import { IEvent } from 'common/EventEmitter'; - -// BufferIndex denotes a position in the buffer: [rowIndex, colIndex] -export type BufferIndex = [number, number]; - -export interface IBufferStringIteratorResult { - range: {first: number, last: number}; - content: string; -} - -export interface IBufferStringIterator { - hasNext(): boolean; - next(): IBufferStringIteratorResult; -} - -export interface IBuffer { - readonly lines: ICircularList<IBufferLine>; - ydisp: number; - ybase: number; - y: number; - x: number; - tabs: any; - scrollBottom: number; - scrollTop: number; - hasScrollback: boolean; - savedY: number; - savedX: number; - savedCharset: ICharset | undefined; - savedCurAttrData: IAttributeData; - isCursorInViewport: boolean; - markers: IMarker[]; - translateBufferLineToString(lineIndex: number, trimRight: boolean, startCol?: number, endCol?: number): string; - getWrappedRangeForLine(y: number): { first: number, last: number }; - nextStop(x?: number): number; - prevStop(x?: number): number; - getBlankLine(attr: IAttributeData, isWrapped?: boolean): IBufferLine; - stringIndexToBufferIndex(lineIndex: number, stringIndex: number, trimRight?: boolean): number[]; - iterator(trimRight: boolean, startIndex?: number, endIndex?: number, startOverscan?: number, endOverscan?: number): IBufferStringIterator; - getNullCell(attr?: IAttributeData): ICellData; - getWhitespaceCell(attr?: IAttributeData): ICellData; - addMarker(y: number): IMarker; - clearMarkers(y?: number): void; -} - -export interface IBufferSet extends IDisposable { - alt: IBuffer; - normal: IBuffer; - active: IBuffer; - - onBufferActivate: IEvent<{ activeBuffer: IBuffer, inactiveBuffer: IBuffer }>; - - activateNormalBuffer(): void; - activateAltBuffer(fillAttr?: IAttributeData): void; - reset(): void; - resize(newCols: number, newRows: number): void; - setupTabStops(i?: number): void; -} diff --git a/node_modules/xterm/src/common/data/Charsets.ts b/node_modules/xterm/src/common/data/Charsets.ts deleted file mode 100644 index c72d5a2..0000000 --- a/node_modules/xterm/src/common/data/Charsets.ts +++ /dev/null @@ -1,256 +0,0 @@ -/** - * Copyright (c) 2016 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { ICharset } from 'common/Types'; - -/** - * The character sets supported by the terminal. These enable several languages - * to be represented within the terminal with only 8-bit encoding. See ISO 2022 - * for a discussion on character sets. Only VT100 character sets are supported. - */ -export const CHARSETS: { [key: string]: ICharset | undefined } = {}; - -/** - * The default character set, US. - */ -export const DEFAULT_CHARSET: ICharset | undefined = CHARSETS['B']; - -/** - * DEC Special Character and Line Drawing Set. - * Reference: http://vt100.net/docs/vt102-ug/table5-13.html - * A lot of curses apps use this if they see TERM=xterm. - * testing: echo -e '\e(0a\e(B' - * The xterm output sometimes seems to conflict with the - * reference above. xterm seems in line with the reference - * when running vttest however. - * The table below now uses xterm's output from vttest. - */ -CHARSETS['0'] = { - '`': '\u25c6', // '◆' - 'a': '\u2592', // '▒' - 'b': '\u2409', // '␉' (HT) - 'c': '\u240c', // '␌' (FF) - 'd': '\u240d', // '␍' (CR) - 'e': '\u240a', // '␊' (LF) - 'f': '\u00b0', // '°' - 'g': '\u00b1', // '±' - 'h': '\u2424', // '' (NL) - 'i': '\u240b', // '␋' (VT) - 'j': '\u2518', // '┘' - 'k': '\u2510', // '┐' - 'l': '\u250c', // '┌' - 'm': '\u2514', // '└' - 'n': '\u253c', // '┼' - 'o': '\u23ba', // '⎺' - 'p': '\u23bb', // '⎻' - 'q': '\u2500', // '─' - 'r': '\u23bc', // '⎼' - 's': '\u23bd', // '⎽' - 't': '\u251c', // '├' - 'u': '\u2524', // '┤' - 'v': '\u2534', // '┴' - 'w': '\u252c', // '┬' - 'x': '\u2502', // '│' - 'y': '\u2264', // '≤' - 'z': '\u2265', // '≥' - '{': '\u03c0', // 'π' - '|': '\u2260', // '≠' - '}': '\u00a3', // '£' - '~': '\u00b7' // '·' -}; - -/** - * British character set - * ESC (A - * Reference: http://vt100.net/docs/vt220-rm/table2-5.html - */ -CHARSETS['A'] = { - '#': '£' -}; - -/** - * United States character set - * ESC (B - */ -CHARSETS['B'] = undefined; - -/** - * Dutch character set - * ESC (4 - * Reference: http://vt100.net/docs/vt220-rm/table2-6.html - */ -CHARSETS['4'] = { - '#': '£', - '@': '¾', - '[': 'ij', - '\\': '½', - ']': '|', - '{': '¨', - '|': 'f', - '}': '¼', - '~': '´' -}; - -/** - * Finnish character set - * ESC (C or ESC (5 - * Reference: http://vt100.net/docs/vt220-rm/table2-7.html - */ -CHARSETS['C'] = -CHARSETS['5'] = { - '[': 'Ä', - '\\': 'Ö', - ']': 'Å', - '^': 'Ü', - '`': 'é', - '{': 'ä', - '|': 'ö', - '}': 'å', - '~': 'ü' -}; - -/** - * French character set - * ESC (R - * Reference: http://vt100.net/docs/vt220-rm/table2-8.html - */ -CHARSETS['R'] = { - '#': '£', - '@': 'à', - '[': '°', - '\\': 'ç', - ']': '§', - '{': 'é', - '|': 'ù', - '}': 'è', - '~': '¨' -}; - -/** - * French Canadian character set - * ESC (Q - * Reference: http://vt100.net/docs/vt220-rm/table2-9.html - */ -CHARSETS['Q'] = { - '@': 'à', - '[': 'â', - '\\': 'ç', - ']': 'ê', - '^': 'î', - '`': 'ô', - '{': 'é', - '|': 'ù', - '}': 'è', - '~': 'û' -}; - -/** - * German character set - * ESC (K - * Reference: http://vt100.net/docs/vt220-rm/table2-10.html - */ -CHARSETS['K'] = { - '@': '§', - '[': 'Ä', - '\\': 'Ö', - ']': 'Ü', - '{': 'ä', - '|': 'ö', - '}': 'ü', - '~': 'ß' -}; - -/** - * Italian character set - * ESC (Y - * Reference: http://vt100.net/docs/vt220-rm/table2-11.html - */ -CHARSETS['Y'] = { - '#': '£', - '@': '§', - '[': '°', - '\\': 'ç', - ']': 'é', - '`': 'ù', - '{': 'à', - '|': 'ò', - '}': 'è', - '~': 'ì' -}; - -/** - * Norwegian/Danish character set - * ESC (E or ESC (6 - * Reference: http://vt100.net/docs/vt220-rm/table2-12.html - */ -CHARSETS['E'] = -CHARSETS['6'] = { - '@': 'Ä', - '[': 'Æ', - '\\': 'Ø', - ']': 'Å', - '^': 'Ü', - '`': 'ä', - '{': 'æ', - '|': 'ø', - '}': 'å', - '~': 'ü' -}; - -/** - * Spanish character set - * ESC (Z - * Reference: http://vt100.net/docs/vt220-rm/table2-13.html - */ -CHARSETS['Z'] = { - '#': '£', - '@': '§', - '[': '¡', - '\\': 'Ñ', - ']': '¿', - '{': '°', - '|': 'ñ', - '}': 'ç' -}; - -/** - * Swedish character set - * ESC (H or ESC (7 - * Reference: http://vt100.net/docs/vt220-rm/table2-14.html - */ -CHARSETS['H'] = -CHARSETS['7'] = { - '@': 'É', - '[': 'Ä', - '\\': 'Ö', - ']': 'Å', - '^': 'Ü', - '`': 'é', - '{': 'ä', - '|': 'ö', - '}': 'å', - '~': 'ü' -}; - -/** - * Swiss character set - * ESC (= - * Reference: http://vt100.net/docs/vt220-rm/table2-15.html - */ -CHARSETS['='] = { - '#': 'ù', - '@': 'à', - '[': 'é', - '\\': 'ç', - ']': 'ê', - '^': 'î', - // eslint-disable-next-line @typescript-eslint/naming-convention - '_': 'è', - '`': 'ô', - '{': 'ä', - '|': 'ö', - '}': 'ü', - '~': 'û' -}; diff --git a/node_modules/xterm/src/common/data/EscapeSequences.ts b/node_modules/xterm/src/common/data/EscapeSequences.ts deleted file mode 100644 index e35f01d..0000000 --- a/node_modules/xterm/src/common/data/EscapeSequences.ts +++ /dev/null @@ -1,150 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -/** - * C0 control codes - * See = https://en.wikipedia.org/wiki/C0_and_C1_control_codes - */ -export namespace C0 { - /** Null (Caret = ^@, C = \0) */ - export const NUL = '\x00'; - /** Start of Heading (Caret = ^A) */ - export const SOH = '\x01'; - /** Start of Text (Caret = ^B) */ - export const STX = '\x02'; - /** End of Text (Caret = ^C) */ - export const ETX = '\x03'; - /** End of Transmission (Caret = ^D) */ - export const EOT = '\x04'; - /** Enquiry (Caret = ^E) */ - export const ENQ = '\x05'; - /** Acknowledge (Caret = ^F) */ - export const ACK = '\x06'; - /** Bell (Caret = ^G, C = \a) */ - export const BEL = '\x07'; - /** Backspace (Caret = ^H, C = \b) */ - export const BS = '\x08'; - /** Character Tabulation, Horizontal Tabulation (Caret = ^I, C = \t) */ - export const HT = '\x09'; - /** Line Feed (Caret = ^J, C = \n) */ - export const LF = '\x0a'; - /** Line Tabulation, Vertical Tabulation (Caret = ^K, C = \v) */ - export const VT = '\x0b'; - /** Form Feed (Caret = ^L, C = \f) */ - export const FF = '\x0c'; - /** Carriage Return (Caret = ^M, C = \r) */ - export const CR = '\x0d'; - /** Shift Out (Caret = ^N) */ - export const SO = '\x0e'; - /** Shift In (Caret = ^O) */ - export const SI = '\x0f'; - /** Data Link Escape (Caret = ^P) */ - export const DLE = '\x10'; - /** Device Control One (XON) (Caret = ^Q) */ - export const DC1 = '\x11'; - /** Device Control Two (Caret = ^R) */ - export const DC2 = '\x12'; - /** Device Control Three (XOFF) (Caret = ^S) */ - export const DC3 = '\x13'; - /** Device Control Four (Caret = ^T) */ - export const DC4 = '\x14'; - /** Negative Acknowledge (Caret = ^U) */ - export const NAK = '\x15'; - /** Synchronous Idle (Caret = ^V) */ - export const SYN = '\x16'; - /** End of Transmission Block (Caret = ^W) */ - export const ETB = '\x17'; - /** Cancel (Caret = ^X) */ - export const CAN = '\x18'; - /** End of Medium (Caret = ^Y) */ - export const EM = '\x19'; - /** Substitute (Caret = ^Z) */ - export const SUB = '\x1a'; - /** Escape (Caret = ^[, C = \e) */ - export const ESC = '\x1b'; - /** File Separator (Caret = ^\) */ - export const FS = '\x1c'; - /** Group Separator (Caret = ^]) */ - export const GS = '\x1d'; - /** Record Separator (Caret = ^^) */ - export const RS = '\x1e'; - /** Unit Separator (Caret = ^_) */ - export const US = '\x1f'; - /** Space */ - export const SP = '\x20'; - /** Delete (Caret = ^?) */ - export const DEL = '\x7f'; -} - -/** - * C1 control codes - * See = https://en.wikipedia.org/wiki/C0_and_C1_control_codes - */ -export namespace C1 { - /** padding character */ - export const PAD = '\x80'; - /** High Octet Preset */ - export const HOP = '\x81'; - /** Break Permitted Here */ - export const BPH = '\x82'; - /** No Break Here */ - export const NBH = '\x83'; - /** Index */ - export const IND = '\x84'; - /** Next Line */ - export const NEL = '\x85'; - /** Start of Selected Area */ - export const SSA = '\x86'; - /** End of Selected Area */ - export const ESA = '\x87'; - /** Horizontal Tabulation Set */ - export const HTS = '\x88'; - /** Horizontal Tabulation With Justification */ - export const HTJ = '\x89'; - /** Vertical Tabulation Set */ - export const VTS = '\x8a'; - /** Partial Line Down */ - export const PLD = '\x8b'; - /** Partial Line Up */ - export const PLU = '\x8c'; - /** Reverse Index */ - export const RI = '\x8d'; - /** Single-Shift 2 */ - export const SS2 = '\x8e'; - /** Single-Shift 3 */ - export const SS3 = '\x8f'; - /** Device Control String */ - export const DCS = '\x90'; - /** Private Use 1 */ - export const PU1 = '\x91'; - /** Private Use 2 */ - export const PU2 = '\x92'; - /** Set Transmit State */ - export const STS = '\x93'; - /** Destructive backspace, intended to eliminate ambiguity about meaning of BS. */ - export const CCH = '\x94'; - /** Message Waiting */ - export const MW = '\x95'; - /** Start of Protected Area */ - export const SPA = '\x96'; - /** End of Protected Area */ - export const EPA = '\x97'; - /** Start of String */ - export const SOS = '\x98'; - /** Single Graphic Character Introducer */ - export const SGCI = '\x99'; - /** Single Character Introducer */ - export const SCI = '\x9a'; - /** Control Sequence Introducer */ - export const CSI = '\x9b'; - /** String Terminator */ - export const ST = '\x9c'; - /** Operating System Command */ - export const OSC = '\x9d'; - /** Privacy Message */ - export const PM = '\x9e'; - /** Application Program Command */ - export const APC = '\x9f'; -} diff --git a/node_modules/xterm/src/common/input/Keyboard.ts b/node_modules/xterm/src/common/input/Keyboard.ts deleted file mode 100644 index b4b3dce..0000000 --- a/node_modules/xterm/src/common/input/Keyboard.ts +++ /dev/null @@ -1,375 +0,0 @@ -/** - * Copyright (c) 2014 The xterm.js authors. All rights reserved. - * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License) - * @license MIT - */ - -import { IKeyboardEvent, IKeyboardResult, KeyboardResultType } from 'common/Types'; -import { C0 } from 'common/data/EscapeSequences'; - -// reg + shift key mappings for digits and special chars -const KEYCODE_KEY_MAPPINGS: { [key: number]: [string, string]} = { - // digits 0-9 - 48: ['0', ')'], - 49: ['1', '!'], - 50: ['2', '@'], - 51: ['3', '#'], - 52: ['4', '$'], - 53: ['5', '%'], - 54: ['6', '^'], - 55: ['7', '&'], - 56: ['8', '*'], - 57: ['9', '('], - - // special chars - 186: [';', ':'], - 187: ['=', '+'], - 188: [',', '<'], - 189: ['-', '_'], - 190: ['.', '>'], - 191: ['/', '?'], - 192: ['`', '~'], - 219: ['[', '{'], - 220: ['\\', '|'], - 221: [']', '}'], - 222: ['\'', '"'] -}; - -export function evaluateKeyboardEvent( - ev: IKeyboardEvent, - applicationCursorMode: boolean, - isMac: boolean, - macOptionIsMeta: boolean -): IKeyboardResult { - const result: IKeyboardResult = { - type: KeyboardResultType.SEND_KEY, - // Whether to cancel event propagation (NOTE: this may not be needed since the event is - // canceled at the end of keyDown - cancel: false, - // The new key even to emit - key: undefined - }; - const modifiers = (ev.shiftKey ? 1 : 0) | (ev.altKey ? 2 : 0) | (ev.ctrlKey ? 4 : 0) | (ev.metaKey ? 8 : 0); - switch (ev.keyCode) { - case 0: - if (ev.key === 'UIKeyInputUpArrow') { - if (applicationCursorMode) { - result.key = C0.ESC + 'OA'; - } else { - result.key = C0.ESC + '[A'; - } - } - else if (ev.key === 'UIKeyInputLeftArrow') { - if (applicationCursorMode) { - result.key = C0.ESC + 'OD'; - } else { - result.key = C0.ESC + '[D'; - } - } - else if (ev.key === 'UIKeyInputRightArrow') { - if (applicationCursorMode) { - result.key = C0.ESC + 'OC'; - } else { - result.key = C0.ESC + '[C'; - } - } - else if (ev.key === 'UIKeyInputDownArrow') { - if (applicationCursorMode) { - result.key = C0.ESC + 'OB'; - } else { - result.key = C0.ESC + '[B'; - } - } - break; - case 8: - // backspace - if (ev.shiftKey) { - result.key = C0.BS; // ^H - break; - } else if (ev.altKey) { - result.key = C0.ESC + C0.DEL; // \e ^? - break; - } - result.key = C0.DEL; // ^? - break; - case 9: - // tab - if (ev.shiftKey) { - result.key = C0.ESC + '[Z'; - break; - } - result.key = C0.HT; - result.cancel = true; - break; - case 13: - // return/enter - result.key = ev.altKey ? C0.ESC + C0.CR : C0.CR; - result.cancel = true; - break; - case 27: - // escape - result.key = C0.ESC; - if (ev.altKey) { - result.key = C0.ESC + C0.ESC; - } - result.cancel = true; - break; - case 37: - // left-arrow - if (ev.metaKey) { - break; - } - if (modifiers) { - result.key = C0.ESC + '[1;' + (modifiers + 1) + 'D'; - // HACK: Make Alt + left-arrow behave like Ctrl + left-arrow: move one word backwards - // http://unix.stackexchange.com/a/108106 - // macOS uses different escape sequences than linux - if (result.key === C0.ESC + '[1;3D') { - result.key = C0.ESC + (isMac ? 'b' : '[1;5D'); - } - } else if (applicationCursorMode) { - result.key = C0.ESC + 'OD'; - } else { - result.key = C0.ESC + '[D'; - } - break; - case 39: - // right-arrow - if (ev.metaKey) { - break; - } - if (modifiers) { - result.key = C0.ESC + '[1;' + (modifiers + 1) + 'C'; - // HACK: Make Alt + right-arrow behave like Ctrl + right-arrow: move one word forward - // http://unix.stackexchange.com/a/108106 - // macOS uses different escape sequences than linux - if (result.key === C0.ESC + '[1;3C') { - result.key = C0.ESC + (isMac ? 'f' : '[1;5C'); - } - } else if (applicationCursorMode) { - result.key = C0.ESC + 'OC'; - } else { - result.key = C0.ESC + '[C'; - } - break; - case 38: - // up-arrow - if (ev.metaKey) { - break; - } - if (modifiers) { - result.key = C0.ESC + '[1;' + (modifiers + 1) + 'A'; - // HACK: Make Alt + up-arrow behave like Ctrl + up-arrow - // http://unix.stackexchange.com/a/108106 - // macOS uses different escape sequences than linux - if (!isMac && result.key === C0.ESC + '[1;3A') { - result.key = C0.ESC + '[1;5A'; - } - } else if (applicationCursorMode) { - result.key = C0.ESC + 'OA'; - } else { - result.key = C0.ESC + '[A'; - } - break; - case 40: - // down-arrow - if (ev.metaKey) { - break; - } - if (modifiers) { - result.key = C0.ESC + '[1;' + (modifiers + 1) + 'B'; - // HACK: Make Alt + down-arrow behave like Ctrl + down-arrow - // http://unix.stackexchange.com/a/108106 - // macOS uses different escape sequences than linux - if (!isMac && result.key === C0.ESC + '[1;3B') { - result.key = C0.ESC + '[1;5B'; - } - } else if (applicationCursorMode) { - result.key = C0.ESC + 'OB'; - } else { - result.key = C0.ESC + '[B'; - } - break; - case 45: - // insert - if (!ev.shiftKey && !ev.ctrlKey) { - // <Ctrl> or <Shift> + <Insert> are used to - // copy-paste on some systems. - result.key = C0.ESC + '[2~'; - } - break; - case 46: - // delete - if (modifiers) { - result.key = C0.ESC + '[3;' + (modifiers + 1) + '~'; - } else { - result.key = C0.ESC + '[3~'; - } - break; - case 36: - // home - if (modifiers) { - result.key = C0.ESC + '[1;' + (modifiers + 1) + 'H'; - } else if (applicationCursorMode) { - result.key = C0.ESC + 'OH'; - } else { - result.key = C0.ESC + '[H'; - } - break; - case 35: - // end - if (modifiers) { - result.key = C0.ESC + '[1;' + (modifiers + 1) + 'F'; - } else if (applicationCursorMode) { - result.key = C0.ESC + 'OF'; - } else { - result.key = C0.ESC + '[F'; - } - break; - case 33: - // page up - if (ev.shiftKey) { - result.type = KeyboardResultType.PAGE_UP; - } else { - result.key = C0.ESC + '[5~'; - } - break; - case 34: - // page down - if (ev.shiftKey) { - result.type = KeyboardResultType.PAGE_DOWN; - } else { - result.key = C0.ESC + '[6~'; - } - break; - case 112: - // F1-F12 - if (modifiers) { - result.key = C0.ESC + '[1;' + (modifiers + 1) + 'P'; - } else { - result.key = C0.ESC + 'OP'; - } - break; - case 113: - if (modifiers) { - result.key = C0.ESC + '[1;' + (modifiers + 1) + 'Q'; - } else { - result.key = C0.ESC + 'OQ'; - } - break; - case 114: - if (modifiers) { - result.key = C0.ESC + '[1;' + (modifiers + 1) + 'R'; - } else { - result.key = C0.ESC + 'OR'; - } - break; - case 115: - if (modifiers) { - result.key = C0.ESC + '[1;' + (modifiers + 1) + 'S'; - } else { - result.key = C0.ESC + 'OS'; - } - break; - case 116: - if (modifiers) { - result.key = C0.ESC + '[15;' + (modifiers + 1) + '~'; - } else { - result.key = C0.ESC + '[15~'; - } - break; - case 117: - if (modifiers) { - result.key = C0.ESC + '[17;' + (modifiers + 1) + '~'; - } else { - result.key = C0.ESC + '[17~'; - } - break; - case 118: - if (modifiers) { - result.key = C0.ESC + '[18;' + (modifiers + 1) + '~'; - } else { - result.key = C0.ESC + '[18~'; - } - break; - case 119: - if (modifiers) { - result.key = C0.ESC + '[19;' + (modifiers + 1) + '~'; - } else { - result.key = C0.ESC + '[19~'; - } - break; - case 120: - if (modifiers) { - result.key = C0.ESC + '[20;' + (modifiers + 1) + '~'; - } else { - result.key = C0.ESC + '[20~'; - } - break; - case 121: - if (modifiers) { - result.key = C0.ESC + '[21;' + (modifiers + 1) + '~'; - } else { - result.key = C0.ESC + '[21~'; - } - break; - case 122: - if (modifiers) { - result.key = C0.ESC + '[23;' + (modifiers + 1) + '~'; - } else { - result.key = C0.ESC + '[23~'; - } - break; - case 123: - if (modifiers) { - result.key = C0.ESC + '[24;' + (modifiers + 1) + '~'; - } else { - result.key = C0.ESC + '[24~'; - } - break; - default: - // a-z and space - if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) { - if (ev.keyCode >= 65 && ev.keyCode <= 90) { - result.key = String.fromCharCode(ev.keyCode - 64); - } else if (ev.keyCode === 32) { - result.key = C0.NUL; - } else if (ev.keyCode >= 51 && ev.keyCode <= 55) { - // escape, file sep, group sep, record sep, unit sep - result.key = String.fromCharCode(ev.keyCode - 51 + 27); - } else if (ev.keyCode === 56) { - result.key = C0.DEL; - } else if (ev.keyCode === 219) { - result.key = C0.ESC; - } else if (ev.keyCode === 220) { - result.key = C0.FS; - } else if (ev.keyCode === 221) { - result.key = C0.GS; - } - } else if ((!isMac || macOptionIsMeta) && ev.altKey && !ev.metaKey) { - // On macOS this is a third level shift when !macOptionIsMeta. Use <Esc> instead. - const keyMapping = KEYCODE_KEY_MAPPINGS[ev.keyCode]; - const key = keyMapping?.[!ev.shiftKey ? 0 : 1]; - if (key) { - result.key = C0.ESC + key; - } else if (ev.keyCode >= 65 && ev.keyCode <= 90) { - const keyCode = ev.ctrlKey ? ev.keyCode - 64 : ev.keyCode + 32; - result.key = C0.ESC + String.fromCharCode(keyCode); - } - } else if (isMac && !ev.altKey && !ev.ctrlKey && !ev.shiftKey && ev.metaKey) { - if (ev.keyCode === 65) { // cmd + a - result.type = KeyboardResultType.SELECT_ALL; - } - } else if (ev.key && !ev.ctrlKey && !ev.altKey && !ev.metaKey && ev.keyCode >= 48 && ev.key.length === 1) { - // Include only keys that that result in a _single_ character; don't include num lock, volume up, etc. - result.key = ev.key; - } else if (ev.key && ev.ctrlKey) { - if (ev.key === '_') { // ^_ - result.key = C0.US; - } - } - break; - } - - return result; -} diff --git a/node_modules/xterm/src/common/input/TextDecoder.ts b/node_modules/xterm/src/common/input/TextDecoder.ts deleted file mode 100644 index 715e919..0000000 --- a/node_modules/xterm/src/common/input/TextDecoder.ts +++ /dev/null @@ -1,346 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -/** - * Polyfill - Convert UTF32 codepoint into JS string. - * Note: The built-in String.fromCodePoint happens to be much slower - * due to additional sanity checks. We can avoid them since - * we always operate on legal UTF32 (granted by the input decoders) - * and use this faster version instead. - */ -export function stringFromCodePoint(codePoint: number): string { - if (codePoint > 0xFFFF) { - codePoint -= 0x10000; - return String.fromCharCode((codePoint >> 10) + 0xD800) + String.fromCharCode((codePoint % 0x400) + 0xDC00); - } - return String.fromCharCode(codePoint); -} - -/** - * Convert UTF32 char codes into JS string. - * Basically the same as `stringFromCodePoint` but for multiple codepoints - * in a loop (which is a lot faster). - */ -export function utf32ToString(data: Uint32Array, start: number = 0, end: number = data.length): string { - let result = ''; - for (let i = start; i < end; ++i) { - let codepoint = data[i]; - if (codepoint > 0xFFFF) { - // JS strings are encoded as UTF16, thus a non BMP codepoint gets converted into a surrogate pair - // conversion rules: - // - subtract 0x10000 from code point, leaving a 20 bit number - // - add high 10 bits to 0xD800 --> first surrogate - // - add low 10 bits to 0xDC00 --> second surrogate - codepoint -= 0x10000; - result += String.fromCharCode((codepoint >> 10) + 0xD800) + String.fromCharCode((codepoint % 0x400) + 0xDC00); - } else { - result += String.fromCharCode(codepoint); - } - } - return result; -} - -/** - * StringToUtf32 - decodes UTF16 sequences into UTF32 codepoints. - * To keep the decoder in line with JS strings it handles single surrogates as UCS2. - */ -export class StringToUtf32 { - private _interim: number = 0; - - /** - * Clears interim and resets decoder to clean state. - */ - public clear(): void { - this._interim = 0; - } - - /** - * Decode JS string to UTF32 codepoints. - * The methods assumes stream input and will store partly transmitted - * surrogate pairs and decode them with the next data chunk. - * Note: The method does no bound checks for target, therefore make sure - * the provided input data does not exceed the size of `target`. - * Returns the number of written codepoints in `target`. - */ - public decode(input: string, target: Uint32Array): number { - const length = input.length; - - if (!length) { - return 0; - } - - let size = 0; - let startPos = 0; - - // handle leftover surrogate high - if (this._interim) { - const second = input.charCodeAt(startPos++); - if (0xDC00 <= second && second <= 0xDFFF) { - target[size++] = (this._interim - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; - } else { - // illegal codepoint (USC2 handling) - target[size++] = this._interim; - target[size++] = second; - } - this._interim = 0; - } - - for (let i = startPos; i < length; ++i) { - const code = input.charCodeAt(i); - // surrogate pair first - if (0xD800 <= code && code <= 0xDBFF) { - if (++i >= length) { - this._interim = code; - return size; - } - const second = input.charCodeAt(i); - if (0xDC00 <= second && second <= 0xDFFF) { - target[size++] = (code - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; - } else { - // illegal codepoint (USC2 handling) - target[size++] = code; - target[size++] = second; - } - continue; - } - if (code === 0xFEFF) { - // BOM - continue; - } - target[size++] = code; - } - return size; - } -} - -/** - * Utf8Decoder - decodes UTF8 byte sequences into UTF32 codepoints. - */ -export class Utf8ToUtf32 { - public interim: Uint8Array = new Uint8Array(3); - - /** - * Clears interim bytes and resets decoder to clean state. - */ - public clear(): void { - this.interim.fill(0); - } - - /** - * Decodes UTF8 byte sequences in `input` to UTF32 codepoints in `target`. - * The methods assumes stream input and will store partly transmitted bytes - * and decode them with the next data chunk. - * Note: The method does no bound checks for target, therefore make sure - * the provided data chunk does not exceed the size of `target`. - * Returns the number of written codepoints in `target`. - */ - public decode(input: Uint8Array, target: Uint32Array): number { - const length = input.length; - - if (!length) { - return 0; - } - - let size = 0; - let byte1: number; - let byte2: number; - let byte3: number; - let byte4: number; - let codepoint = 0; - let startPos = 0; - - // handle leftover bytes - if (this.interim[0]) { - let discardInterim = false; - let cp = this.interim[0]; - cp &= ((((cp & 0xE0) === 0xC0)) ? 0x1F : (((cp & 0xF0) === 0xE0)) ? 0x0F : 0x07); - let pos = 0; - let tmp: number; - while ((tmp = this.interim[++pos] & 0x3F) && pos < 4) { - cp <<= 6; - cp |= tmp; - } - // missing bytes - read ahead from input - const type = (((this.interim[0] & 0xE0) === 0xC0)) ? 2 : (((this.interim[0] & 0xF0) === 0xE0)) ? 3 : 4; - const missing = type - pos; - while (startPos < missing) { - if (startPos >= length) { - return 0; - } - tmp = input[startPos++]; - if ((tmp & 0xC0) !== 0x80) { - // wrong continuation, discard interim bytes completely - startPos--; - discardInterim = true; - break; - } else { - // need to save so we can continue short inputs in next call - this.interim[pos++] = tmp; - cp <<= 6; - cp |= tmp & 0x3F; - } - } - if (!discardInterim) { - // final test is type dependent - if (type === 2) { - if (cp < 0x80) { - // wrong starter byte - startPos--; - } else { - target[size++] = cp; - } - } else if (type === 3) { - if (cp < 0x0800 || (cp >= 0xD800 && cp <= 0xDFFF) || cp === 0xFEFF) { - // illegal codepoint or BOM - } else { - target[size++] = cp; - } - } else { - if (cp < 0x010000 || cp > 0x10FFFF) { - // illegal codepoint - } else { - target[size++] = cp; - } - } - } - this.interim.fill(0); - } - - // loop through input - const fourStop = length - 4; - let i = startPos; - while (i < length) { - /** - * ASCII shortcut with loop unrolled to 4 consecutive ASCII chars. - * This is a compromise between speed gain for ASCII - * and penalty for non ASCII: - * For best ASCII performance the char should be stored directly into target, - * but even a single attempt to write to target and compare afterwards - * penalizes non ASCII really bad (-50%), thus we load the char into byteX first, - * which reduces ASCII performance by ~15%. - * This trial for ASCII reduces non ASCII performance by ~10% which seems acceptible - * compared to the gains. - * Note that this optimization only takes place for 4 consecutive ASCII chars, - * for any shorter it bails out. Worst case - all 4 bytes being read but - * thrown away due to the last being a non ASCII char (-10% performance). - */ - while (i < fourStop - && !((byte1 = input[i]) & 0x80) - && !((byte2 = input[i + 1]) & 0x80) - && !((byte3 = input[i + 2]) & 0x80) - && !((byte4 = input[i + 3]) & 0x80)) - { - target[size++] = byte1; - target[size++] = byte2; - target[size++] = byte3; - target[size++] = byte4; - i += 4; - } - - // reread byte1 - byte1 = input[i++]; - - // 1 byte - if (byte1 < 0x80) { - target[size++] = byte1; - - // 2 bytes - } else if ((byte1 & 0xE0) === 0xC0) { - if (i >= length) { - this.interim[0] = byte1; - return size; - } - byte2 = input[i++]; - if ((byte2 & 0xC0) !== 0x80) { - // wrong continuation - i--; - continue; - } - codepoint = (byte1 & 0x1F) << 6 | (byte2 & 0x3F); - if (codepoint < 0x80) { - // wrong starter byte - i--; - continue; - } - target[size++] = codepoint; - - // 3 bytes - } else if ((byte1 & 0xF0) === 0xE0) { - if (i >= length) { - this.interim[0] = byte1; - return size; - } - byte2 = input[i++]; - if ((byte2 & 0xC0) !== 0x80) { - // wrong continuation - i--; - continue; - } - if (i >= length) { - this.interim[0] = byte1; - this.interim[1] = byte2; - return size; - } - byte3 = input[i++]; - if ((byte3 & 0xC0) !== 0x80) { - // wrong continuation - i--; - continue; - } - codepoint = (byte1 & 0x0F) << 12 | (byte2 & 0x3F) << 6 | (byte3 & 0x3F); - if (codepoint < 0x0800 || (codepoint >= 0xD800 && codepoint <= 0xDFFF) || codepoint === 0xFEFF) { - // illegal codepoint or BOM, no i-- here - continue; - } - target[size++] = codepoint; - - // 4 bytes - } else if ((byte1 & 0xF8) === 0xF0) { - if (i >= length) { - this.interim[0] = byte1; - return size; - } - byte2 = input[i++]; - if ((byte2 & 0xC0) !== 0x80) { - // wrong continuation - i--; - continue; - } - if (i >= length) { - this.interim[0] = byte1; - this.interim[1] = byte2; - return size; - } - byte3 = input[i++]; - if ((byte3 & 0xC0) !== 0x80) { - // wrong continuation - i--; - continue; - } - if (i >= length) { - this.interim[0] = byte1; - this.interim[1] = byte2; - this.interim[2] = byte3; - return size; - } - byte4 = input[i++]; - if ((byte4 & 0xC0) !== 0x80) { - // wrong continuation - i--; - continue; - } - codepoint = (byte1 & 0x07) << 18 | (byte2 & 0x3F) << 12 | (byte3 & 0x3F) << 6 | (byte4 & 0x3F); - if (codepoint < 0x010000 || codepoint > 0x10FFFF) { - // illegal codepoint, no i-- here - continue; - } - target[size++] = codepoint; - } else { - // illegal byte, just skip - } - } - return size; - } -} diff --git a/node_modules/xterm/src/common/input/UnicodeV6.ts b/node_modules/xterm/src/common/input/UnicodeV6.ts deleted file mode 100644 index b308203..0000000 --- a/node_modules/xterm/src/common/input/UnicodeV6.ts +++ /dev/null @@ -1,133 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ -import { IUnicodeVersionProvider } from 'common/services/Services'; -import { fill } from 'common/TypedArrayUtils'; - -type CharWidth = 0 | 1 | 2; - -const BMP_COMBINING = [ - [0x0300, 0x036F], [0x0483, 0x0486], [0x0488, 0x0489], - [0x0591, 0x05BD], [0x05BF, 0x05BF], [0x05C1, 0x05C2], - [0x05C4, 0x05C5], [0x05C7, 0x05C7], [0x0600, 0x0603], - [0x0610, 0x0615], [0x064B, 0x065E], [0x0670, 0x0670], - [0x06D6, 0x06E4], [0x06E7, 0x06E8], [0x06EA, 0x06ED], - [0x070F, 0x070F], [0x0711, 0x0711], [0x0730, 0x074A], - [0x07A6, 0x07B0], [0x07EB, 0x07F3], [0x0901, 0x0902], - [0x093C, 0x093C], [0x0941, 0x0948], [0x094D, 0x094D], - [0x0951, 0x0954], [0x0962, 0x0963], [0x0981, 0x0981], - [0x09BC, 0x09BC], [0x09C1, 0x09C4], [0x09CD, 0x09CD], - [0x09E2, 0x09E3], [0x0A01, 0x0A02], [0x0A3C, 0x0A3C], - [0x0A41, 0x0A42], [0x0A47, 0x0A48], [0x0A4B, 0x0A4D], - [0x0A70, 0x0A71], [0x0A81, 0x0A82], [0x0ABC, 0x0ABC], - [0x0AC1, 0x0AC5], [0x0AC7, 0x0AC8], [0x0ACD, 0x0ACD], - [0x0AE2, 0x0AE3], [0x0B01, 0x0B01], [0x0B3C, 0x0B3C], - [0x0B3F, 0x0B3F], [0x0B41, 0x0B43], [0x0B4D, 0x0B4D], - [0x0B56, 0x0B56], [0x0B82, 0x0B82], [0x0BC0, 0x0BC0], - [0x0BCD, 0x0BCD], [0x0C3E, 0x0C40], [0x0C46, 0x0C48], - [0x0C4A, 0x0C4D], [0x0C55, 0x0C56], [0x0CBC, 0x0CBC], - [0x0CBF, 0x0CBF], [0x0CC6, 0x0CC6], [0x0CCC, 0x0CCD], - [0x0CE2, 0x0CE3], [0x0D41, 0x0D43], [0x0D4D, 0x0D4D], - [0x0DCA, 0x0DCA], [0x0DD2, 0x0DD4], [0x0DD6, 0x0DD6], - [0x0E31, 0x0E31], [0x0E34, 0x0E3A], [0x0E47, 0x0E4E], - [0x0EB1, 0x0EB1], [0x0EB4, 0x0EB9], [0x0EBB, 0x0EBC], - [0x0EC8, 0x0ECD], [0x0F18, 0x0F19], [0x0F35, 0x0F35], - [0x0F37, 0x0F37], [0x0F39, 0x0F39], [0x0F71, 0x0F7E], - [0x0F80, 0x0F84], [0x0F86, 0x0F87], [0x0F90, 0x0F97], - [0x0F99, 0x0FBC], [0x0FC6, 0x0FC6], [0x102D, 0x1030], - [0x1032, 0x1032], [0x1036, 0x1037], [0x1039, 0x1039], - [0x1058, 0x1059], [0x1160, 0x11FF], [0x135F, 0x135F], - [0x1712, 0x1714], [0x1732, 0x1734], [0x1752, 0x1753], - [0x1772, 0x1773], [0x17B4, 0x17B5], [0x17B7, 0x17BD], - [0x17C6, 0x17C6], [0x17C9, 0x17D3], [0x17DD, 0x17DD], - [0x180B, 0x180D], [0x18A9, 0x18A9], [0x1920, 0x1922], - [0x1927, 0x1928], [0x1932, 0x1932], [0x1939, 0x193B], - [0x1A17, 0x1A18], [0x1B00, 0x1B03], [0x1B34, 0x1B34], - [0x1B36, 0x1B3A], [0x1B3C, 0x1B3C], [0x1B42, 0x1B42], - [0x1B6B, 0x1B73], [0x1DC0, 0x1DCA], [0x1DFE, 0x1DFF], - [0x200B, 0x200F], [0x202A, 0x202E], [0x2060, 0x2063], - [0x206A, 0x206F], [0x20D0, 0x20EF], [0x302A, 0x302F], - [0x3099, 0x309A], [0xA806, 0xA806], [0xA80B, 0xA80B], - [0xA825, 0xA826], [0xFB1E, 0xFB1E], [0xFE00, 0xFE0F], - [0xFE20, 0xFE23], [0xFEFF, 0xFEFF], [0xFFF9, 0xFFFB] -]; -const HIGH_COMBINING = [ - [0x10A01, 0x10A03], [0x10A05, 0x10A06], [0x10A0C, 0x10A0F], - [0x10A38, 0x10A3A], [0x10A3F, 0x10A3F], [0x1D167, 0x1D169], - [0x1D173, 0x1D182], [0x1D185, 0x1D18B], [0x1D1AA, 0x1D1AD], - [0x1D242, 0x1D244], [0xE0001, 0xE0001], [0xE0020, 0xE007F], - [0xE0100, 0xE01EF] -]; - -// BMP lookup table, lazy initialized during first addon loading -let table: Uint8Array; - -function bisearch(ucs: number, data: number[][]): boolean { - let min = 0; - let max = data.length - 1; - let mid; - if (ucs < data[0][0] || ucs > data[max][1]) { - return false; - } - while (max >= min) { - mid = (min + max) >> 1; - if (ucs > data[mid][1]) { - min = mid + 1; - } else if (ucs < data[mid][0]) { - max = mid - 1; - } else { - return true; - } - } - return false; -} - -export class UnicodeV6 implements IUnicodeVersionProvider { - public readonly version = '6'; - - constructor() { - // init lookup table once - if (!table) { - table = new Uint8Array(65536); - fill(table, 1); - table[0] = 0; - // control chars - fill(table, 0, 1, 32); - fill(table, 0, 0x7f, 0xa0); - - // apply wide char rules first - // wide chars - fill(table, 2, 0x1100, 0x1160); - table[0x2329] = 2; - table[0x232a] = 2; - fill(table, 2, 0x2e80, 0xa4d0); - table[0x303f] = 1; // wrongly in last line - - fill(table, 2, 0xac00, 0xd7a4); - fill(table, 2, 0xf900, 0xfb00); - fill(table, 2, 0xfe10, 0xfe1a); - fill(table, 2, 0xfe30, 0xfe70); - fill(table, 2, 0xff00, 0xff61); - fill(table, 2, 0xffe0, 0xffe7); - - // apply combining last to ensure we overwrite - // wrongly wide set chars: - // the original algo evals combining first and falls - // through to wide check so we simply do here the opposite - // combining 0 - for (let r = 0; r < BMP_COMBINING.length; ++r) { - fill(table, 0, BMP_COMBINING[r][0], BMP_COMBINING[r][1] + 1); - } - } - } - - public wcwidth(num: number): CharWidth { - if (num < 32) return 0; - if (num < 127) return 1; - if (num < 65536) return table[num] as CharWidth; - if (bisearch(num, HIGH_COMBINING)) return 0; - if ((num >= 0x20000 && num <= 0x2fffd) || (num >= 0x30000 && num <= 0x3fffd)) return 2; - return 1; - } -} diff --git a/node_modules/xterm/src/common/input/WriteBuffer.ts b/node_modules/xterm/src/common/input/WriteBuffer.ts deleted file mode 100644 index cc84c9a..0000000 --- a/node_modules/xterm/src/common/input/WriteBuffer.ts +++ /dev/null @@ -1,224 +0,0 @@ - -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -declare const setTimeout: (handler: () => void, timeout?: number) => void; - -/** - * Safety watermark to avoid memory exhaustion and browser engine crash on fast data input. - * Enable flow control to avoid this limit and make sure that your backend correctly - * propagates this to the underlying pty. (see docs for further instructions) - * Since this limit is meant as a safety parachute to prevent browser crashs, - * it is set to a very high number. Typically xterm.js gets unresponsive with - * a 100 times lower number (>500 kB). - */ -const DISCARD_WATERMARK = 50000000; // ~50 MB - -/** - * The max number of ms to spend on writes before allowing the renderer to - * catch up with a 0ms setTimeout. A value of < 33 to keep us close to - * 30fps, and a value of < 16 to try to run at 60fps. Of course, the real FPS - * depends on the time it takes for the renderer to draw the frame. - */ -const WRITE_TIMEOUT_MS = 12; - -/** - * Threshold of max held chunks in the write buffer, that were already processed. - * This is a tradeoff between extensive write buffer shifts (bad runtime) and high - * memory consumption by data thats not used anymore. - */ -const WRITE_BUFFER_LENGTH_THRESHOLD = 50; - -// queueMicrotask polyfill for nodejs < v11 -const qmt: (cb: () => void) => void = (typeof queueMicrotask === 'undefined') - ? (cb: () => void) => { Promise.resolve().then(cb); } - : queueMicrotask; - - -export class WriteBuffer { - private _writeBuffer: (string | Uint8Array)[] = []; - private _callbacks: ((() => void) | undefined)[] = []; - private _pendingData = 0; - private _bufferOffset = 0; - private _isSyncWriting = false; - private _syncCalls = 0; - - constructor(private _action: (data: string | Uint8Array, promiseResult?: boolean) => void | Promise<boolean>) { } - - /** - * @deprecated Unreliable, to be removed soon. - */ - public writeSync(data: string | Uint8Array, maxSubsequentCalls?: number): void { - // stop writeSync recursions with maxSubsequentCalls argument - // This is dangerous to use as it will lose the current data chunk - // and return immediately. - if (maxSubsequentCalls !== undefined && this._syncCalls > maxSubsequentCalls) { - // comment next line if a whole loop block should only contain x `writeSync` calls - // (total flat vs. deep nested limit) - this._syncCalls = 0; - return; - } - // append chunk to buffer - this._pendingData += data.length; - this._writeBuffer.push(data); - this._callbacks.push(undefined); - - // increase recursion counter - this._syncCalls++; - // exit early if another writeSync loop is active - if (this._isSyncWriting) { - return; - } - this._isSyncWriting = true; - - // force sync processing on pending data chunks to avoid in-band data scrambling - // does the same as innerWrite but without event loop - // we have to do it here as single loop steps to not corrupt loop subject - // by another writeSync call triggered from _action - let chunk: string | Uint8Array | undefined; - while (chunk = this._writeBuffer.shift()) { - this._action(chunk); - const cb = this._callbacks.shift(); - if (cb) cb(); - } - // reset to avoid reprocessing of chunks with scheduled innerWrite call - // stopping scheduled innerWrite by offset > length condition - this._pendingData = 0; - this._bufferOffset = 0x7FFFFFFF; - - // allow another writeSync to loop - this._isSyncWriting = false; - this._syncCalls = 0; - } - - public write(data: string | Uint8Array, callback?: () => void): void { - if (this._pendingData > DISCARD_WATERMARK) { - throw new Error('write data discarded, use flow control to avoid losing data'); - } - - // schedule chunk processing for next event loop run - if (!this._writeBuffer.length) { - this._bufferOffset = 0; - setTimeout(() => this._innerWrite()); - } - - this._pendingData += data.length; - this._writeBuffer.push(data); - this._callbacks.push(callback); - } - - /** - * Inner write call, that enters the sliced chunk processing by timing. - * - * `lastTime` indicates, when the last _innerWrite call had started. - * It is used to aggregate async handler execution under a timeout constraint - * effectively lowering the redrawing needs, schematically: - * - * macroTask _innerWrite: - * if (Date.now() - (lastTime | 0) < WRITE_TIMEOUT_MS): - * schedule microTask _innerWrite(lastTime) - * else: - * schedule macroTask _innerWrite(0) - * - * overall execution order on task queues: - * - * macrotasks: [...] --> _innerWrite(0) --> [...] --> screenUpdate --> [...] - * m t: | - * i a: [...] - * c s: | - * r k: while < timeout: - * o s: _innerWrite(timeout) - * - * `promiseResult` depicts the promise resolve value of an async handler. - * This value gets carried forward through all saved stack states of the - * paused parser for proper continuation. - * - * Note, for pure sync code `lastTime` and `promiseResult` have no meaning. - */ - protected _innerWrite(lastTime: number = 0, promiseResult: boolean = true): void { - const startTime = lastTime || Date.now(); - while (this._writeBuffer.length > this._bufferOffset) { - const data = this._writeBuffer[this._bufferOffset]; - const result = this._action(data, promiseResult); - if (result) { - /** - * If we get a promise as return value, we re-schedule the continuation - * as thenable on the promise and exit right away. - * - * The exit here means, that we block input processing at the current active chunk, - * the exact execution position within the chunk is preserved by the saved - * stack content in InputHandler and EscapeSequenceParser. - * - * Resuming happens automatically from that saved stack state. - * Also the resolved promise value is passed along the callstack to - * `EscapeSequenceParser.parse` to correctly resume the stopped handler loop. - * - * Exceptions on async handlers will be logged to console async, but do not interrupt - * the input processing (continues with next handler at the current input position). - */ - - /** - * If a promise takes long to resolve, we should schedule continuation behind setTimeout. - * This might already be too late, if our .then enters really late (executor + prev thens took very long). - * This cannot be solved here for the handler itself (it is the handlers responsibility to slice hard work), - * but we can at least schedule a screen update as we gain control. - */ - const continuation: (r: boolean) => void = (r: boolean) => Date.now() - startTime >= WRITE_TIMEOUT_MS - ? setTimeout(() => this._innerWrite(0, r)) - : this._innerWrite(startTime, r); - - /** - * Optimization considerations: - * The continuation above favors FPS over throughput by eval'ing `startTime` on resolve. - * This might schedule too many screen updates with bad throughput drops (in case a slow - * resolving handler sliced its work properly behind setTimeout calls). We cannot spot - * this condition here, also the renderer has no way to spot nonsense updates either. - * FIXME: A proper fix for this would track the FPS at the renderer entry level separately. - * - * If favoring of FPS shows bad throughtput impact, use the following instead. It favors - * throughput by eval'ing `startTime` upfront pulling at least one more chunk into the - * current microtask queue (executed before setTimeout). - */ - // const continuation: (r: boolean) => void = Date.now() - startTime >= WRITE_TIMEOUT_MS - // ? r => setTimeout(() => this._innerWrite(0, r)) - // : r => this._innerWrite(startTime, r); - - // Handle exceptions synchronously to current band position, idea: - // 1. spawn a single microtask which we allow to throw hard - // 2. spawn a promise immediately resolving to `true` - // (executed on the same queue, thus properly aligned before continuation happens) - result.catch(err => { - qmt(() => {throw err;}); - return Promise.resolve(false); - }).then(continuation); - return; - } - - const cb = this._callbacks[this._bufferOffset]; - if (cb) cb(); - this._bufferOffset++; - this._pendingData -= data.length; - - if (Date.now() - startTime >= WRITE_TIMEOUT_MS) { - break; - } - } - if (this._writeBuffer.length > this._bufferOffset) { - // Allow renderer to catch up before processing the next batch - // trim already processed chunks if we are above threshold - if (this._bufferOffset > WRITE_BUFFER_LENGTH_THRESHOLD) { - this._writeBuffer = this._writeBuffer.slice(this._bufferOffset); - this._callbacks = this._callbacks.slice(this._bufferOffset); - this._bufferOffset = 0; - } - setTimeout(() => this._innerWrite()); - } else { - this._writeBuffer.length = 0; - this._callbacks.length = 0; - this._pendingData = 0; - this._bufferOffset = 0; - } - } -} diff --git a/node_modules/xterm/src/common/input/XParseColor.ts b/node_modules/xterm/src/common/input/XParseColor.ts deleted file mode 100644 index 8c023a3..0000000 --- a/node_modules/xterm/src/common/input/XParseColor.ts +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Copyright (c) 2021 The xterm.js authors. All rights reserved. - * @license MIT - */ - - -// 'rgb:' rule - matching: r/g/b | rr/gg/bb | rrr/ggg/bbb | rrrr/gggg/bbbb (hex digits) -const RGB_REX = /^([\da-f]{1})\/([\da-f]{1})\/([\da-f]{1})$|^([\da-f]{2})\/([\da-f]{2})\/([\da-f]{2})$|^([\da-f]{3})\/([\da-f]{3})\/([\da-f]{3})$|^([\da-f]{4})\/([\da-f]{4})\/([\da-f]{4})$/; -// '#...' rule - matching any hex digits -const HASH_REX = /^[\da-f]+$/; - -/** - * Parse color spec to RGB values (8 bit per channel). - * See `man xparsecolor` for details about certain format specifications. - * - * Supported formats: - * - rgb:<red>/<green>/<blue> with <red>, <green>, <blue> in h | hh | hhh | hhhh - * - #RGB, #RRGGBB, #RRRGGGBBB, #RRRRGGGGBBBB - * - * All other formats like rgbi: or device-independent string specifications - * with float numbering are not supported. - */ -export function parseColor(data: string): [number, number, number] | undefined { - if (!data) return; - // also handle uppercases - let low = data.toLowerCase(); - if (low.indexOf('rgb:') === 0) { - // 'rgb:' specifier - low = low.slice(4); - const m = RGB_REX.exec(low); - if (m) { - const base = m[1] ? 15 : m[4] ? 255 : m[7] ? 4095 : 65535; - return [ - Math.round(parseInt(m[1] || m[4] || m[7] || m[10], 16) / base * 255), - Math.round(parseInt(m[2] || m[5] || m[8] || m[11], 16) / base * 255), - Math.round(parseInt(m[3] || m[6] || m[9] || m[12], 16) / base * 255) - ]; - } - } else if (low.indexOf('#') === 0) { - // '#' specifier - low = low.slice(1); - if (HASH_REX.exec(low) && [3, 6, 9, 12].includes(low.length)) { - const adv = low.length / 3; - const result: [number, number, number] = [0, 0, 0]; - for (let i = 0; i < 3; ++i) { - const c = parseInt(low.slice(adv * i, adv * i + adv), 16); - result[i] = adv === 1 ? c << 4 : adv === 2 ? c : adv === 3 ? c >> 4 : c >> 8; - } - return result; - } - } - - // Named colors are currently not supported due to the large addition to the xterm.js bundle size - // they would add. In order to support named colors, we would need some way of optionally loading - // additional payloads so startup/download time is not bloated (see #3530). -} - -// pad hex output to requested bit width -function pad(n: number, bits: number): string { - const s = n.toString(16); - const s2 = s.length < 2 ? '0' + s : s; - switch (bits) { - case 4: - return s[0]; - case 8: - return s2; - case 12: - return (s2 + s2).slice(0, 3); - default: - return s2 + s2; - } -} - -/** - * Convert a given color to rgb:../../.. string of `bits` depth. - */ -export function toRgbString(color: [number, number, number], bits: number = 16): string { - const [r, g, b] = color; - return `rgb:${pad(r, bits)}/${pad(g, bits)}/${pad(b, bits)}`; -} diff --git a/node_modules/xterm/src/common/parser/Constants.ts b/node_modules/xterm/src/common/parser/Constants.ts deleted file mode 100644 index 85156c3..0000000 --- a/node_modules/xterm/src/common/parser/Constants.ts +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -/** - * Internal states of EscapeSequenceParser. - */ -export const enum ParserState { - GROUND = 0, - ESCAPE = 1, - ESCAPE_INTERMEDIATE = 2, - CSI_ENTRY = 3, - CSI_PARAM = 4, - CSI_INTERMEDIATE = 5, - CSI_IGNORE = 6, - SOS_PM_APC_STRING = 7, - OSC_STRING = 8, - DCS_ENTRY = 9, - DCS_PARAM = 10, - DCS_IGNORE = 11, - DCS_INTERMEDIATE = 12, - DCS_PASSTHROUGH = 13 -} - -/** -* Internal actions of EscapeSequenceParser. -*/ -export const enum ParserAction { - IGNORE = 0, - ERROR = 1, - PRINT = 2, - EXECUTE = 3, - OSC_START = 4, - OSC_PUT = 5, - OSC_END = 6, - CSI_DISPATCH = 7, - PARAM = 8, - COLLECT = 9, - ESC_DISPATCH = 10, - CLEAR = 11, - DCS_HOOK = 12, - DCS_PUT = 13, - DCS_UNHOOK = 14 -} - -/** - * Internal states of OscParser. - */ -export const enum OscState { - START = 0, - ID = 1, - PAYLOAD = 2, - ABORT = 3 -} - -// payload limit for OSC and DCS -export const PAYLOAD_LIMIT = 10000000; diff --git a/node_modules/xterm/src/common/parser/DcsParser.ts b/node_modules/xterm/src/common/parser/DcsParser.ts deleted file mode 100644 index b66524b..0000000 --- a/node_modules/xterm/src/common/parser/DcsParser.ts +++ /dev/null @@ -1,192 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IDisposable } from 'common/Types'; -import { IDcsHandler, IParams, IHandlerCollection, IDcsParser, DcsFallbackHandlerType, ISubParserStackState } from 'common/parser/Types'; -import { utf32ToString } from 'common/input/TextDecoder'; -import { Params } from 'common/parser/Params'; -import { PAYLOAD_LIMIT } from 'common/parser/Constants'; - -const EMPTY_HANDLERS: IDcsHandler[] = []; - -export class DcsParser implements IDcsParser { - private _handlers: IHandlerCollection<IDcsHandler> = Object.create(null); - private _active: IDcsHandler[] = EMPTY_HANDLERS; - private _ident: number = 0; - private _handlerFb: DcsFallbackHandlerType = () => { }; - private _stack: ISubParserStackState = { - paused: false, - loopPosition: 0, - fallThrough: false - }; - - public dispose(): void { - this._handlers = Object.create(null); - this._handlerFb = () => { }; - this._active = EMPTY_HANDLERS; - } - - public registerHandler(ident: number, handler: IDcsHandler): IDisposable { - if (this._handlers[ident] === undefined) { - this._handlers[ident] = []; - } - const handlerList = this._handlers[ident]; - handlerList.push(handler); - return { - dispose: () => { - const handlerIndex = handlerList.indexOf(handler); - if (handlerIndex !== -1) { - handlerList.splice(handlerIndex, 1); - } - } - }; - } - - public clearHandler(ident: number): void { - if (this._handlers[ident]) delete this._handlers[ident]; - } - - public setHandlerFallback(handler: DcsFallbackHandlerType): void { - this._handlerFb = handler; - } - - public reset(): void { - // force cleanup leftover handlers - if (this._active.length) { - for (let j = this._stack.paused ? this._stack.loopPosition - 1 : this._active.length - 1; j >= 0; --j) { - this._active[j].unhook(false); - } - } - this._stack.paused = false; - this._active = EMPTY_HANDLERS; - this._ident = 0; - } - - public hook(ident: number, params: IParams): void { - // always reset leftover handlers - this.reset(); - this._ident = ident; - this._active = this._handlers[ident] || EMPTY_HANDLERS; - if (!this._active.length) { - this._handlerFb(this._ident, 'HOOK', params); - } else { - for (let j = this._active.length - 1; j >= 0; j--) { - this._active[j].hook(params); - } - } - } - - public put(data: Uint32Array, start: number, end: number): void { - if (!this._active.length) { - this._handlerFb(this._ident, 'PUT', utf32ToString(data, start, end)); - } else { - for (let j = this._active.length - 1; j >= 0; j--) { - this._active[j].put(data, start, end); - } - } - } - - public unhook(success: boolean, promiseResult: boolean = true): void | Promise<boolean> { - if (!this._active.length) { - this._handlerFb(this._ident, 'UNHOOK', success); - } else { - let handlerResult: boolean | Promise<boolean> = false; - let j = this._active.length - 1; - let fallThrough = false; - if (this._stack.paused) { - j = this._stack.loopPosition - 1; - handlerResult = promiseResult; - fallThrough = this._stack.fallThrough; - this._stack.paused = false; - } - if (!fallThrough && handlerResult === false) { - for (; j >= 0; j--) { - handlerResult = this._active[j].unhook(success); - if (handlerResult === true) { - break; - } else if (handlerResult instanceof Promise) { - this._stack.paused = true; - this._stack.loopPosition = j; - this._stack.fallThrough = false; - return handlerResult; - } - } - j--; - } - // cleanup left over handlers (fallThrough for async) - for (; j >= 0; j--) { - handlerResult = this._active[j].unhook(false); - if (handlerResult instanceof Promise) { - this._stack.paused = true; - this._stack.loopPosition = j; - this._stack.fallThrough = true; - return handlerResult; - } - } - } - this._active = EMPTY_HANDLERS; - this._ident = 0; - } -} - -// predefine empty params as [0] (ZDM) -const EMPTY_PARAMS = new Params(); -EMPTY_PARAMS.addParam(0); - -/** - * Convenient class to create a DCS handler from a single callback function. - * Note: The payload is currently limited to 50 MB (hardcoded). - */ -export class DcsHandler implements IDcsHandler { - private _data = ''; - private _params: IParams = EMPTY_PARAMS; - private _hitLimit: boolean = false; - - constructor(private _handler: (data: string, params: IParams) => boolean | Promise<boolean>) { } - - public hook(params: IParams): void { - // since we need to preserve params until `unhook`, we have to clone it - // (only borrowed from parser and spans multiple parser states) - // perf optimization: - // clone only, if we have non empty params, otherwise stick with default - this._params = (params.length > 1 || params.params[0]) ? params.clone() : EMPTY_PARAMS; - this._data = ''; - this._hitLimit = false; - } - - public put(data: Uint32Array, start: number, end: number): void { - if (this._hitLimit) { - return; - } - this._data += utf32ToString(data, start, end); - if (this._data.length > PAYLOAD_LIMIT) { - this._data = ''; - this._hitLimit = true; - } - } - - public unhook(success: boolean): boolean | Promise<boolean> { - let ret: boolean | Promise<boolean> = false; - if (this._hitLimit) { - ret = false; - } else if (success) { - ret = this._handler(this._data, this._params); - if (ret instanceof Promise) { - // need to hold data and params until `ret` got resolved - // dont care for errors, data will be freed anyway on next start - return ret.then(res => { - this._params = EMPTY_PARAMS; - this._data = ''; - this._hitLimit = false; - return res; - }); - } - } - this._params = EMPTY_PARAMS; - this._data = ''; - this._hitLimit = false; - return ret; - } -} diff --git a/node_modules/xterm/src/common/parser/EscapeSequenceParser.ts b/node_modules/xterm/src/common/parser/EscapeSequenceParser.ts deleted file mode 100644 index f20a7e9..0000000 --- a/node_modules/xterm/src/common/parser/EscapeSequenceParser.ts +++ /dev/null @@ -1,796 +0,0 @@ -/** - * Copyright (c) 2018 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IParsingState, IDcsHandler, IEscapeSequenceParser, IParams, IOscHandler, IHandlerCollection, CsiHandlerType, OscFallbackHandlerType, IOscParser, EscHandlerType, IDcsParser, DcsFallbackHandlerType, IFunctionIdentifier, ExecuteFallbackHandlerType, CsiFallbackHandlerType, EscFallbackHandlerType, PrintHandlerType, PrintFallbackHandlerType, ExecuteHandlerType, IParserStackState, ParserStackType, ResumableHandlersType } from 'common/parser/Types'; -import { ParserState, ParserAction } from 'common/parser/Constants'; -import { Disposable } from 'common/Lifecycle'; -import { IDisposable } from 'common/Types'; -import { fill } from 'common/TypedArrayUtils'; -import { Params } from 'common/parser/Params'; -import { OscParser } from 'common/parser/OscParser'; -import { DcsParser } from 'common/parser/DcsParser'; - -/** - * Table values are generated like this: - * index: currentState << TableValue.INDEX_STATE_SHIFT | charCode - * value: action << TableValue.TRANSITION_ACTION_SHIFT | nextState - */ -const enum TableAccess { - TRANSITION_ACTION_SHIFT = 4, - TRANSITION_STATE_MASK = 15, - INDEX_STATE_SHIFT = 8 -} - -/** - * Transition table for EscapeSequenceParser. - */ -export class TransitionTable { - public table: Uint8Array; - - constructor(length: number) { - this.table = new Uint8Array(length); - } - - /** - * Set default transition. - * @param action default action - * @param next default next state - */ - public setDefault(action: ParserAction, next: ParserState): void { - fill(this.table, action << TableAccess.TRANSITION_ACTION_SHIFT | next); - } - - /** - * Add a transition to the transition table. - * @param code input character code - * @param state current parser state - * @param action parser action to be done - * @param next next parser state - */ - public add(code: number, state: ParserState, action: ParserAction, next: ParserState): void { - this.table[state << TableAccess.INDEX_STATE_SHIFT | code] = action << TableAccess.TRANSITION_ACTION_SHIFT | next; - } - - /** - * Add transitions for multiple input character codes. - * @param codes input character code array - * @param state current parser state - * @param action parser action to be done - * @param next next parser state - */ - public addMany(codes: number[], state: ParserState, action: ParserAction, next: ParserState): void { - for (let i = 0; i < codes.length; i++) { - this.table[state << TableAccess.INDEX_STATE_SHIFT | codes[i]] = action << TableAccess.TRANSITION_ACTION_SHIFT | next; - } - } -} - - -// Pseudo-character placeholder for printable non-ascii characters (unicode). -const NON_ASCII_PRINTABLE = 0xA0; - - -/** - * VT500 compatible transition table. - * Taken from https://vt100.net/emu/dec_ansi_parser. - */ -export const VT500_TRANSITION_TABLE = (function (): TransitionTable { - const table: TransitionTable = new TransitionTable(4095); - - // range macro for byte - const BYTE_VALUES = 256; - const blueprint = Array.apply(null, Array(BYTE_VALUES)).map((unused: any, i: number) => i); - const r = (start: number, end: number): number[] => blueprint.slice(start, end); - - // Default definitions. - const PRINTABLES = r(0x20, 0x7f); // 0x20 (SP) included, 0x7F (DEL) excluded - const EXECUTABLES = r(0x00, 0x18); - EXECUTABLES.push(0x19); - EXECUTABLES.push.apply(EXECUTABLES, r(0x1c, 0x20)); - - const states: number[] = r(ParserState.GROUND, ParserState.DCS_PASSTHROUGH + 1); - let state: any; - - // set default transition - table.setDefault(ParserAction.ERROR, ParserState.GROUND); - // printables - table.addMany(PRINTABLES, ParserState.GROUND, ParserAction.PRINT, ParserState.GROUND); - // global anywhere rules - for (state in states) { - table.addMany([0x18, 0x1a, 0x99, 0x9a], state, ParserAction.EXECUTE, ParserState.GROUND); - table.addMany(r(0x80, 0x90), state, ParserAction.EXECUTE, ParserState.GROUND); - table.addMany(r(0x90, 0x98), state, ParserAction.EXECUTE, ParserState.GROUND); - table.add(0x9c, state, ParserAction.IGNORE, ParserState.GROUND); // ST as terminator - table.add(0x1b, state, ParserAction.CLEAR, ParserState.ESCAPE); // ESC - table.add(0x9d, state, ParserAction.OSC_START, ParserState.OSC_STRING); // OSC - table.addMany([0x98, 0x9e, 0x9f], state, ParserAction.IGNORE, ParserState.SOS_PM_APC_STRING); - table.add(0x9b, state, ParserAction.CLEAR, ParserState.CSI_ENTRY); // CSI - table.add(0x90, state, ParserAction.CLEAR, ParserState.DCS_ENTRY); // DCS - } - // rules for executables and 7f - table.addMany(EXECUTABLES, ParserState.GROUND, ParserAction.EXECUTE, ParserState.GROUND); - table.addMany(EXECUTABLES, ParserState.ESCAPE, ParserAction.EXECUTE, ParserState.ESCAPE); - table.add(0x7f, ParserState.ESCAPE, ParserAction.IGNORE, ParserState.ESCAPE); - table.addMany(EXECUTABLES, ParserState.OSC_STRING, ParserAction.IGNORE, ParserState.OSC_STRING); - table.addMany(EXECUTABLES, ParserState.CSI_ENTRY, ParserAction.EXECUTE, ParserState.CSI_ENTRY); - table.add(0x7f, ParserState.CSI_ENTRY, ParserAction.IGNORE, ParserState.CSI_ENTRY); - table.addMany(EXECUTABLES, ParserState.CSI_PARAM, ParserAction.EXECUTE, ParserState.CSI_PARAM); - table.add(0x7f, ParserState.CSI_PARAM, ParserAction.IGNORE, ParserState.CSI_PARAM); - table.addMany(EXECUTABLES, ParserState.CSI_IGNORE, ParserAction.EXECUTE, ParserState.CSI_IGNORE); - table.addMany(EXECUTABLES, ParserState.CSI_INTERMEDIATE, ParserAction.EXECUTE, ParserState.CSI_INTERMEDIATE); - table.add(0x7f, ParserState.CSI_INTERMEDIATE, ParserAction.IGNORE, ParserState.CSI_INTERMEDIATE); - table.addMany(EXECUTABLES, ParserState.ESCAPE_INTERMEDIATE, ParserAction.EXECUTE, ParserState.ESCAPE_INTERMEDIATE); - table.add(0x7f, ParserState.ESCAPE_INTERMEDIATE, ParserAction.IGNORE, ParserState.ESCAPE_INTERMEDIATE); - // osc - table.add(0x5d, ParserState.ESCAPE, ParserAction.OSC_START, ParserState.OSC_STRING); - table.addMany(PRINTABLES, ParserState.OSC_STRING, ParserAction.OSC_PUT, ParserState.OSC_STRING); - table.add(0x7f, ParserState.OSC_STRING, ParserAction.OSC_PUT, ParserState.OSC_STRING); - table.addMany([0x9c, 0x1b, 0x18, 0x1a, 0x07], ParserState.OSC_STRING, ParserAction.OSC_END, ParserState.GROUND); - table.addMany(r(0x1c, 0x20), ParserState.OSC_STRING, ParserAction.IGNORE, ParserState.OSC_STRING); - // sos/pm/apc does nothing - table.addMany([0x58, 0x5e, 0x5f], ParserState.ESCAPE, ParserAction.IGNORE, ParserState.SOS_PM_APC_STRING); - table.addMany(PRINTABLES, ParserState.SOS_PM_APC_STRING, ParserAction.IGNORE, ParserState.SOS_PM_APC_STRING); - table.addMany(EXECUTABLES, ParserState.SOS_PM_APC_STRING, ParserAction.IGNORE, ParserState.SOS_PM_APC_STRING); - table.add(0x9c, ParserState.SOS_PM_APC_STRING, ParserAction.IGNORE, ParserState.GROUND); - table.add(0x7f, ParserState.SOS_PM_APC_STRING, ParserAction.IGNORE, ParserState.SOS_PM_APC_STRING); - // csi entries - table.add(0x5b, ParserState.ESCAPE, ParserAction.CLEAR, ParserState.CSI_ENTRY); - table.addMany(r(0x40, 0x7f), ParserState.CSI_ENTRY, ParserAction.CSI_DISPATCH, ParserState.GROUND); - table.addMany(r(0x30, 0x3c), ParserState.CSI_ENTRY, ParserAction.PARAM, ParserState.CSI_PARAM); - table.addMany([0x3c, 0x3d, 0x3e, 0x3f], ParserState.CSI_ENTRY, ParserAction.COLLECT, ParserState.CSI_PARAM); - table.addMany(r(0x30, 0x3c), ParserState.CSI_PARAM, ParserAction.PARAM, ParserState.CSI_PARAM); - table.addMany(r(0x40, 0x7f), ParserState.CSI_PARAM, ParserAction.CSI_DISPATCH, ParserState.GROUND); - table.addMany([0x3c, 0x3d, 0x3e, 0x3f], ParserState.CSI_PARAM, ParserAction.IGNORE, ParserState.CSI_IGNORE); - table.addMany(r(0x20, 0x40), ParserState.CSI_IGNORE, ParserAction.IGNORE, ParserState.CSI_IGNORE); - table.add(0x7f, ParserState.CSI_IGNORE, ParserAction.IGNORE, ParserState.CSI_IGNORE); - table.addMany(r(0x40, 0x7f), ParserState.CSI_IGNORE, ParserAction.IGNORE, ParserState.GROUND); - table.addMany(r(0x20, 0x30), ParserState.CSI_ENTRY, ParserAction.COLLECT, ParserState.CSI_INTERMEDIATE); - table.addMany(r(0x20, 0x30), ParserState.CSI_INTERMEDIATE, ParserAction.COLLECT, ParserState.CSI_INTERMEDIATE); - table.addMany(r(0x30, 0x40), ParserState.CSI_INTERMEDIATE, ParserAction.IGNORE, ParserState.CSI_IGNORE); - table.addMany(r(0x40, 0x7f), ParserState.CSI_INTERMEDIATE, ParserAction.CSI_DISPATCH, ParserState.GROUND); - table.addMany(r(0x20, 0x30), ParserState.CSI_PARAM, ParserAction.COLLECT, ParserState.CSI_INTERMEDIATE); - // esc_intermediate - table.addMany(r(0x20, 0x30), ParserState.ESCAPE, ParserAction.COLLECT, ParserState.ESCAPE_INTERMEDIATE); - table.addMany(r(0x20, 0x30), ParserState.ESCAPE_INTERMEDIATE, ParserAction.COLLECT, ParserState.ESCAPE_INTERMEDIATE); - table.addMany(r(0x30, 0x7f), ParserState.ESCAPE_INTERMEDIATE, ParserAction.ESC_DISPATCH, ParserState.GROUND); - table.addMany(r(0x30, 0x50), ParserState.ESCAPE, ParserAction.ESC_DISPATCH, ParserState.GROUND); - table.addMany(r(0x51, 0x58), ParserState.ESCAPE, ParserAction.ESC_DISPATCH, ParserState.GROUND); - table.addMany([0x59, 0x5a, 0x5c], ParserState.ESCAPE, ParserAction.ESC_DISPATCH, ParserState.GROUND); - table.addMany(r(0x60, 0x7f), ParserState.ESCAPE, ParserAction.ESC_DISPATCH, ParserState.GROUND); - // dcs entry - table.add(0x50, ParserState.ESCAPE, ParserAction.CLEAR, ParserState.DCS_ENTRY); - table.addMany(EXECUTABLES, ParserState.DCS_ENTRY, ParserAction.IGNORE, ParserState.DCS_ENTRY); - table.add(0x7f, ParserState.DCS_ENTRY, ParserAction.IGNORE, ParserState.DCS_ENTRY); - table.addMany(r(0x1c, 0x20), ParserState.DCS_ENTRY, ParserAction.IGNORE, ParserState.DCS_ENTRY); - table.addMany(r(0x20, 0x30), ParserState.DCS_ENTRY, ParserAction.COLLECT, ParserState.DCS_INTERMEDIATE); - table.addMany(r(0x30, 0x3c), ParserState.DCS_ENTRY, ParserAction.PARAM, ParserState.DCS_PARAM); - table.addMany([0x3c, 0x3d, 0x3e, 0x3f], ParserState.DCS_ENTRY, ParserAction.COLLECT, ParserState.DCS_PARAM); - table.addMany(EXECUTABLES, ParserState.DCS_IGNORE, ParserAction.IGNORE, ParserState.DCS_IGNORE); - table.addMany(r(0x20, 0x80), ParserState.DCS_IGNORE, ParserAction.IGNORE, ParserState.DCS_IGNORE); - table.addMany(r(0x1c, 0x20), ParserState.DCS_IGNORE, ParserAction.IGNORE, ParserState.DCS_IGNORE); - table.addMany(EXECUTABLES, ParserState.DCS_PARAM, ParserAction.IGNORE, ParserState.DCS_PARAM); - table.add(0x7f, ParserState.DCS_PARAM, ParserAction.IGNORE, ParserState.DCS_PARAM); - table.addMany(r(0x1c, 0x20), ParserState.DCS_PARAM, ParserAction.IGNORE, ParserState.DCS_PARAM); - table.addMany(r(0x30, 0x3c), ParserState.DCS_PARAM, ParserAction.PARAM, ParserState.DCS_PARAM); - table.addMany([0x3c, 0x3d, 0x3e, 0x3f], ParserState.DCS_PARAM, ParserAction.IGNORE, ParserState.DCS_IGNORE); - table.addMany(r(0x20, 0x30), ParserState.DCS_PARAM, ParserAction.COLLECT, ParserState.DCS_INTERMEDIATE); - table.addMany(EXECUTABLES, ParserState.DCS_INTERMEDIATE, ParserAction.IGNORE, ParserState.DCS_INTERMEDIATE); - table.add(0x7f, ParserState.DCS_INTERMEDIATE, ParserAction.IGNORE, ParserState.DCS_INTERMEDIATE); - table.addMany(r(0x1c, 0x20), ParserState.DCS_INTERMEDIATE, ParserAction.IGNORE, ParserState.DCS_INTERMEDIATE); - table.addMany(r(0x20, 0x30), ParserState.DCS_INTERMEDIATE, ParserAction.COLLECT, ParserState.DCS_INTERMEDIATE); - table.addMany(r(0x30, 0x40), ParserState.DCS_INTERMEDIATE, ParserAction.IGNORE, ParserState.DCS_IGNORE); - table.addMany(r(0x40, 0x7f), ParserState.DCS_INTERMEDIATE, ParserAction.DCS_HOOK, ParserState.DCS_PASSTHROUGH); - table.addMany(r(0x40, 0x7f), ParserState.DCS_PARAM, ParserAction.DCS_HOOK, ParserState.DCS_PASSTHROUGH); - table.addMany(r(0x40, 0x7f), ParserState.DCS_ENTRY, ParserAction.DCS_HOOK, ParserState.DCS_PASSTHROUGH); - table.addMany(EXECUTABLES, ParserState.DCS_PASSTHROUGH, ParserAction.DCS_PUT, ParserState.DCS_PASSTHROUGH); - table.addMany(PRINTABLES, ParserState.DCS_PASSTHROUGH, ParserAction.DCS_PUT, ParserState.DCS_PASSTHROUGH); - table.add(0x7f, ParserState.DCS_PASSTHROUGH, ParserAction.IGNORE, ParserState.DCS_PASSTHROUGH); - table.addMany([0x1b, 0x9c, 0x18, 0x1a], ParserState.DCS_PASSTHROUGH, ParserAction.DCS_UNHOOK, ParserState.GROUND); - // special handling of unicode chars - table.add(NON_ASCII_PRINTABLE, ParserState.GROUND, ParserAction.PRINT, ParserState.GROUND); - table.add(NON_ASCII_PRINTABLE, ParserState.OSC_STRING, ParserAction.OSC_PUT, ParserState.OSC_STRING); - table.add(NON_ASCII_PRINTABLE, ParserState.CSI_IGNORE, ParserAction.IGNORE, ParserState.CSI_IGNORE); - table.add(NON_ASCII_PRINTABLE, ParserState.DCS_IGNORE, ParserAction.IGNORE, ParserState.DCS_IGNORE); - table.add(NON_ASCII_PRINTABLE, ParserState.DCS_PASSTHROUGH, ParserAction.DCS_PUT, ParserState.DCS_PASSTHROUGH); - return table; -})(); - - -/** - * EscapeSequenceParser. - * This class implements the ANSI/DEC compatible parser described by - * Paul Williams (https://vt100.net/emu/dec_ansi_parser). - * - * To implement custom ANSI compliant escape sequences it is not needed to - * alter this parser, instead consider registering a custom handler. - * For non ANSI compliant sequences change the transition table with - * the optional `transitions` constructor argument and - * reimplement the `parse` method. - * - * This parser is currently hardcoded to operate in ZDM (Zero Default Mode) - * as suggested by the original parser, thus empty parameters are set to 0. - * This this is not in line with the latest ECMA-48 specification - * (ZDM was part of the early specs and got completely removed later on). - * - * Other than the original parser from vt100.net this parser supports - * sub parameters in digital parameters separated by colons. Empty sub parameters - * are set to -1 (no ZDM for sub parameters). - * - * About prefix and intermediate bytes: - * This parser follows the assumptions of the vt100.net parser with these restrictions: - * - only one prefix byte is allowed as first parameter byte, byte range 0x3c .. 0x3f - * - max. two intermediates are respected, byte range 0x20 .. 0x2f - * Note that this is not in line with ECMA-48 which does not limit either of those. - * Furthermore ECMA-48 allows the prefix byte range at any param byte position. Currently - * there are no known sequences that follow the broader definition of the specification. - * - * TODO: implement error recovery hook via error handler return values - */ -export class EscapeSequenceParser extends Disposable implements IEscapeSequenceParser { - public initialState: number; - public currentState: number; - public precedingCodepoint: number; - - // buffers over several parse calls - protected _params: Params; - protected _collect: number; - - // handler lookup containers - protected _printHandler: PrintHandlerType; - protected _executeHandlers: { [flag: number]: ExecuteHandlerType }; - protected _csiHandlers: IHandlerCollection<CsiHandlerType>; - protected _escHandlers: IHandlerCollection<EscHandlerType>; - protected _oscParser: IOscParser; - protected _dcsParser: IDcsParser; - protected _errorHandler: (state: IParsingState) => IParsingState; - - // fallback handlers - protected _printHandlerFb: PrintFallbackHandlerType; - protected _executeHandlerFb: ExecuteFallbackHandlerType; - protected _csiHandlerFb: CsiFallbackHandlerType; - protected _escHandlerFb: EscFallbackHandlerType; - protected _errorHandlerFb: (state: IParsingState) => IParsingState; - - // parser stack save for async handler support - protected _parseStack: IParserStackState = { - state: ParserStackType.NONE, - handlers: [], - handlerPos: 0, - transition: 0, - chunkPos: 0 - }; - - constructor( - protected readonly _transitions: TransitionTable = VT500_TRANSITION_TABLE - ) { - super(); - - this.initialState = ParserState.GROUND; - this.currentState = this.initialState; - this._params = new Params(); // defaults to 32 storable params/subparams - this._params.addParam(0); // ZDM - this._collect = 0; - this.precedingCodepoint = 0; - - // set default fallback handlers and handler lookup containers - this._printHandlerFb = (data, start, end): void => { }; - this._executeHandlerFb = (code: number): void => { }; - this._csiHandlerFb = (ident: number, params: IParams): void => { }; - this._escHandlerFb = (ident: number): void => { }; - this._errorHandlerFb = (state: IParsingState): IParsingState => state; - this._printHandler = this._printHandlerFb; - this._executeHandlers = Object.create(null); - this._csiHandlers = Object.create(null); - this._escHandlers = Object.create(null); - this._oscParser = new OscParser(); - this._dcsParser = new DcsParser(); - this._errorHandler = this._errorHandlerFb; - - // swallow 7bit ST (ESC+\) - this.registerEscHandler({ final: '\\' }, () => true); - } - - protected _identifier(id: IFunctionIdentifier, finalRange: number[] = [0x40, 0x7e]): number { - let res = 0; - if (id.prefix) { - if (id.prefix.length > 1) { - throw new Error('only one byte as prefix supported'); - } - res = id.prefix.charCodeAt(0); - if (res && 0x3c > res || res > 0x3f) { - throw new Error('prefix must be in range 0x3c .. 0x3f'); - } - } - if (id.intermediates) { - if (id.intermediates.length > 2) { - throw new Error('only two bytes as intermediates are supported'); - } - for (let i = 0; i < id.intermediates.length; ++i) { - const intermediate = id.intermediates.charCodeAt(i); - if (0x20 > intermediate || intermediate > 0x2f) { - throw new Error('intermediate must be in range 0x20 .. 0x2f'); - } - res <<= 8; - res |= intermediate; - } - } - if (id.final.length !== 1) { - throw new Error('final must be a single byte'); - } - const finalCode = id.final.charCodeAt(0); - if (finalRange[0] > finalCode || finalCode > finalRange[1]) { - throw new Error(`final must be in range ${finalRange[0]} .. ${finalRange[1]}`); - } - res <<= 8; - res |= finalCode; - - return res; - } - - public identToString(ident: number): string { - const res: string[] = []; - while (ident) { - res.push(String.fromCharCode(ident & 0xFF)); - ident >>= 8; - } - return res.reverse().join(''); - } - - public dispose(): void { - this._csiHandlers = Object.create(null); - this._executeHandlers = Object.create(null); - this._escHandlers = Object.create(null); - this._oscParser.dispose(); - this._dcsParser.dispose(); - } - - public setPrintHandler(handler: PrintHandlerType): void { - this._printHandler = handler; - } - public clearPrintHandler(): void { - this._printHandler = this._printHandlerFb; - } - - public registerEscHandler(id: IFunctionIdentifier, handler: EscHandlerType): IDisposable { - const ident = this._identifier(id, [0x30, 0x7e]); - if (this._escHandlers[ident] === undefined) { - this._escHandlers[ident] = []; - } - const handlerList = this._escHandlers[ident]; - handlerList.push(handler); - return { - dispose: () => { - const handlerIndex = handlerList.indexOf(handler); - if (handlerIndex !== -1) { - handlerList.splice(handlerIndex, 1); - } - } - }; - } - public clearEscHandler(id: IFunctionIdentifier): void { - if (this._escHandlers[this._identifier(id, [0x30, 0x7e])]) delete this._escHandlers[this._identifier(id, [0x30, 0x7e])]; - } - public setEscHandlerFallback(handler: EscFallbackHandlerType): void { - this._escHandlerFb = handler; - } - - public setExecuteHandler(flag: string, handler: ExecuteHandlerType): void { - this._executeHandlers[flag.charCodeAt(0)] = handler; - } - public clearExecuteHandler(flag: string): void { - if (this._executeHandlers[flag.charCodeAt(0)]) delete this._executeHandlers[flag.charCodeAt(0)]; - } - public setExecuteHandlerFallback(handler: ExecuteFallbackHandlerType): void { - this._executeHandlerFb = handler; - } - - public registerCsiHandler(id: IFunctionIdentifier, handler: CsiHandlerType): IDisposable { - const ident = this._identifier(id); - if (this._csiHandlers[ident] === undefined) { - this._csiHandlers[ident] = []; - } - const handlerList = this._csiHandlers[ident]; - handlerList.push(handler); - return { - dispose: () => { - const handlerIndex = handlerList.indexOf(handler); - if (handlerIndex !== -1) { - handlerList.splice(handlerIndex, 1); - } - } - }; - } - public clearCsiHandler(id: IFunctionIdentifier): void { - if (this._csiHandlers[this._identifier(id)]) delete this._csiHandlers[this._identifier(id)]; - } - public setCsiHandlerFallback(callback: (ident: number, params: IParams) => void): void { - this._csiHandlerFb = callback; - } - - public registerDcsHandler(id: IFunctionIdentifier, handler: IDcsHandler): IDisposable { - return this._dcsParser.registerHandler(this._identifier(id), handler); - } - public clearDcsHandler(id: IFunctionIdentifier): void { - this._dcsParser.clearHandler(this._identifier(id)); - } - public setDcsHandlerFallback(handler: DcsFallbackHandlerType): void { - this._dcsParser.setHandlerFallback(handler); - } - - public registerOscHandler(ident: number, handler: IOscHandler): IDisposable { - return this._oscParser.registerHandler(ident, handler); - } - public clearOscHandler(ident: number): void { - this._oscParser.clearHandler(ident); - } - public setOscHandlerFallback(handler: OscFallbackHandlerType): void { - this._oscParser.setHandlerFallback(handler); - } - - public setErrorHandler(callback: (state: IParsingState) => IParsingState): void { - this._errorHandler = callback; - } - public clearErrorHandler(): void { - this._errorHandler = this._errorHandlerFb; - } - - /** - * Reset parser to initial values. - * - * This can also be used to lift the improper continuation error condition - * when dealing with async handlers. Use this only as a last resort to silence - * that error when the terminal has no pending data to be processed. Note that - * the interrupted async handler might continue its work in the future messing - * up the terminal state even further. - */ - public reset(): void { - this.currentState = this.initialState; - this._oscParser.reset(); - this._dcsParser.reset(); - this._params.reset(); - this._params.addParam(0); // ZDM - this._collect = 0; - this.precedingCodepoint = 0; - // abort pending continuation from async handler - // Here the RESET type indicates, that the next parse call will - // ignore any saved stack, instead continues sync with next codepoint from GROUND - if (this._parseStack.state !== ParserStackType.NONE) { - this._parseStack.state = ParserStackType.RESET; - this._parseStack.handlers = []; // also release handlers ref - } - } - - /** - * Async parse support. - */ - protected _preserveStack( - state: ParserStackType, - handlers: ResumableHandlersType, - handlerPos: number, - transition: number, - chunkPos: number - ): void { - this._parseStack.state = state; - this._parseStack.handlers = handlers; - this._parseStack.handlerPos = handlerPos; - this._parseStack.transition = transition; - this._parseStack.chunkPos = chunkPos; - } - - /** - * Parse UTF32 codepoints in `data` up to `length`. - * - * Note: For several actions with high data load the parsing is optimized - * by using local read ahead loops with hardcoded conditions to - * avoid costly table lookups. Make sure that any change of table values - * will be reflected in the loop conditions as well and vice versa. - * Affected states/actions: - * - GROUND:PRINT - * - CSI_PARAM:PARAM - * - DCS_PARAM:PARAM - * - OSC_STRING:OSC_PUT - * - DCS_PASSTHROUGH:DCS_PUT - * - * Note on asynchronous handler support: - * Any handler returning a promise will be treated as asynchronous. - * To keep the in-band blocking working for async handlers, `parse` pauses execution, - * creates a stack save and returns the promise to the caller. - * For proper continuation of the paused state it is important - * to await the promise resolving. On resolve the parse must be repeated - * with the same chunk of data and the resolved value in `promiseResult` - * until no promise is returned. - * - * Important: With only sync handlers defined, parsing is completely synchronous as well. - * As soon as an async handler is involved, synchronous parsing is not possible anymore. - * - * Boilerplate for proper parsing of multiple chunks with async handlers: - * - * ```typescript - * async function parseMultipleChunks(chunks: Uint32Array[]): Promise<void> { - * for (const chunk of chunks) { - * let result: void | Promise<boolean>; - * let prev: boolean | undefined; - * while (result = parser.parse(chunk, chunk.length, prev)) { - * prev = await result; - * } - * } - * // finished parsing all chunks... - * } - * ``` - */ - public parse(data: Uint32Array, length: number, promiseResult?: boolean): void | Promise<boolean> { - let code = 0; - let transition = 0; - let start = 0; - let handlerResult: void | boolean | Promise<boolean>; - - // resume from async handler - if (this._parseStack.state) { - // allow sync parser reset even in continuation mode - // Note: can be used to recover parser from improper continuation error below - if (this._parseStack.state === ParserStackType.RESET) { - this._parseStack.state = ParserStackType.NONE; - start = this._parseStack.chunkPos + 1; // continue with next codepoint in GROUND - } else { - if (promiseResult === undefined || this._parseStack.state === ParserStackType.FAIL) { - /** - * Reject further parsing on improper continuation after pausing. - * This is a really bad condition with screwed up execution order and prolly messed up - * terminal state, therefore we exit hard with an exception and reject any further parsing. - * - * Note: With `Terminal.write` usage this exception should never occur, as the top level - * calls are guaranteed to handle async conditions properly. If you ever encounter this - * exception in your terminal integration it indicates, that you injected data chunks to - * `InputHandler.parse` or `EscapeSequenceParser.parse` synchronously without waiting for - * continuation of a running async handler. - * - * It is possible to get rid of this error by calling `reset`. But dont rely on that, - * as the pending async handler still might mess up the terminal later. Instead fix the faulty - * async handling, so this error will not be thrown anymore. - */ - this._parseStack.state = ParserStackType.FAIL; - throw new Error('improper continuation due to previous async handler, giving up parsing'); - } - - // we have to resume the old handler loop if: - // - return value of the promise was `false` - // - handlers are not exhausted yet - const handlers = this._parseStack.handlers; - let handlerPos = this._parseStack.handlerPos - 1; - switch (this._parseStack.state) { - case ParserStackType.CSI: - if (promiseResult === false && handlerPos > -1) { - for (; handlerPos >= 0; handlerPos--) { - handlerResult = (handlers as CsiHandlerType[])[handlerPos](this._params); - if (handlerResult === true) { - break; - } else if (handlerResult instanceof Promise) { - this._parseStack.handlerPos = handlerPos; - return handlerResult; - } - } - } - this._parseStack.handlers = []; - break; - case ParserStackType.ESC: - if (promiseResult === false && handlerPos > -1) { - for (; handlerPos >= 0; handlerPos--) { - handlerResult = (handlers as EscHandlerType[])[handlerPos](); - if (handlerResult === true) { - break; - } else if (handlerResult instanceof Promise) { - this._parseStack.handlerPos = handlerPos; - return handlerResult; - } - } - } - this._parseStack.handlers = []; - break; - case ParserStackType.DCS: - code = data[this._parseStack.chunkPos]; - handlerResult = this._dcsParser.unhook(code !== 0x18 && code !== 0x1a, promiseResult); - if (handlerResult) { - return handlerResult; - } - if (code === 0x1b) this._parseStack.transition |= ParserState.ESCAPE; - this._params.reset(); - this._params.addParam(0); // ZDM - this._collect = 0; - break; - case ParserStackType.OSC: - code = data[this._parseStack.chunkPos]; - handlerResult = this._oscParser.end(code !== 0x18 && code !== 0x1a, promiseResult); - if (handlerResult) { - return handlerResult; - } - if (code === 0x1b) this._parseStack.transition |= ParserState.ESCAPE; - this._params.reset(); - this._params.addParam(0); // ZDM - this._collect = 0; - break; - } - // cleanup before continuing with the main sync loop - this._parseStack.state = ParserStackType.NONE; - start = this._parseStack.chunkPos + 1; - this.precedingCodepoint = 0; - this.currentState = this._parseStack.transition & TableAccess.TRANSITION_STATE_MASK; - } - } - - // continue with main sync loop - - // process input string - for (let i = start; i < length; ++i) { - code = data[i]; - - // normal transition & action lookup - transition = this._transitions.table[this.currentState << TableAccess.INDEX_STATE_SHIFT | (code < 0xa0 ? code : NON_ASCII_PRINTABLE)]; - switch (transition >> TableAccess.TRANSITION_ACTION_SHIFT) { - case ParserAction.PRINT: - // read ahead with loop unrolling - // Note: 0x20 (SP) is included, 0x7F (DEL) is excluded - for (let j = i + 1; ; ++j) { - if (j >= length || (code = data[j]) < 0x20 || (code > 0x7e && code < NON_ASCII_PRINTABLE)) { - this._printHandler(data, i, j); - i = j - 1; - break; - } - if (++j >= length || (code = data[j]) < 0x20 || (code > 0x7e && code < NON_ASCII_PRINTABLE)) { - this._printHandler(data, i, j); - i = j - 1; - break; - } - if (++j >= length || (code = data[j]) < 0x20 || (code > 0x7e && code < NON_ASCII_PRINTABLE)) { - this._printHandler(data, i, j); - i = j - 1; - break; - } - if (++j >= length || (code = data[j]) < 0x20 || (code > 0x7e && code < NON_ASCII_PRINTABLE)) { - this._printHandler(data, i, j); - i = j - 1; - break; - } - } - break; - case ParserAction.EXECUTE: - if (this._executeHandlers[code]) this._executeHandlers[code](); - else this._executeHandlerFb(code); - this.precedingCodepoint = 0; - break; - case ParserAction.IGNORE: - break; - case ParserAction.ERROR: - const inject: IParsingState = this._errorHandler( - { - position: i, - code, - currentState: this.currentState, - collect: this._collect, - params: this._params, - abort: false - }); - if (inject.abort) return; - // inject values: currently not implemented - break; - case ParserAction.CSI_DISPATCH: - // Trigger CSI Handler - const handlers = this._csiHandlers[this._collect << 8 | code]; - let j = handlers ? handlers.length - 1 : -1; - for (; j >= 0; j--) { - // true means success and to stop bubbling - // a promise indicates an async handler that needs to finish before progressing - handlerResult = handlers[j](this._params); - if (handlerResult === true) { - break; - } else if (handlerResult instanceof Promise) { - this._preserveStack(ParserStackType.CSI, handlers, j, transition, i); - return handlerResult; - } - } - if (j < 0) { - this._csiHandlerFb(this._collect << 8 | code, this._params); - } - this.precedingCodepoint = 0; - break; - case ParserAction.PARAM: - // inner loop: digits (0x30 - 0x39) and ; (0x3b) and : (0x3a) - do { - switch (code) { - case 0x3b: - this._params.addParam(0); // ZDM - break; - case 0x3a: - this._params.addSubParam(-1); - break; - default: // 0x30 - 0x39 - this._params.addDigit(code - 48); - } - } while (++i < length && (code = data[i]) > 0x2f && code < 0x3c); - i--; - break; - case ParserAction.COLLECT: - this._collect <<= 8; - this._collect |= code; - break; - case ParserAction.ESC_DISPATCH: - const handlersEsc = this._escHandlers[this._collect << 8 | code]; - let jj = handlersEsc ? handlersEsc.length - 1 : -1; - for (; jj >= 0; jj--) { - // true means success and to stop bubbling - // a promise indicates an async handler that needs to finish before progressing - handlerResult = handlersEsc[jj](); - if (handlerResult === true) { - break; - } else if (handlerResult instanceof Promise) { - this._preserveStack(ParserStackType.ESC, handlersEsc, jj, transition, i); - return handlerResult; - } - } - if (jj < 0) { - this._escHandlerFb(this._collect << 8 | code); - } - this.precedingCodepoint = 0; - break; - case ParserAction.CLEAR: - this._params.reset(); - this._params.addParam(0); // ZDM - this._collect = 0; - break; - case ParserAction.DCS_HOOK: - this._dcsParser.hook(this._collect << 8 | code, this._params); - break; - case ParserAction.DCS_PUT: - // inner loop - exit DCS_PUT: 0x18, 0x1a, 0x1b, 0x7f, 0x80 - 0x9f - // unhook triggered by: 0x1b, 0x9c (success) and 0x18, 0x1a (abort) - for (let j = i + 1; ; ++j) { - if (j >= length || (code = data[j]) === 0x18 || code === 0x1a || code === 0x1b || (code > 0x7f && code < NON_ASCII_PRINTABLE)) { - this._dcsParser.put(data, i, j); - i = j - 1; - break; - } - } - break; - case ParserAction.DCS_UNHOOK: - handlerResult = this._dcsParser.unhook(code !== 0x18 && code !== 0x1a); - if (handlerResult) { - this._preserveStack(ParserStackType.DCS, [], 0, transition, i); - return handlerResult; - } - if (code === 0x1b) transition |= ParserState.ESCAPE; - this._params.reset(); - this._params.addParam(0); // ZDM - this._collect = 0; - this.precedingCodepoint = 0; - break; - case ParserAction.OSC_START: - this._oscParser.start(); - break; - case ParserAction.OSC_PUT: - // inner loop: 0x20 (SP) included, 0x7F (DEL) included - for (let j = i + 1; ; j++) { - if (j >= length || (code = data[j]) < 0x20 || (code > 0x7f && code < NON_ASCII_PRINTABLE)) { - this._oscParser.put(data, i, j); - i = j - 1; - break; - } - } - break; - case ParserAction.OSC_END: - handlerResult = this._oscParser.end(code !== 0x18 && code !== 0x1a); - if (handlerResult) { - this._preserveStack(ParserStackType.OSC, [], 0, transition, i); - return handlerResult; - } - if (code === 0x1b) transition |= ParserState.ESCAPE; - this._params.reset(); - this._params.addParam(0); // ZDM - this._collect = 0; - this.precedingCodepoint = 0; - break; - } - this.currentState = transition & TableAccess.TRANSITION_STATE_MASK; - } - } -} diff --git a/node_modules/xterm/src/common/parser/OscParser.ts b/node_modules/xterm/src/common/parser/OscParser.ts deleted file mode 100644 index 32710ae..0000000 --- a/node_modules/xterm/src/common/parser/OscParser.ts +++ /dev/null @@ -1,238 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IOscHandler, IHandlerCollection, OscFallbackHandlerType, IOscParser, ISubParserStackState } from 'common/parser/Types'; -import { OscState, PAYLOAD_LIMIT } from 'common/parser/Constants'; -import { utf32ToString } from 'common/input/TextDecoder'; -import { IDisposable } from 'common/Types'; - -const EMPTY_HANDLERS: IOscHandler[] = []; - -export class OscParser implements IOscParser { - private _state = OscState.START; - private _active = EMPTY_HANDLERS; - private _id = -1; - private _handlers: IHandlerCollection<IOscHandler> = Object.create(null); - private _handlerFb: OscFallbackHandlerType = () => { }; - private _stack: ISubParserStackState = { - paused: false, - loopPosition: 0, - fallThrough: false - }; - - public registerHandler(ident: number, handler: IOscHandler): IDisposable { - if (this._handlers[ident] === undefined) { - this._handlers[ident] = []; - } - const handlerList = this._handlers[ident]; - handlerList.push(handler); - return { - dispose: () => { - const handlerIndex = handlerList.indexOf(handler); - if (handlerIndex !== -1) { - handlerList.splice(handlerIndex, 1); - } - } - }; - } - public clearHandler(ident: number): void { - if (this._handlers[ident]) delete this._handlers[ident]; - } - public setHandlerFallback(handler: OscFallbackHandlerType): void { - this._handlerFb = handler; - } - - public dispose(): void { - this._handlers = Object.create(null); - this._handlerFb = () => { }; - this._active = EMPTY_HANDLERS; - } - - public reset(): void { - // force cleanup handlers if payload was already sent - if (this._state === OscState.PAYLOAD) { - for (let j = this._stack.paused ? this._stack.loopPosition - 1 : this._active.length - 1; j >= 0; --j) { - this._active[j].end(false); - } - } - this._stack.paused = false; - this._active = EMPTY_HANDLERS; - this._id = -1; - this._state = OscState.START; - } - - private _start(): void { - this._active = this._handlers[this._id] || EMPTY_HANDLERS; - if (!this._active.length) { - this._handlerFb(this._id, 'START'); - } else { - for (let j = this._active.length - 1; j >= 0; j--) { - this._active[j].start(); - } - } - } - - private _put(data: Uint32Array, start: number, end: number): void { - if (!this._active.length) { - this._handlerFb(this._id, 'PUT', utf32ToString(data, start, end)); - } else { - for (let j = this._active.length - 1; j >= 0; j--) { - this._active[j].put(data, start, end); - } - } - } - - public start(): void { - // always reset leftover handlers - this.reset(); - this._state = OscState.ID; - } - - /** - * Put data to current OSC command. - * Expects the identifier of the OSC command in the form - * OSC id ; payload ST/BEL - * Payload chunks are not further processed and get - * directly passed to the handlers. - */ - public put(data: Uint32Array, start: number, end: number): void { - if (this._state === OscState.ABORT) { - return; - } - if (this._state === OscState.ID) { - while (start < end) { - const code = data[start++]; - if (code === 0x3b) { - this._state = OscState.PAYLOAD; - this._start(); - break; - } - if (code < 0x30 || 0x39 < code) { - this._state = OscState.ABORT; - return; - } - if (this._id === -1) { - this._id = 0; - } - this._id = this._id * 10 + code - 48; - } - } - if (this._state === OscState.PAYLOAD && end - start > 0) { - this._put(data, start, end); - } - } - - /** - * Indicates end of an OSC command. - * Whether the OSC got aborted or finished normally - * is indicated by `success`. - */ - public end(success: boolean, promiseResult: boolean = true): void | Promise<boolean> { - if (this._state === OscState.START) { - return; - } - // do nothing if command was faulty - if (this._state !== OscState.ABORT) { - // if we are still in ID state and get an early end - // means that the command has no payload thus we still have - // to announce START and send END right after - if (this._state === OscState.ID) { - this._start(); - } - - if (!this._active.length) { - this._handlerFb(this._id, 'END', success); - } else { - let handlerResult: boolean | Promise<boolean> = false; - let j = this._active.length - 1; - let fallThrough = false; - if (this._stack.paused) { - j = this._stack.loopPosition - 1; - handlerResult = promiseResult; - fallThrough = this._stack.fallThrough; - this._stack.paused = false; - } - if (!fallThrough && handlerResult === false) { - for (; j >= 0; j--) { - handlerResult = this._active[j].end(success); - if (handlerResult === true) { - break; - } else if (handlerResult instanceof Promise) { - this._stack.paused = true; - this._stack.loopPosition = j; - this._stack.fallThrough = false; - return handlerResult; - } - } - j--; - } - // cleanup left over handlers - // we always have to call .end for proper cleanup, - // here we use `success` to indicate whether a handler should execute - for (; j >= 0; j--) { - handlerResult = this._active[j].end(false); - if (handlerResult instanceof Promise) { - this._stack.paused = true; - this._stack.loopPosition = j; - this._stack.fallThrough = true; - return handlerResult; - } - } - } - - } - this._active = EMPTY_HANDLERS; - this._id = -1; - this._state = OscState.START; - } -} - -/** - * Convenient class to allow attaching string based handler functions - * as OSC handlers. - */ -export class OscHandler implements IOscHandler { - private _data = ''; - private _hitLimit: boolean = false; - - constructor(private _handler: (data: string) => boolean | Promise<boolean>) { } - - public start(): void { - this._data = ''; - this._hitLimit = false; - } - - public put(data: Uint32Array, start: number, end: number): void { - if (this._hitLimit) { - return; - } - this._data += utf32ToString(data, start, end); - if (this._data.length > PAYLOAD_LIMIT) { - this._data = ''; - this._hitLimit = true; - } - } - - public end(success: boolean): boolean | Promise<boolean> { - let ret: boolean | Promise<boolean> = false; - if (this._hitLimit) { - ret = false; - } else if (success) { - ret = this._handler(this._data); - if (ret instanceof Promise) { - // need to hold data until `ret` got resolved - // dont care for errors, data will be freed anyway on next start - return ret.then(res => { - this._data = ''; - this._hitLimit = false; - return res; - }); - } - } - this._data = ''; - this._hitLimit = false; - return ret; - } -} diff --git a/node_modules/xterm/src/common/parser/Params.ts b/node_modules/xterm/src/common/parser/Params.ts deleted file mode 100644 index 7071453..0000000 --- a/node_modules/xterm/src/common/parser/Params.ts +++ /dev/null @@ -1,229 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ -import { IParams, ParamsArray } from 'common/parser/Types'; - -// max value supported for a single param/subparam (clamped to positive int32 range) -const MAX_VALUE = 0x7FFFFFFF; -// max allowed subparams for a single sequence (hardcoded limitation) -const MAX_SUBPARAMS = 256; - -/** - * Params storage class. - * This type is used by the parser to accumulate sequence parameters and sub parameters - * and transmit them to the input handler actions. - * - * NOTES: - * - params object for action handlers is borrowed, use `.toArray` or `.clone` to get a copy - * - never read beyond `params.length - 1` (likely to contain arbitrary data) - * - `.getSubParams` returns a borrowed typed array, use `.getSubParamsAll` for cloned sub params - * - hardcoded limitations: - * - max. value for a single (sub) param is 2^31 - 1 (greater values are clamped to that) - * - max. 256 sub params possible - * - negative values are not allowed beside -1 (placeholder for default value) - * - * About ZDM (Zero Default Mode): - * ZDM is not orchestrated by this class. If the parser is in ZDM, - * it should add 0 for empty params, otherwise -1. This does not apply - * to subparams, empty subparams should always be added with -1. - */ -export class Params implements IParams { - // params store and length - public params: Int32Array; - public length: number; - - // sub params store and length - protected _subParams: Int32Array; - protected _subParamsLength: number; - - // sub params offsets from param: param idx --> [start, end] offset - private _subParamsIdx: Uint16Array; - private _rejectDigits: boolean; - private _rejectSubDigits: boolean; - private _digitIsSub: boolean; - - /** - * Create a `Params` type from JS array representation. - */ - public static fromArray(values: ParamsArray): Params { - const params = new Params(); - if (!values.length) { - return params; - } - // skip leading sub params - for (let i = (Array.isArray(values[0])) ? 1 : 0; i < values.length; ++i) { - const value = values[i]; - if (Array.isArray(value)) { - for (let k = 0; k < value.length; ++k) { - params.addSubParam(value[k]); - } - } else { - params.addParam(value); - } - } - return params; - } - - /** - * @param maxLength max length of storable parameters - * @param maxSubParamsLength max length of storable sub parameters - */ - constructor(public maxLength: number = 32, public maxSubParamsLength: number = 32) { - if (maxSubParamsLength > MAX_SUBPARAMS) { - throw new Error('maxSubParamsLength must not be greater than 256'); - } - this.params = new Int32Array(maxLength); - this.length = 0; - this._subParams = new Int32Array(maxSubParamsLength); - this._subParamsLength = 0; - this._subParamsIdx = new Uint16Array(maxLength); - this._rejectDigits = false; - this._rejectSubDigits = false; - this._digitIsSub = false; - } - - /** - * Clone object. - */ - public clone(): Params { - const newParams = new Params(this.maxLength, this.maxSubParamsLength); - newParams.params.set(this.params); - newParams.length = this.length; - newParams._subParams.set(this._subParams); - newParams._subParamsLength = this._subParamsLength; - newParams._subParamsIdx.set(this._subParamsIdx); - newParams._rejectDigits = this._rejectDigits; - newParams._rejectSubDigits = this._rejectSubDigits; - newParams._digitIsSub = this._digitIsSub; - return newParams; - } - - /** - * Get a JS array representation of the current parameters and sub parameters. - * The array is structured as follows: - * sequence: "1;2:3:4;5::6" - * array : [1, 2, [3, 4], 5, [-1, 6]] - */ - public toArray(): ParamsArray { - const res: ParamsArray = []; - for (let i = 0; i < this.length; ++i) { - res.push(this.params[i]); - const start = this._subParamsIdx[i] >> 8; - const end = this._subParamsIdx[i] & 0xFF; - if (end - start > 0) { - res.push(Array.prototype.slice.call(this._subParams, start, end)); - } - } - return res; - } - - /** - * Reset to initial empty state. - */ - public reset(): void { - this.length = 0; - this._subParamsLength = 0; - this._rejectDigits = false; - this._rejectSubDigits = false; - this._digitIsSub = false; - } - - /** - * Add a parameter value. - * `Params` only stores up to `maxLength` parameters, any later - * parameter will be ignored. - * Note: VT devices only stored up to 16 values, xterm seems to - * store up to 30. - */ - public addParam(value: number): void { - this._digitIsSub = false; - if (this.length >= this.maxLength) { - this._rejectDigits = true; - return; - } - if (value < -1) { - throw new Error('values lesser than -1 are not allowed'); - } - this._subParamsIdx[this.length] = this._subParamsLength << 8 | this._subParamsLength; - this.params[this.length++] = value > MAX_VALUE ? MAX_VALUE : value; - } - - /** - * Add a sub parameter value. - * The sub parameter is automatically associated with the last parameter value. - * Thus it is not possible to add a subparameter without any parameter added yet. - * `Params` only stores up to `subParamsLength` sub parameters, any later - * sub parameter will be ignored. - */ - public addSubParam(value: number): void { - this._digitIsSub = true; - if (!this.length) { - return; - } - if (this._rejectDigits || this._subParamsLength >= this.maxSubParamsLength) { - this._rejectSubDigits = true; - return; - } - if (value < -1) { - throw new Error('values lesser than -1 are not allowed'); - } - this._subParams[this._subParamsLength++] = value > MAX_VALUE ? MAX_VALUE : value; - this._subParamsIdx[this.length - 1]++; - } - - /** - * Whether parameter at index `idx` has sub parameters. - */ - public hasSubParams(idx: number): boolean { - return ((this._subParamsIdx[idx] & 0xFF) - (this._subParamsIdx[idx] >> 8) > 0); - } - - /** - * Return sub parameters for parameter at index `idx`. - * Note: The values are borrowed, thus you need to copy - * the values if you need to hold them in nonlocal scope. - */ - public getSubParams(idx: number): Int32Array | null { - const start = this._subParamsIdx[idx] >> 8; - const end = this._subParamsIdx[idx] & 0xFF; - if (end - start > 0) { - return this._subParams.subarray(start, end); - } - return null; - } - - /** - * Return all sub parameters as {idx: subparams} mapping. - * Note: The values are not borrowed. - */ - public getSubParamsAll(): {[idx: number]: Int32Array} { - const result: {[idx: number]: Int32Array} = {}; - for (let i = 0; i < this.length; ++i) { - const start = this._subParamsIdx[i] >> 8; - const end = this._subParamsIdx[i] & 0xFF; - if (end - start > 0) { - result[i] = this._subParams.slice(start, end); - } - } - return result; - } - - /** - * Add a single digit value to current parameter. - * This is used by the parser to account digits on a char by char basis. - */ - public addDigit(value: number): void { - let length; - if (this._rejectDigits - || !(length = this._digitIsSub ? this._subParamsLength : this.length) - || (this._digitIsSub && this._rejectSubDigits) - ) { - return; - } - - const store = this._digitIsSub ? this._subParams : this.params; - const cur = store[length - 1]; - store[length - 1] = ~cur ? Math.min(cur * 10 + value, MAX_VALUE) : value; - } -} diff --git a/node_modules/xterm/src/common/parser/Types.d.ts b/node_modules/xterm/src/common/parser/Types.d.ts deleted file mode 100644 index 3a621ea..0000000 --- a/node_modules/xterm/src/common/parser/Types.d.ts +++ /dev/null @@ -1,274 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IDisposable } from 'common/Types'; -import { ParserState } from 'common/parser/Constants'; - - -/** sequence params serialized to js arrays */ -export type ParamsArray = (number | number[])[]; - -/** Params constructor type. */ -export interface IParamsConstructor { - new(maxLength: number, maxSubParamsLength: number): IParams; - - /** create params from ParamsArray */ - fromArray(values: ParamsArray): IParams; -} - -/** Interface of Params storage class. */ -export interface IParams { - /** from ctor */ - maxLength: number; - maxSubParamsLength: number; - - /** param values and its length */ - params: Int32Array; - length: number; - - /** methods */ - clone(): IParams; - toArray(): ParamsArray; - reset(): void; - addParam(value: number): void; - addSubParam(value: number): void; - hasSubParams(idx: number): boolean; - getSubParams(idx: number): Int32Array | null; - getSubParamsAll(): {[idx: number]: Int32Array}; -} - -/** - * Internal state of EscapeSequenceParser. - * Used as argument of the error handler to allow - * introspection at runtime on parse errors. - * Return it with altered values to recover from - * faulty states (not yet supported). - * Set `abort` to `true` to abort the current parsing. - */ -export interface IParsingState { - // position in parse string - position: number; - // actual character code - code: number; - // current parser state - currentState: ParserState; - // collect buffer with intermediate characters - collect: number; - // params buffer - params: IParams; - // should abort (default: false) - abort: boolean; -} - -/** - * Command handler interfaces. - */ - -/** - * CSI handler types. - * Note: `params` is borrowed. - */ -export type CsiHandlerType = (params: IParams) => boolean | Promise<boolean>; -export type CsiFallbackHandlerType = (ident: number, params: IParams) => void; - -/** - * DCS handler types. - */ -export interface IDcsHandler { - /** - * Called when a DCS command starts. - * Prepare needed data structures here. - * Note: `params` is borrowed. - */ - hook(params: IParams): void; - /** - * Incoming payload chunk. - * Note: `params` is borrowed. - */ - put(data: Uint32Array, start: number, end: number): void; - /** - * End of DCS command. `success` indicates whether the - * command finished normally or got aborted, thus final - * execution of the command should depend on `success`. - * To save memory also cleanup data structures here. - */ - unhook(success: boolean): boolean | Promise<boolean>; -} -export type DcsFallbackHandlerType = (ident: number, action: 'HOOK' | 'PUT' | 'UNHOOK', payload?: any) => void; - -/** - * ESC handler types. - */ -export type EscHandlerType = () => boolean | Promise<boolean>; -export type EscFallbackHandlerType = (identifier: number) => void; - -/** - * EXECUTE handler types. - */ -export type ExecuteHandlerType = () => boolean; -export type ExecuteFallbackHandlerType = (ident: number) => void; - -/** - * OSC handler types. - */ -export interface IOscHandler { - /** - * Announces start of this OSC command. - * Prepare needed data structures here. - */ - start(): void; - /** - * Incoming data chunk. - * Note: Data is borrowed. - */ - put(data: Uint32Array, start: number, end: number): void; - /** - * End of OSC command. `success` indicates whether the - * command finished normally or got aborted, thus final - * execution of the command should depend on `success`. - * To save memory also cleanup data structures here. - */ - end(success: boolean): boolean | Promise<boolean>; -} -export type OscFallbackHandlerType = (ident: number, action: 'START' | 'PUT' | 'END', payload?: any) => void; - -/** - * PRINT handler types. - */ -export type PrintHandlerType = (data: Uint32Array, start: number, end: number) => void; -export type PrintFallbackHandlerType = PrintHandlerType; - - -/** -* EscapeSequenceParser interface. -*/ -export interface IEscapeSequenceParser extends IDisposable { - /** - * Preceding codepoint to get REP working correctly. - * This must be set by the print handler as last action. - * It gets reset by the parser for any valid sequence beside REP itself. - */ - precedingCodepoint: number; - - /** - * Reset the parser to its initial state (handlers are kept). - */ - reset(): void; - - /** - * Parse UTF32 codepoints in `data` up to `length`. - * @param data The data to parse. - */ - parse(data: Uint32Array, length: number, promiseResult?: boolean): void | Promise<boolean>; - - /** - * Get string from numercial function identifier `ident`. - * Useful in fallback handlers which expose the low level - * numcerical function identifier for debugging purposes. - * Note: A full back translation to `IFunctionIdentifier` - * is not implemented. - */ - identToString(ident: number): string; - - setPrintHandler(handler: PrintHandlerType): void; - clearPrintHandler(): void; - - registerEscHandler(id: IFunctionIdentifier, handler: EscHandlerType): IDisposable; - clearEscHandler(id: IFunctionIdentifier): void; - setEscHandlerFallback(handler: EscFallbackHandlerType): void; - - setExecuteHandler(flag: string, handler: ExecuteHandlerType): void; - clearExecuteHandler(flag: string): void; - setExecuteHandlerFallback(handler: ExecuteFallbackHandlerType): void; - - registerCsiHandler(id: IFunctionIdentifier, handler: CsiHandlerType): IDisposable; - clearCsiHandler(id: IFunctionIdentifier): void; - setCsiHandlerFallback(callback: CsiFallbackHandlerType): void; - - registerDcsHandler(id: IFunctionIdentifier, handler: IDcsHandler): IDisposable; - clearDcsHandler(id: IFunctionIdentifier): void; - setDcsHandlerFallback(handler: DcsFallbackHandlerType): void; - - registerOscHandler(ident: number, handler: IOscHandler): IDisposable; - clearOscHandler(ident: number): void; - setOscHandlerFallback(handler: OscFallbackHandlerType): void; - - setErrorHandler(handler: (state: IParsingState) => IParsingState): void; - clearErrorHandler(): void; -} - -/** - * Subparser interfaces. - * The subparsers are instantiated in `EscapeSequenceParser` and - * called during `EscapeSequenceParser.parse`. - */ -export interface ISubParser<T, U> extends IDisposable { - reset(): void; - registerHandler(ident: number, handler: T): IDisposable; - clearHandler(ident: number): void; - setHandlerFallback(handler: U): void; - put(data: Uint32Array, start: number, end: number): void; -} - -export interface IOscParser extends ISubParser<IOscHandler, OscFallbackHandlerType> { - start(): void; - end(success: boolean, promiseResult?: boolean): void | Promise<boolean>; -} - -export interface IDcsParser extends ISubParser<IDcsHandler, DcsFallbackHandlerType> { - hook(ident: number, params: IParams): void; - unhook(success: boolean, promiseResult?: boolean): void | Promise<boolean>; -} - -/** - * Interface to denote a specific ESC, CSI or DCS handler slot. - * The values are used to create an integer respresentation during handler - * regristation before passed to the subparsers as `ident`. - * The integer translation is made to allow a faster handler access - * in `EscapeSequenceParser.parse`. - */ -export interface IFunctionIdentifier { - prefix?: string; - intermediates?: string; - final: string; -} - -export interface IHandlerCollection<T> { - [key: string]: T[]; -} - -/** - * Types for async parser support. - */ - -// type of saved stack state in parser -export const enum ParserStackType { - NONE = 0, - FAIL, - RESET, - CSI, - ESC, - OSC, - DCS -} - -// aggregate of resumable handler lists -export type ResumableHandlersType = CsiHandlerType[] | EscHandlerType[]; - -// saved stack state of the parser -export interface IParserStackState { - state: ParserStackType; - handlers: ResumableHandlersType; - handlerPos: number; - transition: number; - chunkPos: number; -} - -// saved stack state of subparser (OSC and DCS) -export interface ISubParserStackState { - paused: boolean; - loopPosition: number; - fallThrough: boolean; -} diff --git a/node_modules/xterm/src/common/public/AddonManager.ts b/node_modules/xterm/src/common/public/AddonManager.ts deleted file mode 100644 index 06c7812..0000000 --- a/node_modules/xterm/src/common/public/AddonManager.ts +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { ITerminalAddon, IDisposable, Terminal } from 'xterm'; - -export interface ILoadedAddon { - instance: ITerminalAddon; - dispose: () => void; - isDisposed: boolean; -} - -export class AddonManager implements IDisposable { - protected _addons: ILoadedAddon[] = []; - - constructor() { - } - - public dispose(): void { - for (let i = this._addons.length - 1; i >= 0; i--) { - this._addons[i].instance.dispose(); - } - } - - public loadAddon(terminal: Terminal, instance: ITerminalAddon): void { - const loadedAddon: ILoadedAddon = { - instance, - dispose: instance.dispose, - isDisposed: false - }; - this._addons.push(loadedAddon); - instance.dispose = () => this._wrappedAddonDispose(loadedAddon); - instance.activate(terminal as any); - } - - private _wrappedAddonDispose(loadedAddon: ILoadedAddon): void { - if (loadedAddon.isDisposed) { - // Do nothing if already disposed - return; - } - let index = -1; - for (let i = 0; i < this._addons.length; i++) { - if (this._addons[i] === loadedAddon) { - index = i; - break; - } - } - if (index === -1) { - throw new Error('Could not dispose an addon that has not been loaded'); - } - loadedAddon.isDisposed = true; - loadedAddon.dispose.apply(loadedAddon.instance); - this._addons.splice(index, 1); - } -} diff --git a/node_modules/xterm/src/common/public/BufferApiView.ts b/node_modules/xterm/src/common/public/BufferApiView.ts deleted file mode 100644 index ca9ef2d..0000000 --- a/node_modules/xterm/src/common/public/BufferApiView.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2021 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IBuffer as IBufferApi, IBufferLine as IBufferLineApi, IBufferCell as IBufferCellApi } from 'xterm'; -import { IBuffer } from 'common/buffer/Types'; -import { BufferLineApiView } from 'common/public/BufferLineApiView'; -import { CellData } from 'common/buffer/CellData'; - -export class BufferApiView implements IBufferApi { - constructor( - private _buffer: IBuffer, - public readonly type: 'normal' | 'alternate' - ) { } - - public init(buffer: IBuffer): BufferApiView { - this._buffer = buffer; - return this; - } - - public get cursorY(): number { return this._buffer.y; } - public get cursorX(): number { return this._buffer.x; } - public get viewportY(): number { return this._buffer.ydisp; } - public get baseY(): number { return this._buffer.ybase; } - public get length(): number { return this._buffer.lines.length; } - public getLine(y: number): IBufferLineApi | undefined { - const line = this._buffer.lines.get(y); - if (!line) { - return undefined; - } - return new BufferLineApiView(line); - } - public getNullCell(): IBufferCellApi { return new CellData(); } -} diff --git a/node_modules/xterm/src/common/public/BufferLineApiView.ts b/node_modules/xterm/src/common/public/BufferLineApiView.ts deleted file mode 100644 index 6037501..0000000 --- a/node_modules/xterm/src/common/public/BufferLineApiView.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) 2021 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { CellData } from 'common/buffer/CellData'; -import { IBufferLine, ICellData } from 'common/Types'; -import { IBufferCell as IBufferCellApi, IBufferLine as IBufferLineApi } from 'xterm'; - -export class BufferLineApiView implements IBufferLineApi { - constructor(private _line: IBufferLine) { } - - public get isWrapped(): boolean { return this._line.isWrapped; } - public get length(): number { return this._line.length; } - public getCell(x: number, cell?: IBufferCellApi): IBufferCellApi | undefined { - if (x < 0 || x >= this._line.length) { - return undefined; - } - - if (cell) { - this._line.loadCell(x, cell as ICellData); - return cell; - } - return this._line.loadCell(x, new CellData()); - } - public translateToString(trimRight?: boolean, startColumn?: number, endColumn?: number): string { - return this._line.translateToString(trimRight, startColumn, endColumn); - } -} diff --git a/node_modules/xterm/src/common/public/BufferNamespaceApi.ts b/node_modules/xterm/src/common/public/BufferNamespaceApi.ts deleted file mode 100644 index d86f6bf..0000000 --- a/node_modules/xterm/src/common/public/BufferNamespaceApi.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2021 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IBuffer as IBufferApi, IBufferNamespace as IBufferNamespaceApi } from 'xterm'; -import { BufferApiView } from 'common/public/BufferApiView'; -import { IEvent, EventEmitter } from 'common/EventEmitter'; -import { ICoreTerminal } from 'common/Types'; - -export class BufferNamespaceApi implements IBufferNamespaceApi { - private _normal: BufferApiView; - private _alternate: BufferApiView; - private _onBufferChange = new EventEmitter<IBufferApi>(); - public get onBufferChange(): IEvent<IBufferApi> { return this._onBufferChange.event; } - - constructor(private _core: ICoreTerminal) { - this._normal = new BufferApiView(this._core.buffers.normal, 'normal'); - this._alternate = new BufferApiView(this._core.buffers.alt, 'alternate'); - this._core.buffers.onBufferActivate(() => this._onBufferChange.fire(this.active)); - } - public get active(): IBufferApi { - if (this._core.buffers.active === this._core.buffers.normal) { return this.normal; } - if (this._core.buffers.active === this._core.buffers.alt) { return this.alternate; } - throw new Error('Active buffer is neither normal nor alternate'); - } - public get normal(): IBufferApi { - return this._normal.init(this._core.buffers.normal); - } - public get alternate(): IBufferApi { - return this._alternate.init(this._core.buffers.alt); - } -} diff --git a/node_modules/xterm/src/common/public/ParserApi.ts b/node_modules/xterm/src/common/public/ParserApi.ts deleted file mode 100644 index 67df4be..0000000 --- a/node_modules/xterm/src/common/public/ParserApi.ts +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2021 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IParams } from 'common/parser/Types'; -import { IDisposable, IFunctionIdentifier, IParser } from 'xterm'; -import { ICoreTerminal } from 'common/Types'; - -export class ParserApi implements IParser { - constructor(private _core: ICoreTerminal) { } - - public registerCsiHandler(id: IFunctionIdentifier, callback: (params: (number | number[])[]) => boolean | Promise<boolean>): IDisposable { - return this._core.registerCsiHandler(id, (params: IParams) => callback(params.toArray())); - } - public addCsiHandler(id: IFunctionIdentifier, callback: (params: (number | number[])[]) => boolean | Promise<boolean>): IDisposable { - return this.registerCsiHandler(id, callback); - } - public registerDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: (number | number[])[]) => boolean | Promise<boolean>): IDisposable { - return this._core.registerDcsHandler(id, (data: string, params: IParams) => callback(data, params.toArray())); - } - public addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: (number | number[])[]) => boolean | Promise<boolean>): IDisposable { - return this.registerDcsHandler(id, callback); - } - public registerEscHandler(id: IFunctionIdentifier, handler: () => boolean | Promise<boolean>): IDisposable { - return this._core.registerEscHandler(id, handler); - } - public addEscHandler(id: IFunctionIdentifier, handler: () => boolean | Promise<boolean>): IDisposable { - return this.registerEscHandler(id, handler); - } - public registerOscHandler(ident: number, callback: (data: string) => boolean | Promise<boolean>): IDisposable { - return this._core.registerOscHandler(ident, callback); - } - public addOscHandler(ident: number, callback: (data: string) => boolean | Promise<boolean>): IDisposable { - return this.registerOscHandler(ident, callback); - } -} diff --git a/node_modules/xterm/src/common/public/UnicodeApi.ts b/node_modules/xterm/src/common/public/UnicodeApi.ts deleted file mode 100644 index 8a669a0..0000000 --- a/node_modules/xterm/src/common/public/UnicodeApi.ts +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2021 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { ICoreTerminal } from 'common/Types'; -import { IUnicodeHandling, IUnicodeVersionProvider } from 'xterm'; - -export class UnicodeApi implements IUnicodeHandling { - constructor(private _core: ICoreTerminal) { } - - public register(provider: IUnicodeVersionProvider): void { - this._core.unicodeService.register(provider); - } - - public get versions(): string[] { - return this._core.unicodeService.versions; - } - - public get activeVersion(): string { - return this._core.unicodeService.activeVersion; - } - - public set activeVersion(version: string) { - this._core.unicodeService.activeVersion = version; - } -} diff --git a/node_modules/xterm/src/common/services/BufferService.ts b/node_modules/xterm/src/common/services/BufferService.ts deleted file mode 100644 index bba60dd..0000000 --- a/node_modules/xterm/src/common/services/BufferService.ts +++ /dev/null @@ -1,185 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IBufferService, IOptionsService } from 'common/services/Services'; -import { BufferSet } from 'common/buffer/BufferSet'; -import { IBufferSet, IBuffer } from 'common/buffer/Types'; -import { EventEmitter, IEvent } from 'common/EventEmitter'; -import { Disposable } from 'common/Lifecycle'; -import { IAttributeData, IBufferLine, ScrollSource } from 'common/Types'; - -export const MINIMUM_COLS = 2; // Less than 2 can mess with wide chars -export const MINIMUM_ROWS = 1; - -export class BufferService extends Disposable implements IBufferService { - public serviceBrand: any; - - public cols: number; - public rows: number; - public buffers: IBufferSet; - /** Whether the user is scrolling (locks the scroll position) */ - public isUserScrolling: boolean = false; - - private _onResize = new EventEmitter<{ cols: number, rows: number }>(); - public get onResize(): IEvent<{ cols: number, rows: number }> { return this._onResize.event; } - private _onScroll = new EventEmitter<number>(); - public get onScroll(): IEvent<number> { return this._onScroll.event; } - - public get buffer(): IBuffer { return this.buffers.active; } - - /** An IBufferline to clone/copy from for new blank lines */ - private _cachedBlankLine: IBufferLine | undefined; - - constructor( - @IOptionsService private _optionsService: IOptionsService - ) { - super(); - this.cols = Math.max(_optionsService.rawOptions.cols || 0, MINIMUM_COLS); - this.rows = Math.max(_optionsService.rawOptions.rows || 0, MINIMUM_ROWS); - this.buffers = new BufferSet(_optionsService, this); - } - - public dispose(): void { - super.dispose(); - this.buffers.dispose(); - } - - public resize(cols: number, rows: number): void { - this.cols = cols; - this.rows = rows; - this.buffers.resize(cols, rows); - this.buffers.setupTabStops(this.cols); - this._onResize.fire({ cols, rows }); - } - - public reset(): void { - this.buffers.reset(); - this.isUserScrolling = false; - } - - /** - * Scroll the terminal down 1 row, creating a blank line. - * @param isWrapped Whether the new line is wrapped from the previous line. - */ - public scroll(eraseAttr: IAttributeData, isWrapped: boolean = false): void { - const buffer = this.buffer; - - let newLine: IBufferLine | undefined; - newLine = this._cachedBlankLine; - if (!newLine || newLine.length !== this.cols || newLine.getFg(0) !== eraseAttr.fg || newLine.getBg(0) !== eraseAttr.bg) { - newLine = buffer.getBlankLine(eraseAttr, isWrapped); - this._cachedBlankLine = newLine; - } - newLine.isWrapped = isWrapped; - - const topRow = buffer.ybase + buffer.scrollTop; - const bottomRow = buffer.ybase + buffer.scrollBottom; - - if (buffer.scrollTop === 0) { - // Determine whether the buffer is going to be trimmed after insertion. - const willBufferBeTrimmed = buffer.lines.isFull; - - // Insert the line using the fastest method - if (bottomRow === buffer.lines.length - 1) { - if (willBufferBeTrimmed) { - buffer.lines.recycle().copyFrom(newLine); - } else { - buffer.lines.push(newLine.clone()); - } - } else { - buffer.lines.splice(bottomRow + 1, 0, newLine.clone()); - } - - // Only adjust ybase and ydisp when the buffer is not trimmed - if (!willBufferBeTrimmed) { - buffer.ybase++; - // Only scroll the ydisp with ybase if the user has not scrolled up - if (!this.isUserScrolling) { - buffer.ydisp++; - } - } else { - // When the buffer is full and the user has scrolled up, keep the text - // stable unless ydisp is right at the top - if (this.isUserScrolling) { - buffer.ydisp = Math.max(buffer.ydisp - 1, 0); - } - } - } else { - // scrollTop is non-zero which means no line will be going to the - // scrollback, instead we can just shift them in-place. - const scrollRegionHeight = bottomRow - topRow + 1 /* as it's zero-based */; - buffer.lines.shiftElements(topRow + 1, scrollRegionHeight - 1, -1); - buffer.lines.set(bottomRow, newLine.clone()); - } - - // Move the viewport to the bottom of the buffer unless the user is - // scrolling. - if (!this.isUserScrolling) { - buffer.ydisp = buffer.ybase; - } - - this._onScroll.fire(buffer.ydisp); - } - - /** - * Scroll the display of the terminal - * @param disp The number of lines to scroll down (negative scroll up). - * @param suppressScrollEvent Don't emit the scroll event as scrollLines. This is used - * to avoid unwanted events being handled by the viewport when the event was triggered from the - * viewport originally. - */ - public scrollLines(disp: number, suppressScrollEvent?: boolean, source?: ScrollSource): void { - const buffer = this.buffer; - if (disp < 0) { - if (buffer.ydisp === 0) { - return; - } - this.isUserScrolling = true; - } else if (disp + buffer.ydisp >= buffer.ybase) { - this.isUserScrolling = false; - } - - const oldYdisp = buffer.ydisp; - buffer.ydisp = Math.max(Math.min(buffer.ydisp + disp, buffer.ybase), 0); - - // No change occurred, don't trigger scroll/refresh - if (oldYdisp === buffer.ydisp) { - return; - } - - if (!suppressScrollEvent) { - this._onScroll.fire(buffer.ydisp); - } - } - - /** - * Scroll the display of the terminal by a number of pages. - * @param pageCount The number of pages to scroll (negative scrolls up). - */ - public scrollPages(pageCount: number): void { - this.scrollLines(pageCount * (this.rows - 1)); - } - - /** - * Scrolls the display of the terminal to the top. - */ - public scrollToTop(): void { - this.scrollLines(-this.buffer.ydisp); - } - - /** - * Scrolls the display of the terminal to the bottom. - */ - public scrollToBottom(): void { - this.scrollLines(this.buffer.ybase - this.buffer.ydisp); - } - - public scrollToLine(line: number): void { - const scrollAmount = line - this.buffer.ydisp; - if (scrollAmount !== 0) { - this.scrollLines(scrollAmount); - } - } -} diff --git a/node_modules/xterm/src/common/services/CharsetService.ts b/node_modules/xterm/src/common/services/CharsetService.ts deleted file mode 100644 index c538106..0000000 --- a/node_modules/xterm/src/common/services/CharsetService.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { ICharsetService } from 'common/services/Services'; -import { ICharset } from 'common/Types'; - -export class CharsetService implements ICharsetService { - public serviceBrand: any; - - public charset: ICharset | undefined; - public glevel: number = 0; - - private _charsets: (ICharset | undefined)[] = []; - - public reset(): void { - this.charset = undefined; - this._charsets = []; - this.glevel = 0; - } - - public setgLevel(g: number): void { - this.glevel = g; - this.charset = this._charsets[g]; - } - - public setgCharset(g: number, charset: ICharset | undefined): void { - this._charsets[g] = charset; - if (this.glevel === g) { - this.charset = charset; - } - } -} diff --git a/node_modules/xterm/src/common/services/CoreMouseService.ts b/node_modules/xterm/src/common/services/CoreMouseService.ts deleted file mode 100644 index 0b0dc36..0000000 --- a/node_modules/xterm/src/common/services/CoreMouseService.ts +++ /dev/null @@ -1,309 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ -import { IBufferService, ICoreService, ICoreMouseService } from 'common/services/Services'; -import { EventEmitter, IEvent } from 'common/EventEmitter'; -import { ICoreMouseProtocol, ICoreMouseEvent, CoreMouseEncoding, CoreMouseEventType, CoreMouseButton, CoreMouseAction } from 'common/Types'; - -/** - * Supported default protocols. - */ -const DEFAULT_PROTOCOLS: {[key: string]: ICoreMouseProtocol} = { - /** - * NONE - * Events: none - * Modifiers: none - */ - NONE: { - events: CoreMouseEventType.NONE, - restrict: () => false - }, - /** - * X10 - * Events: mousedown - * Modifiers: none - */ - X10: { - events: CoreMouseEventType.DOWN, - restrict: (e: ICoreMouseEvent) => { - // no wheel, no move, no up - if (e.button === CoreMouseButton.WHEEL || e.action !== CoreMouseAction.DOWN) { - return false; - } - // no modifiers - e.ctrl = false; - e.alt = false; - e.shift = false; - return true; - } - }, - /** - * VT200 - * Events: mousedown / mouseup / wheel - * Modifiers: all - */ - VT200: { - events: CoreMouseEventType.DOWN | CoreMouseEventType.UP | CoreMouseEventType.WHEEL, - restrict: (e: ICoreMouseEvent) => { - // no move - if (e.action === CoreMouseAction.MOVE) { - return false; - } - return true; - } - }, - /** - * DRAG - * Events: mousedown / mouseup / wheel / mousedrag - * Modifiers: all - */ - DRAG: { - events: CoreMouseEventType.DOWN | CoreMouseEventType.UP | CoreMouseEventType.WHEEL | CoreMouseEventType.DRAG, - restrict: (e: ICoreMouseEvent) => { - // no move without button - if (e.action === CoreMouseAction.MOVE && e.button === CoreMouseButton.NONE) { - return false; - } - return true; - } - }, - /** - * ANY - * Events: all mouse related events - * Modifiers: all - */ - ANY: { - events: - CoreMouseEventType.DOWN | CoreMouseEventType.UP | CoreMouseEventType.WHEEL - | CoreMouseEventType.DRAG | CoreMouseEventType.MOVE, - restrict: (e: ICoreMouseEvent) => true - } -}; - -const enum Modifiers { - SHIFT = 4, - ALT = 8, - CTRL = 16 -} - -// helper for default encoders to generate the event code. -function eventCode(e: ICoreMouseEvent, isSGR: boolean): number { - let code = (e.ctrl ? Modifiers.CTRL : 0) | (e.shift ? Modifiers.SHIFT : 0) | (e.alt ? Modifiers.ALT : 0); - if (e.button === CoreMouseButton.WHEEL) { - code |= 64; - code |= e.action; - } else { - code |= e.button & 3; - if (e.button & 4) { - code |= 64; - } - if (e.button & 8) { - code |= 128; - } - if (e.action === CoreMouseAction.MOVE) { - code |= CoreMouseAction.MOVE; - } else if (e.action === CoreMouseAction.UP && !isSGR) { - // special case - only SGR can report button on release - // all others have to go with NONE - code |= CoreMouseButton.NONE; - } - } - return code; -} - -const S = String.fromCharCode; - -/** - * Supported default encodings. - */ -const DEFAULT_ENCODINGS: {[key: string]: CoreMouseEncoding} = { - /** - * DEFAULT - CSI M Pb Px Py - * Single byte encoding for coords and event code. - * Can encode values up to 223 (1-based). - */ - DEFAULT: (e: ICoreMouseEvent) => { - const params = [eventCode(e, false) + 32, e.col + 32, e.row + 32]; - // supress mouse report if we exceed addressible range - // Note this is handled differently by emulators - // - xterm: sends 0;0 coords instead - // - vte, konsole: no report - if (params[0] > 255 || params[1] > 255 || params[2] > 255) { - return ''; - } - return `\x1b[M${S(params[0])}${S(params[1])}${S(params[2])}`; - }, - /** - * SGR - CSI < Pb ; Px ; Py M|m - * No encoding limitation. - * Can report button on release and works with a well formed sequence. - */ - SGR: (e: ICoreMouseEvent) => { - const final = (e.action === CoreMouseAction.UP && e.button !== CoreMouseButton.WHEEL) ? 'm' : 'M'; - return `\x1b[<${eventCode(e, true)};${e.col};${e.row}${final}`; - } -}; - -/** - * CoreMouseService - * - * Provides mouse tracking reports with different protocols and encodings. - * - protocols: NONE (default), X10, VT200, DRAG, ANY - * - encodings: DEFAULT, SGR (UTF8, URXVT removed in #2507) - * - * Custom protocols/encodings can be added by `addProtocol` / `addEncoding`. - * To activate a protocol/encoding, set `activeProtocol` / `activeEncoding`. - * Switching a protocol will send a notification event `onProtocolChange` - * with a list of needed events to track. - * - * The service handles the mouse tracking state and decides whether to send - * a tracking report to the backend based on protocol and encoding limitations. - * To send a mouse event call `triggerMouseEvent`. - */ -export class CoreMouseService implements ICoreMouseService { - private _protocols: {[name: string]: ICoreMouseProtocol} = {}; - private _encodings: {[name: string]: CoreMouseEncoding} = {}; - private _activeProtocol: string = ''; - private _activeEncoding: string = ''; - private _onProtocolChange = new EventEmitter<CoreMouseEventType>(); - private _lastEvent: ICoreMouseEvent | null = null; - - constructor( - @IBufferService private readonly _bufferService: IBufferService, - @ICoreService private readonly _coreService: ICoreService - ) { - // register default protocols and encodings - for (const name of Object.keys(DEFAULT_PROTOCOLS)) this.addProtocol(name, DEFAULT_PROTOCOLS[name]); - for (const name of Object.keys(DEFAULT_ENCODINGS)) this.addEncoding(name, DEFAULT_ENCODINGS[name]); - // call reset to set defaults - this.reset(); - } - - public addProtocol(name: string, protocol: ICoreMouseProtocol): void { - this._protocols[name] = protocol; - } - - public addEncoding(name: string, encoding: CoreMouseEncoding): void { - this._encodings[name] = encoding; - } - - public get activeProtocol(): string { - return this._activeProtocol; - } - - public get areMouseEventsActive(): boolean { - return this._protocols[this._activeProtocol].events !== 0; - } - - public set activeProtocol(name: string) { - if (!this._protocols[name]) { - throw new Error(`unknown protocol "${name}"`); - } - this._activeProtocol = name; - this._onProtocolChange.fire(this._protocols[name].events); - } - - public get activeEncoding(): string { - return this._activeEncoding; - } - - public set activeEncoding(name: string) { - if (!this._encodings[name]) { - throw new Error(`unknown encoding "${name}"`); - } - this._activeEncoding = name; - } - - public reset(): void { - this.activeProtocol = 'NONE'; - this.activeEncoding = 'DEFAULT'; - this._lastEvent = null; - } - - /** - * Event to announce changes in mouse tracking. - */ - public get onProtocolChange(): IEvent<CoreMouseEventType> { - return this._onProtocolChange.event; - } - - /** - * Triggers a mouse event to be sent. - * - * Returns true if the event passed all protocol restrictions and a report - * was sent, otherwise false. The return value may be used to decide whether - * the default event action in the bowser component should be omitted. - * - * Note: The method will change values of the given event object - * to fullfill protocol and encoding restrictions. - */ - public triggerMouseEvent(e: ICoreMouseEvent): boolean { - // range check for col/row - if (e.col < 0 || e.col >= this._bufferService.cols - || e.row < 0 || e.row >= this._bufferService.rows) { - return false; - } - - // filter nonsense combinations of button + action - if (e.button === CoreMouseButton.WHEEL && e.action === CoreMouseAction.MOVE) { - return false; - } - if (e.button === CoreMouseButton.NONE && e.action !== CoreMouseAction.MOVE) { - return false; - } - if (e.button !== CoreMouseButton.WHEEL && (e.action === CoreMouseAction.LEFT || e.action === CoreMouseAction.RIGHT)) { - return false; - } - - // report 1-based coords - e.col++; - e.row++; - - // debounce move at grid level - if (e.action === CoreMouseAction.MOVE && this._lastEvent && this._compareEvents(this._lastEvent, e)) { - return false; - } - - // apply protocol restrictions - if (!this._protocols[this._activeProtocol].restrict(e)) { - return false; - } - - // encode report and send - const report = this._encodings[this._activeEncoding](e); - if (report) { - // always send DEFAULT as binary data - if (this._activeEncoding === 'DEFAULT') { - this._coreService.triggerBinaryEvent(report); - } else { - this._coreService.triggerDataEvent(report, true); - } - } - - this._lastEvent = e; - - return true; - } - - public explainEvents(events: CoreMouseEventType): {[event: string]: boolean} { - return { - down: !!(events & CoreMouseEventType.DOWN), - up: !!(events & CoreMouseEventType.UP), - drag: !!(events & CoreMouseEventType.DRAG), - move: !!(events & CoreMouseEventType.MOVE), - wheel: !!(events & CoreMouseEventType.WHEEL) - }; - } - - private _compareEvents(e1: ICoreMouseEvent, e2: ICoreMouseEvent): boolean { - if (e1.col !== e2.col) return false; - if (e1.row !== e2.row) return false; - if (e1.button !== e2.button) return false; - if (e1.action !== e2.action) return false; - if (e1.ctrl !== e2.ctrl) return false; - if (e1.alt !== e2.alt) return false; - if (e1.shift !== e2.shift) return false; - return true; - } -} diff --git a/node_modules/xterm/src/common/services/CoreService.ts b/node_modules/xterm/src/common/services/CoreService.ts deleted file mode 100644 index 20a3460..0000000 --- a/node_modules/xterm/src/common/services/CoreService.ts +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { ICoreService, ILogService, IOptionsService, IBufferService } from 'common/services/Services'; -import { EventEmitter, IEvent } from 'common/EventEmitter'; -import { IDecPrivateModes, IModes } from 'common/Types'; -import { clone } from 'common/Clone'; -import { Disposable } from 'common/Lifecycle'; - -const DEFAULT_MODES: IModes = Object.freeze({ - insertMode: false -}); - -const DEFAULT_DEC_PRIVATE_MODES: IDecPrivateModes = Object.freeze({ - applicationCursorKeys: false, - applicationKeypad: false, - bracketedPasteMode: false, - origin: false, - reverseWraparound: false, - sendFocus: false, - wraparound: true // defaults: xterm - true, vt100 - false -}); - -export class CoreService extends Disposable implements ICoreService { - public serviceBrand: any; - - public isCursorInitialized: boolean = false; - public isCursorHidden: boolean = false; - public modes: IModes; - public decPrivateModes: IDecPrivateModes; - - // Circular dependency, this must be unset or memory will leak after Terminal.dispose - private _scrollToBottom: (() => void) | undefined; - - private _onData = this.register(new EventEmitter<string>()); - public get onData(): IEvent<string> { return this._onData.event; } - private _onUserInput = this.register(new EventEmitter<void>()); - public get onUserInput(): IEvent<void> { return this._onUserInput.event; } - private _onBinary = this.register(new EventEmitter<string>()); - public get onBinary(): IEvent<string> { return this._onBinary.event; } - - constructor( - // TODO: Move this into a service - scrollToBottom: () => void, - @IBufferService private readonly _bufferService: IBufferService, - @ILogService private readonly _logService: ILogService, - @IOptionsService private readonly _optionsService: IOptionsService - ) { - super(); - this._scrollToBottom = scrollToBottom; - this.register({ dispose: () => this._scrollToBottom = undefined }); - this.modes = clone(DEFAULT_MODES); - this.decPrivateModes = clone(DEFAULT_DEC_PRIVATE_MODES); - } - - public reset(): void { - this.modes = clone(DEFAULT_MODES); - this.decPrivateModes = clone(DEFAULT_DEC_PRIVATE_MODES); - } - - public triggerDataEvent(data: string, wasUserInput: boolean = false): void { - // Prevents all events to pty process if stdin is disabled - if (this._optionsService.rawOptions.disableStdin) { - return; - } - - // Input is being sent to the terminal, the terminal should focus the prompt. - const buffer = this._bufferService.buffer; - if (buffer.ybase !== buffer.ydisp) { - this._scrollToBottom!(); - } - - // Fire onUserInput so listeners can react as well (eg. clear selection) - if (wasUserInput) { - this._onUserInput.fire(); - } - - // Fire onData API - this._logService.debug(`sending data "${data}"`, () => data.split('').map(e => e.charCodeAt(0))); - this._onData.fire(data); - } - - public triggerBinaryEvent(data: string): void { - if (this._optionsService.rawOptions.disableStdin) { - return; - } - this._logService.debug(`sending binary "${data}"`, () => data.split('').map(e => e.charCodeAt(0))); - this._onBinary.fire(data); - } -} diff --git a/node_modules/xterm/src/common/services/DirtyRowService.ts b/node_modules/xterm/src/common/services/DirtyRowService.ts deleted file mode 100644 index 1c43b67..0000000 --- a/node_modules/xterm/src/common/services/DirtyRowService.ts +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IBufferService, IDirtyRowService } from 'common/services/Services'; - -export class DirtyRowService implements IDirtyRowService { - public serviceBrand: any; - - private _start!: number; - private _end!: number; - - public get start(): number { return this._start; } - public get end(): number { return this._end; } - - constructor( - @IBufferService private readonly _bufferService: IBufferService - ) { - this.clearRange(); - } - - public clearRange(): void { - this._start = this._bufferService.buffer.y; - this._end = this._bufferService.buffer.y; - } - - public markDirty(y: number): void { - if (y < this._start) { - this._start = y; - } else if (y > this._end) { - this._end = y; - } - } - - public markRangeDirty(y1: number, y2: number): void { - if (y1 > y2) { - const temp = y1; - y1 = y2; - y2 = temp; - } - if (y1 < this._start) { - this._start = y1; - } - if (y2 > this._end) { - this._end = y2; - } - } - - public markAllDirty(): void { - this.markRangeDirty(0, this._bufferService.rows - 1); - } -} diff --git a/node_modules/xterm/src/common/services/InstantiationService.ts b/node_modules/xterm/src/common/services/InstantiationService.ts deleted file mode 100644 index 8280948..0000000 --- a/node_modules/xterm/src/common/services/InstantiationService.ts +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - * - * This was heavily inspired from microsoft/vscode's dependency injection system (MIT). - */ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IInstantiationService, IServiceIdentifier } from 'common/services/Services'; -import { getServiceDependencies } from 'common/services/ServiceRegistry'; - -export class ServiceCollection { - - private _entries = new Map<IServiceIdentifier<any>, any>(); - - constructor(...entries: [IServiceIdentifier<any>, any][]) { - for (const [id, service] of entries) { - this.set(id, service); - } - } - - public set<T>(id: IServiceIdentifier<T>, instance: T): T { - const result = this._entries.get(id); - this._entries.set(id, instance); - return result; - } - - public forEach(callback: (id: IServiceIdentifier<any>, instance: any) => any): void { - this._entries.forEach((value, key) => callback(key, value)); - } - - public has(id: IServiceIdentifier<any>): boolean { - return this._entries.has(id); - } - - public get<T>(id: IServiceIdentifier<T>): T | undefined { - return this._entries.get(id); - } -} - -export class InstantiationService implements IInstantiationService { - public serviceBrand: undefined; - - private readonly _services: ServiceCollection = new ServiceCollection(); - - constructor() { - this._services.set(IInstantiationService, this); - } - - public setService<T>(id: IServiceIdentifier<T>, instance: T): void { - this._services.set(id, instance); - } - - public getService<T>(id: IServiceIdentifier<T>): T | undefined { - return this._services.get(id); - } - - public createInstance<T>(ctor: any, ...args: any[]): T { - const serviceDependencies = getServiceDependencies(ctor).sort((a, b) => a.index - b.index); - - const serviceArgs: any[] = []; - for (const dependency of serviceDependencies) { - const service = this._services.get(dependency.id); - if (!service) { - throw new Error(`[createInstance] ${ctor.name} depends on UNKNOWN service ${dependency.id}.`); - } - serviceArgs.push(service); - } - - const firstServiceArgPos = serviceDependencies.length > 0 ? serviceDependencies[0].index : args.length; - - // check for argument mismatches, adjust static args if needed - if (args.length !== firstServiceArgPos) { - throw new Error(`[createInstance] First service dependency of ${ctor.name} at position ${firstServiceArgPos + 1} conflicts with ${args.length} static arguments`); - } - - // now create the instance - return new ctor(...[...args, ...serviceArgs]); - } -} diff --git a/node_modules/xterm/src/common/services/LogService.ts b/node_modules/xterm/src/common/services/LogService.ts deleted file mode 100644 index d356656..0000000 --- a/node_modules/xterm/src/common/services/LogService.ts +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { ILogService, IOptionsService, LogLevelEnum } from 'common/services/Services'; - -type LogType = (message?: any, ...optionalParams: any[]) => void; - -interface IConsole { - log: LogType; - error: LogType; - info: LogType; - trace: LogType; - warn: LogType; -} - -// console is available on both node.js and browser contexts but the common -// module doesn't depend on them so we need to explicitly declare it. -declare const console: IConsole; - -const optionsKeyToLogLevel: { [key: string]: LogLevelEnum } = { - debug: LogLevelEnum.DEBUG, - info: LogLevelEnum.INFO, - warn: LogLevelEnum.WARN, - error: LogLevelEnum.ERROR, - off: LogLevelEnum.OFF -}; - -const LOG_PREFIX = 'xterm.js: '; - -export class LogService implements ILogService { - public serviceBrand: any; - - public logLevel: LogLevelEnum = LogLevelEnum.OFF; - - constructor( - @IOptionsService private readonly _optionsService: IOptionsService - ) { - this._updateLogLevel(); - this._optionsService.onOptionChange(key => { - if (key === 'logLevel') { - this._updateLogLevel(); - } - }); - } - - private _updateLogLevel(): void { - this.logLevel = optionsKeyToLogLevel[this._optionsService.rawOptions.logLevel]; - } - - private _evalLazyOptionalParams(optionalParams: any[]): void { - for (let i = 0; i < optionalParams.length; i++) { - if (typeof optionalParams[i] === 'function') { - optionalParams[i] = optionalParams[i](); - } - } - } - - private _log(type: LogType, message: string, optionalParams: any[]): void { - this._evalLazyOptionalParams(optionalParams); - type.call(console, LOG_PREFIX + message, ...optionalParams); - } - - public debug(message: string, ...optionalParams: any[]): void { - if (this.logLevel <= LogLevelEnum.DEBUG) { - this._log(console.log, message, optionalParams); - } - } - - public info(message: string, ...optionalParams: any[]): void { - if (this.logLevel <= LogLevelEnum.INFO) { - this._log(console.info, message, optionalParams); - } - } - - public warn(message: string, ...optionalParams: any[]): void { - if (this.logLevel <= LogLevelEnum.WARN) { - this._log(console.warn, message, optionalParams); - } - } - - public error(message: string, ...optionalParams: any[]): void { - if (this.logLevel <= LogLevelEnum.ERROR) { - this._log(console.error, message, optionalParams); - } - } -} diff --git a/node_modules/xterm/src/common/services/OptionsService.ts b/node_modules/xterm/src/common/services/OptionsService.ts deleted file mode 100644 index 43fe998..0000000 --- a/node_modules/xterm/src/common/services/OptionsService.ts +++ /dev/null @@ -1,177 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IOptionsService, ITerminalOptions, FontWeight } from 'common/services/Services'; -import { EventEmitter, IEvent } from 'common/EventEmitter'; -import { isMac } from 'common/Platform'; - -// Source: https://freesound.org/people/altemark/sounds/45759/ -// This sound is released under the Creative Commons Attribution 3.0 Unported -// (CC BY 3.0) license. It was created by 'altemark'. No modifications have been -// made, apart from the conversion to base64. -export const DEFAULT_BELL_SOUND = 'data:audio/mp3;base64,SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2ZjU4LjMyLjEwNAAAAAAAAAAAAAAA//tQxAADB8AhSmxhIIEVCSiJrDCQBTcu3UrAIwUdkRgQbFAZC1CQEwTJ9mjRvBA4UOLD8nKVOWfh+UlK3z/177OXrfOdKl7pyn3Xf//WreyTRUoAWgBgkOAGbZHBgG1OF6zM82DWbZaUmMBptgQhGjsyYqc9ae9XFz280948NMBWInljyzsNRFLPWdnZGWrddDsjK1unuSrVN9jJsK8KuQtQCtMBjCEtImISdNKJOopIpBFpNSMbIHCSRpRR5iakjTiyzLhchUUBwCgyKiweBv/7UsQbg8isVNoMPMjAAAA0gAAABEVFGmgqK////9bP/6XCykxBTUUzLjEwMKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'; - -export const DEFAULT_OPTIONS: Readonly<ITerminalOptions> = { - cols: 80, - rows: 24, - cursorBlink: false, - cursorStyle: 'block', - cursorWidth: 1, - customGlyphs: true, - bellSound: DEFAULT_BELL_SOUND, - bellStyle: 'none', - drawBoldTextInBrightColors: true, - fastScrollModifier: 'alt', - fastScrollSensitivity: 5, - fontFamily: 'courier-new, courier, monospace', - fontSize: 15, - fontWeight: 'normal', - fontWeightBold: 'bold', - lineHeight: 1.0, - linkTooltipHoverDuration: 500, - letterSpacing: 0, - logLevel: 'info', - scrollback: 1000, - scrollSensitivity: 1, - screenReaderMode: false, - macOptionIsMeta: false, - macOptionClickForcesSelection: false, - minimumContrastRatio: 1, - disableStdin: false, - allowProposedApi: true, - allowTransparency: false, - tabStopWidth: 8, - theme: {}, - rightClickSelectsWord: isMac, - rendererType: 'canvas', - windowOptions: {}, - windowsMode: false, - wordSeparator: ' ()[]{}\',"`', - altClickMovesCursor: true, - convertEol: false, - termName: 'xterm', - cancelEvents: false -}; - -const FONT_WEIGHT_OPTIONS: Extract<FontWeight, string>[] = ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900']; - -export class OptionsService implements IOptionsService { - public serviceBrand: any; - - public readonly rawOptions: ITerminalOptions; - public options: ITerminalOptions; - - private _onOptionChange = new EventEmitter<string>(); - public get onOptionChange(): IEvent<string> { return this._onOptionChange.event; } - - constructor(options: Partial<ITerminalOptions>) { - // set the default value of each option - const defaultOptions = { ...DEFAULT_OPTIONS }; - for (const key in options) { - if (key in defaultOptions) { - try { - const newValue = options[key]; - defaultOptions[key] = this._sanitizeAndValidateOption(key, newValue); - } catch (e) { - console.error(e); - } - } - } - - // set up getters and setters for each option - this.rawOptions = defaultOptions; - this.options = { ... defaultOptions }; - this._setupOptions(); - } - - private _setupOptions(): void { - const getter = (propName: string): any => { - if (!(propName in DEFAULT_OPTIONS)) { - throw new Error(`No option with key "${propName}"`); - } - return this.rawOptions[propName]; - }; - - const setter = (propName: string, value: any): void => { - if (!(propName in DEFAULT_OPTIONS)) { - throw new Error(`No option with key "${propName}"`); - } - - value = this._sanitizeAndValidateOption(propName, value); - // Don't fire an option change event if they didn't change - if (this.rawOptions[propName] !== value) { - this.rawOptions[propName] = value; - this._onOptionChange.fire(propName); - } - }; - - for (const propName in this.rawOptions) { - const desc = { - get: getter.bind(this, propName), - set: setter.bind(this, propName) - }; - Object.defineProperty(this.options, propName, desc); - } - } - - public setOption(key: string, value: any): void { - this.options[key] = value; - } - - private _sanitizeAndValidateOption(key: string, value: any): any { - switch (key) { - case 'bellStyle': - case 'cursorStyle': - case 'rendererType': - case 'wordSeparator': - if (!value) { - value = DEFAULT_OPTIONS[key]; - } - break; - case 'fontWeight': - case 'fontWeightBold': - if (typeof value === 'number' && 1 <= value && value <= 1000) { - // already valid numeric value - break; - } - value = FONT_WEIGHT_OPTIONS.includes(value) ? value : DEFAULT_OPTIONS[key]; - break; - case 'cursorWidth': - value = Math.floor(value); - // Fall through for bounds check - case 'lineHeight': - case 'tabStopWidth': - if (value < 1) { - throw new Error(`${key} cannot be less than 1, value: ${value}`); - } - break; - case 'minimumContrastRatio': - value = Math.max(1, Math.min(21, Math.round(value * 10) / 10)); - break; - case 'scrollback': - value = Math.min(value, 4294967295); - if (value < 0) { - throw new Error(`${key} cannot be less than 0, value: ${value}`); - } - break; - case 'fastScrollSensitivity': - case 'scrollSensitivity': - if (value <= 0) { - throw new Error(`${key} cannot be less than or equal to 0, value: ${value}`); - } - case 'rows': - case 'cols': - if (!value && value !== 0) { - throw new Error(`${key} must be numeric, value: ${value}`); - } - break; - } - return value; - } - - public getOption(key: string): any { - return this.options[key]; - } -} diff --git a/node_modules/xterm/src/common/services/ServiceRegistry.ts b/node_modules/xterm/src/common/services/ServiceRegistry.ts deleted file mode 100644 index 6510fb8..0000000 --- a/node_modules/xterm/src/common/services/ServiceRegistry.ts +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - * - * This was heavily inspired from microsoft/vscode's dependency injection system (MIT). - */ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IServiceIdentifier } from 'common/services/Services'; - -const DI_TARGET = 'di$target'; -const DI_DEPENDENCIES = 'di$dependencies'; - -export const serviceRegistry: Map<string, IServiceIdentifier<any>> = new Map(); - -export function getServiceDependencies(ctor: any): { id: IServiceIdentifier<any>, index: number, optional: boolean }[] { - return ctor[DI_DEPENDENCIES] || []; -} - -export function createDecorator<T>(id: string): IServiceIdentifier<T> { - if (serviceRegistry.has(id)) { - return serviceRegistry.get(id)!; - } - - const decorator: any = function (target: Function, key: string, index: number): any { - if (arguments.length !== 3) { - throw new Error('@IServiceName-decorator can only be used to decorate a parameter'); - } - - storeServiceDependency(decorator, target, index); - }; - - decorator.toString = () => id; - - serviceRegistry.set(id, decorator); - return decorator; -} - -function storeServiceDependency(id: Function, target: Function, index: number): void { - if ((target as any)[DI_TARGET] === target) { - (target as any)[DI_DEPENDENCIES].push({ id, index }); - } else { - (target as any)[DI_DEPENDENCIES] = [{ id, index }]; - (target as any)[DI_TARGET] = target; - } -} diff --git a/node_modules/xterm/src/common/services/Services.ts b/node_modules/xterm/src/common/services/Services.ts deleted file mode 100644 index 90dca98..0000000 --- a/node_modules/xterm/src/common/services/Services.ts +++ /dev/null @@ -1,300 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IEvent } from 'common/EventEmitter'; -import { IBuffer, IBufferSet } from 'common/buffer/Types'; -import { IDecPrivateModes, ICoreMouseEvent, CoreMouseEncoding, ICoreMouseProtocol, CoreMouseEventType, ICharset, IWindowOptions, IModes, IAttributeData, ScrollSource } from 'common/Types'; -import { createDecorator } from 'common/services/ServiceRegistry'; - -export const IBufferService = createDecorator<IBufferService>('BufferService'); -export interface IBufferService { - serviceBrand: undefined; - - readonly cols: number; - readonly rows: number; - readonly buffer: IBuffer; - readonly buffers: IBufferSet; - isUserScrolling: boolean; - onResize: IEvent<{ cols: number, rows: number }>; - onScroll: IEvent<number>; - scroll(eraseAttr: IAttributeData, isWrapped?: boolean): void; - scrollToBottom(): void; - scrollToTop(): void; - scrollToLine(line: number): void; - scrollLines(disp: number, suppressScrollEvent?: boolean, source?: ScrollSource): void; - scrollPages(pageCount: number): void; - resize(cols: number, rows: number): void; - reset(): void; -} - -export const ICoreMouseService = createDecorator<ICoreMouseService>('CoreMouseService'); -export interface ICoreMouseService { - activeProtocol: string; - activeEncoding: string; - areMouseEventsActive: boolean; - addProtocol(name: string, protocol: ICoreMouseProtocol): void; - addEncoding(name: string, encoding: CoreMouseEncoding): void; - reset(): void; - - /** - * Triggers a mouse event to be sent. - * - * Returns true if the event passed all protocol restrictions and a report - * was sent, otherwise false. The return value may be used to decide whether - * the default event action in the bowser component should be omitted. - * - * Note: The method will change values of the given event object - * to fullfill protocol and encoding restrictions. - */ - triggerMouseEvent(event: ICoreMouseEvent): boolean; - - /** - * Event to announce changes in mouse tracking. - */ - onProtocolChange: IEvent<CoreMouseEventType>; - - /** - * Human readable version of mouse events. - */ - explainEvents(events: CoreMouseEventType): { [event: string]: boolean }; -} - -export const ICoreService = createDecorator<ICoreService>('CoreService'); -export interface ICoreService { - serviceBrand: undefined; - - /** - * Initially the cursor will not be visible until the first time the terminal - * is focused. - */ - isCursorInitialized: boolean; - isCursorHidden: boolean; - - readonly modes: IModes; - readonly decPrivateModes: IDecPrivateModes; - - readonly onData: IEvent<string>; - readonly onUserInput: IEvent<void>; - readonly onBinary: IEvent<string>; - - reset(): void; - - /** - * Triggers the onData event in the public API. - * @param data The data that is being emitted. - * @param wasFromUser Whether the data originated from the user (as opposed to - * resulting from parsing incoming data). When true this will also: - * - Scroll to the bottom of the buffer.s - * - Fire the `onUserInput` event (so selection can be cleared). - */ - triggerDataEvent(data: string, wasUserInput?: boolean): void; - - /** - * Triggers the onBinary event in the public API. - * @param data The data that is being emitted. - */ - triggerBinaryEvent(data: string): void; -} - -export const ICharsetService = createDecorator<ICharsetService>('CharsetService'); -export interface ICharsetService { - serviceBrand: undefined; - - charset: ICharset | undefined; - readonly glevel: number; - - reset(): void; - - /** - * Set the G level of the terminal. - * @param g - */ - setgLevel(g: number): void; - - /** - * Set the charset for the given G level of the terminal. - * @param g - * @param charset - */ - setgCharset(g: number, charset: ICharset | undefined): void; -} - -export const IDirtyRowService = createDecorator<IDirtyRowService>('DirtyRowService'); -export interface IDirtyRowService { - serviceBrand: undefined; - - readonly start: number; - readonly end: number; - - clearRange(): void; - markDirty(y: number): void; - markRangeDirty(y1: number, y2: number): void; - markAllDirty(): void; -} - -export interface IServiceIdentifier<T> { - (...args: any[]): void; - type: T; -} - -export interface IBrandedService { - serviceBrand: undefined; -} - -type GetLeadingNonServiceArgs<Args> = - Args extends [...IBrandedService[]] ? [] - : Args extends [infer A1, ...IBrandedService[]] ? [A1] - : Args extends [infer A1, infer A2, ...IBrandedService[]] ? [A1, A2] - : Args extends [infer A1, infer A2, infer A3, ...IBrandedService[]] ? [A1, A2, A3] - : Args extends [infer A1, infer A2, infer A3, infer A4, ...IBrandedService[]] ? [A1, A2, A3, A4] - : Args extends [infer A1, infer A2, infer A3, infer A4, infer A5, ...IBrandedService[]] ? [A1, A2, A3, A4, A5] - : Args extends [infer A1, infer A2, infer A3, infer A4, infer A5, infer A6, ...IBrandedService[]] ? [A1, A2, A3, A4, A5, A6] - : Args extends [infer A1, infer A2, infer A3, infer A4, infer A5, infer A6, infer A7, ...IBrandedService[]] ? [A1, A2, A3, A4, A5, A6, A7] - : Args extends [infer A1, infer A2, infer A3, infer A4, infer A5, infer A6, infer A7, infer A8, ...IBrandedService[]] ? [A1, A2, A3, A4, A5, A6, A7, A8] - : never; - -export const IInstantiationService = createDecorator<IInstantiationService>('InstantiationService'); -export interface IInstantiationService { - serviceBrand: undefined; - - setService<T>(id: IServiceIdentifier<T>, instance: T): void; - getService<T>(id: IServiceIdentifier<T>): T | undefined; - createInstance<Ctor extends new (...args: any[]) => any, R extends InstanceType<Ctor>>(t: Ctor, ...args: GetLeadingNonServiceArgs<ConstructorParameters<Ctor>>): R; -} - -export enum LogLevelEnum { - DEBUG = 0, - INFO = 1, - WARN = 2, - ERROR = 3, - OFF = 4 -} - -export const ILogService = createDecorator<ILogService>('LogService'); -export interface ILogService { - serviceBrand: undefined; - - logLevel: LogLevelEnum; - - debug(message: any, ...optionalParams: any[]): void; - info(message: any, ...optionalParams: any[]): void; - warn(message: any, ...optionalParams: any[]): void; - error(message: any, ...optionalParams: any[]): void; -} - -export const IOptionsService = createDecorator<IOptionsService>('OptionsService'); -export interface IOptionsService { - serviceBrand: undefined; - - /** - * Read only access to the raw options object, this is an internal-only fast path for accessing - * single options without any validation as we trust TypeScript to enforce correct usage - * internally. - */ - readonly rawOptions: Readonly<ITerminalOptions>; - readonly options: ITerminalOptions; - - readonly onOptionChange: IEvent<string>; - - setOption<T>(key: string, value: T): void; - getOption<T>(key: string): T | undefined; -} - -export type FontWeight = 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' | number; -export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'off'; - -export type RendererType = 'dom' | 'canvas'; - -export interface ITerminalOptions { - allowProposedApi: boolean; - allowTransparency: boolean; - altClickMovesCursor: boolean; - bellSound: string; - bellStyle: 'none' | 'sound' /* | 'visual' | 'both' */; - cols: number; - convertEol: boolean; - cursorBlink: boolean; - cursorStyle: 'block' | 'underline' | 'bar'; - cursorWidth: number; - customGlyphs: boolean; - disableStdin: boolean; - drawBoldTextInBrightColors: boolean; - fastScrollModifier: 'alt' | 'ctrl' | 'shift' | undefined; - fastScrollSensitivity: number; - fontSize: number; - fontFamily: string; - fontWeight: FontWeight; - fontWeightBold: FontWeight; - letterSpacing: number; - lineHeight: number; - linkTooltipHoverDuration: number; - logLevel: LogLevel; - macOptionIsMeta: boolean; - macOptionClickForcesSelection: boolean; - minimumContrastRatio: number; - rendererType: RendererType; - rightClickSelectsWord: boolean; - rows: number; - screenReaderMode: boolean; - scrollback: number; - scrollSensitivity: number; - tabStopWidth: number; - theme: ITheme; - windowsMode: boolean; - windowOptions: IWindowOptions; - wordSeparator: string; - - [key: string]: any; - cancelEvents: boolean; - termName: string; -} - -export interface ITheme { - foreground?: string; - background?: string; - cursor?: string; - cursorAccent?: string; - selection?: string; - black?: string; - red?: string; - green?: string; - yellow?: string; - blue?: string; - magenta?: string; - cyan?: string; - white?: string; - brightBlack?: string; - brightRed?: string; - brightGreen?: string; - brightYellow?: string; - brightBlue?: string; - brightMagenta?: string; - brightCyan?: string; - brightWhite?: string; -} - -export const IUnicodeService = createDecorator<IUnicodeService>('UnicodeService'); -export interface IUnicodeService { - serviceBrand: undefined; - /** Register an Unicode version provider. */ - register(provider: IUnicodeVersionProvider): void; - /** Registered Unicode versions. */ - readonly versions: string[]; - /** Currently active version. */ - activeVersion: string; - /** Event triggered, when activate version changed. */ - readonly onChange: IEvent<string>; - - /** - * Unicode version dependent - */ - wcwidth(codepoint: number): number; - getStringCellWidth(s: string): number; -} - -export interface IUnicodeVersionProvider { - readonly version: string; - wcwidth(ucs: number): 0 | 1 | 2; -} diff --git a/node_modules/xterm/src/common/services/UnicodeService.ts b/node_modules/xterm/src/common/services/UnicodeService.ts deleted file mode 100644 index e96b757..0000000 --- a/node_modules/xterm/src/common/services/UnicodeService.ts +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ -import { IUnicodeService, IUnicodeVersionProvider } from 'common/services/Services'; -import { EventEmitter, IEvent } from 'common/EventEmitter'; -import { UnicodeV6 } from 'common/input/UnicodeV6'; - - -export class UnicodeService implements IUnicodeService { - public serviceBrand: any; - - private _providers: {[key: string]: IUnicodeVersionProvider} = Object.create(null); - private _active: string = ''; - private _activeProvider: IUnicodeVersionProvider; - private _onChange = new EventEmitter<string>(); - public get onChange(): IEvent<string> { return this._onChange.event; } - - constructor() { - const defaultProvider = new UnicodeV6(); - this.register(defaultProvider); - this._active = defaultProvider.version; - this._activeProvider = defaultProvider; - } - - public get versions(): string[] { - return Object.keys(this._providers); - } - - public get activeVersion(): string { - return this._active; - } - - public set activeVersion(version: string) { - if (!this._providers[version]) { - throw new Error(`unknown Unicode version "${version}"`); - } - this._active = version; - this._activeProvider = this._providers[version]; - this._onChange.fire(version); - } - - public register(provider: IUnicodeVersionProvider): void { - this._providers[provider.version] = provider; - } - - /** - * Unicode version dependent interface. - */ - public wcwidth(num: number): number { - return this._activeProvider.wcwidth(num); - } - - public getStringCellWidth(s: string): number { - let result = 0; - const length = s.length; - for (let i = 0; i < length; ++i) { - let code = s.charCodeAt(i); - // surrogate pair first - if (0xD800 <= code && code <= 0xDBFF) { - if (++i >= length) { - // this should not happen with strings retrieved from - // Buffer.translateToString as it converts from UTF-32 - // and therefore always should contain the second part - // for any other string we still have to handle it somehow: - // simply treat the lonely surrogate first as a single char (UCS-2 behavior) - return result + this.wcwidth(code); - } - const second = s.charCodeAt(i); - // convert surrogate pair to high codepoint only for valid second part (UTF-16) - // otherwise treat them independently (UCS-2 behavior) - if (0xDC00 <= second && second <= 0xDFFF) { - code = (code - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; - } else { - result += this.wcwidth(second); - } - } - result += this.wcwidth(code); - } - return result; - } -} diff --git a/node_modules/xterm/src/headless/Terminal.ts b/node_modules/xterm/src/headless/Terminal.ts deleted file mode 100644 index 7f138ce..0000000 --- a/node_modules/xterm/src/headless/Terminal.ts +++ /dev/null @@ -1,170 +0,0 @@ -/** - * Copyright (c) 2014 The xterm.js authors. All rights reserved. - * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License) - * @license MIT - * - * Originally forked from (with the author's permission): - * Fabrice Bellard's javascript vt100 for jslinux: - * http://bellard.org/jslinux/ - * Copyright (c) 2011 Fabrice Bellard - * The original design remains. The terminal itself - * has been extended to include xterm CSI codes, among - * other features. - * - * Terminal Emulation References: - * http://vt100.net/ - * http://invisible-island.net/xterm/ctlseqs/ctlseqs.txt - * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html - * http://invisible-island.net/vttest/ - * http://www.inwap.com/pdp10/ansicode.txt - * http://linux.die.net/man/4/console_codes - * http://linux.die.net/man/7/urxvt - */ - -import { DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; -import { IBuffer } from 'common/buffer/Types'; -import { CoreTerminal } from 'common/CoreTerminal'; -import { EventEmitter, forwardEvent, IEvent } from 'common/EventEmitter'; -import { ITerminalOptions as IInitializedTerminalOptions } from 'common/services/Services'; -import { IMarker, ITerminalOptions, ScrollSource } from 'common/Types'; - -export class Terminal extends CoreTerminal { - // TODO: We should remove options once components adopt optionsService - public get options(): IInitializedTerminalOptions { return this.optionsService.options; } - - private _onBell = new EventEmitter<void>(); - public get onBell(): IEvent<void> { return this._onBell.event; } - private _onCursorMove = new EventEmitter<void>(); - public get onCursorMove(): IEvent<void> { return this._onCursorMove.event; } - private _onTitleChange = new EventEmitter<string>(); - public get onTitleChange(): IEvent<string> { return this._onTitleChange.event; } - - private _onA11yCharEmitter = new EventEmitter<string>(); - public get onA11yChar(): IEvent<string> { return this._onA11yCharEmitter.event; } - private _onA11yTabEmitter = new EventEmitter<number>(); - public get onA11yTab(): IEvent<number> { return this._onA11yTabEmitter.event; } - - /** - * Creates a new `Terminal` object. - * - * @param options An object containing a set of options, the available options are: - * - `cursorBlink` (boolean): Whether the terminal cursor blinks - * - `cols` (number): The number of columns of the terminal (horizontal size) - * - `rows` (number): The number of rows of the terminal (vertical size) - * - * @public - * @class Xterm Xterm - * @alias module:xterm/src/xterm - */ - constructor( - options: ITerminalOptions = {} - ) { - super(options); - - this._setup(); - - // Setup InputHandler listeners - this.register(this._inputHandler.onRequestBell(() => this.bell())); - this.register(this._inputHandler.onRequestReset(() => this.reset())); - this.register(forwardEvent(this._inputHandler.onCursorMove, this._onCursorMove)); - this.register(forwardEvent(this._inputHandler.onTitleChange, this._onTitleChange)); - this.register(forwardEvent(this._inputHandler.onA11yChar, this._onA11yCharEmitter)); - this.register(forwardEvent(this._inputHandler.onA11yTab, this._onA11yTabEmitter)); - } - - public dispose(): void { - if (this._isDisposed) { - return; - } - super.dispose(); - this.write = () => { }; - } - - /** - * Convenience property to active buffer. - */ - public get buffer(): IBuffer { - return this.buffers.active; - } - - protected _updateOptions(key: string): void { - super._updateOptions(key); - - // TODO: These listeners should be owned by individual components - switch (key) { - case 'tabStopWidth': this.buffers.setupTabStops(); break; - } - } - - // TODO: Support paste here? - - public get markers(): IMarker[] { - return this.buffer.markers; - } - - public addMarker(cursorYOffset: number): IMarker | undefined { - // Disallow markers on the alt buffer - if (this.buffer !== this.buffers.normal) { - return; - } - - return this.buffer.addMarker(this.buffer.ybase + this.buffer.y + cursorYOffset); - } - - public bell(): void { - this._onBell.fire(); - } - - /** - * Resizes the terminal. - * - * @param x The number of columns to resize to. - * @param y The number of rows to resize to. - */ - public resize(x: number, y: number): void { - if (x === this.cols && y === this.rows) { - return; - } - - super.resize(x, y); - } - - /** - * Clear the entire buffer, making the prompt line the new first line. - */ - public clear(): void { - if (this.buffer.ybase === 0 && this.buffer.y === 0) { - // Don't clear if it's already clear - return; - } - this.buffer.lines.set(0, this.buffer.lines.get(this.buffer.ybase + this.buffer.y)!); - this.buffer.lines.length = 1; - this.buffer.ydisp = 0; - this.buffer.ybase = 0; - this.buffer.y = 0; - for (let i = 1; i < this.rows; i++) { - this.buffer.lines.push(this.buffer.getBlankLine(DEFAULT_ATTR_DATA)); - } - this._onScroll.fire({ position: this.buffer.ydisp, source: ScrollSource.TERMINAL }); - } - - /** - * Reset terminal. - * Note: Calling this directly from JS is synchronous but does not clear - * input buffers and does not reset the parser, thus the terminal will - * continue to apply pending input data. - * If you need in band reset (synchronous with input data) consider - * using DECSTR (soft reset, CSI ! p) or RIS instead (hard reset, ESC c). - */ - public reset(): void { - /** - * Since _setup handles a full terminal creation, we have to carry forward - * a few things that should not reset. - */ - this.options.rows = this.rows; - this.options.cols = this.cols; - - this._setup(); - super.reset(); - } -} diff --git a/node_modules/xterm/src/headless/Types.d.ts b/node_modules/xterm/src/headless/Types.d.ts deleted file mode 100644 index 868e5c1..0000000 --- a/node_modules/xterm/src/headless/Types.d.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { IBuffer, IBufferSet } from 'common/buffer/Types'; -import { IEvent } from 'common/EventEmitter'; -import { IFunctionIdentifier, IParams } from 'common/parser/Types'; -import { ICoreTerminal, IDisposable, IMarker, ITerminalOptions } from 'common/Types'; - -export interface ITerminal extends ICoreTerminal { - rows: number; - cols: number; - buffer: IBuffer; - buffers: IBufferSet; - markers: IMarker[]; - // TODO: We should remove options once components adopt optionsService - options: ITerminalOptions; - - onCursorMove: IEvent<void>; - onData: IEvent<string>; - onBinary: IEvent<string>; - onLineFeed: IEvent<void>; - onResize: IEvent<{ cols: number, rows: number }>; - onTitleChange: IEvent<string>; - resize(columns: number, rows: number): void; - addCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean): IDisposable; - addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean): IDisposable; - addEscHandler(id: IFunctionIdentifier, callback: () => boolean): IDisposable; - addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable; - addMarker(cursorYOffset: number): IMarker | undefined; - dispose(): void; - clear(): void; - write(data: string | Uint8Array, callback?: () => void): void; - reset(): void; -} diff --git a/node_modules/xterm/src/headless/public/Terminal.ts b/node_modules/xterm/src/headless/public/Terminal.ts deleted file mode 100644 index 5a35fae..0000000 --- a/node_modules/xterm/src/headless/public/Terminal.ts +++ /dev/null @@ -1,216 +0,0 @@ -/** - * Copyright (c) 2018 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IEvent } from 'common/EventEmitter'; -import { BufferNamespaceApi } from 'common/public/BufferNamespaceApi'; -import { ParserApi } from 'common/public/ParserApi'; -import { UnicodeApi } from 'common/public/UnicodeApi'; -import { IBufferNamespace as IBufferNamespaceApi, IMarker, IModes, IParser, ITerminalAddon, IUnicodeHandling, Terminal as ITerminalApi } from 'xterm-headless'; -import { Terminal as TerminalCore } from 'headless/Terminal'; -import { AddonManager } from 'common/public/AddonManager'; -import { ITerminalOptions } from 'common/Types'; - -/** - * The set of options that only have an effect when set in the Terminal constructor. - */ -const CONSTRUCTOR_ONLY_OPTIONS = ['cols', 'rows']; - -export class Terminal implements ITerminalApi { - private _core: TerminalCore; - private _addonManager: AddonManager; - private _parser: IParser | undefined; - private _buffer: BufferNamespaceApi | undefined; - private _publicOptions: ITerminalOptions; - - constructor(options?: ITerminalOptions) { - this._core = new TerminalCore(options); - this._addonManager = new AddonManager(); - - this._publicOptions = { ... this._core.options }; - const getter = (propName: string): any => { - return this._core.options[propName]; - }; - const setter = (propName: string, value: any): void => { - this._checkReadonlyOptions(propName); - this._core.options[propName] = value; - }; - - for (const propName in this._core.options) { - Object.defineProperty(this._publicOptions, propName, { - get: () => { - return this._core.options[propName]; - }, - set: (value: any) => { - this._checkReadonlyOptions(propName); - this._core.options[propName] = value; - } - }); - const desc = { - get: getter.bind(this, propName), - set: setter.bind(this, propName) - }; - Object.defineProperty(this._publicOptions, propName, desc); - } - } - - private _checkReadonlyOptions(propName: string): void { - // Throw an error if any constructor only option is modified - // from terminal.options - // Modifications from anywhere else are allowed - if (CONSTRUCTOR_ONLY_OPTIONS.includes(propName)) { - throw new Error(`Option "${propName}" can only be set in the constructor`); - } - } - - private _checkProposedApi(): void { - if (!this._core.optionsService.options.allowProposedApi) { - throw new Error('You must set the allowProposedApi option to true to use proposed API'); - } - } - - public get onBell(): IEvent<void> { return this._core.onBell; } - public get onBinary(): IEvent<string> { return this._core.onBinary; } - public get onCursorMove(): IEvent<void> { return this._core.onCursorMove; } - public get onData(): IEvent<string> { return this._core.onData; } - public get onLineFeed(): IEvent<void> { return this._core.onLineFeed; } - public get onResize(): IEvent<{ cols: number, rows: number }> { return this._core.onResize; } - public get onScroll(): IEvent<number> { return this._core.onScroll; } - public get onTitleChange(): IEvent<string> { return this._core.onTitleChange; } - - public get parser(): IParser { - this._checkProposedApi(); - if (!this._parser) { - this._parser = new ParserApi(this._core); - } - return this._parser; - } - public get unicode(): IUnicodeHandling { - this._checkProposedApi(); - return new UnicodeApi(this._core); - } - public get rows(): number { return this._core.rows; } - public get cols(): number { return this._core.cols; } - public get buffer(): IBufferNamespaceApi { - this._checkProposedApi(); - if (!this._buffer) { - this._buffer = new BufferNamespaceApi(this._core); - } - return this._buffer; - } - public get markers(): ReadonlyArray<IMarker> { - this._checkProposedApi(); - return this._core.markers; - } - public get modes(): IModes { - const m = this._core.coreService.decPrivateModes; - let mouseTrackingMode: 'none' | 'x10' | 'vt200' | 'drag' | 'any' = 'none'; - switch (this._core.coreMouseService.activeProtocol) { - case 'X10': mouseTrackingMode = 'x10'; break; - case 'VT200': mouseTrackingMode = 'vt200'; break; - case 'DRAG': mouseTrackingMode = 'drag'; break; - case 'ANY': mouseTrackingMode = 'any'; break; - } - return { - applicationCursorKeysMode: m.applicationCursorKeys, - applicationKeypadMode: m.applicationKeypad, - bracketedPasteMode: m.bracketedPasteMode, - insertMode: this._core.coreService.modes.insertMode, - mouseTrackingMode: mouseTrackingMode, - originMode: m.origin, - reverseWraparoundMode: m.reverseWraparound, - sendFocusMode: m.sendFocus, - wraparoundMode: m.wraparound - }; - } - public get options(): ITerminalOptions { - return this._publicOptions; - } - public set options(options: ITerminalOptions) { - for (const propName in options) { - this._publicOptions[propName] = options[propName]; - } - } - public resize(columns: number, rows: number): void { - this._verifyIntegers(columns, rows); - this._core.resize(columns, rows); - } - public registerMarker(cursorYOffset: number = 0): IMarker | undefined { - this._checkProposedApi(); - this._verifyIntegers(cursorYOffset); - return this._core.addMarker(cursorYOffset); - } - public addMarker(cursorYOffset: number): IMarker | undefined { - return this.registerMarker(cursorYOffset); - } - public dispose(): void { - this._addonManager.dispose(); - this._core.dispose(); - } - public scrollLines(amount: number): void { - this._verifyIntegers(amount); - this._core.scrollLines(amount); - } - public scrollPages(pageCount: number): void { - this._verifyIntegers(pageCount); - this._core.scrollPages(pageCount); - } - public scrollToTop(): void { - this._core.scrollToTop(); - } - public scrollToBottom(): void { - this._core.scrollToBottom(); - } - public scrollToLine(line: number): void { - this._verifyIntegers(line); - this._core.scrollToLine(line); - } - public clear(): void { - this._core.clear(); - } - public write(data: string | Uint8Array, callback?: () => void): void { - this._core.write(data, callback); - } - public writeUtf8(data: Uint8Array, callback?: () => void): void { - this._core.write(data, callback); - } - public writeln(data: string | Uint8Array, callback?: () => void): void { - this._core.write(data); - this._core.write('\r\n', callback); - } - public getOption(key: 'bellSound' | 'bellStyle' | 'cursorStyle' | 'fontFamily' | 'logLevel' | 'rendererType' | 'termName' | 'wordSeparator'): string; - public getOption(key: 'allowTransparency' | 'altClickMovesCursor' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'disableStdin' | 'macOptionIsMeta' | 'rightClickSelectsWord' | 'popOnBell' | 'visualBell'): boolean; - public getOption(key: 'cols' | 'fontSize' | 'letterSpacing' | 'lineHeight' | 'rows' | 'tabStopWidth' | 'scrollback'): number; - public getOption(key: string): any; - public getOption(key: any): any { - return this._core.optionsService.getOption(key); - } - public setOption(key: 'bellSound' | 'fontFamily' | 'termName' | 'wordSeparator', value: string): void; - public setOption(key: 'fontWeight' | 'fontWeightBold', value: 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' | number): void; - public setOption(key: 'logLevel', value: 'debug' | 'info' | 'warn' | 'error' | 'off'): void; - public setOption(key: 'bellStyle', value: 'none' | 'visual' | 'sound' | 'both'): void; - public setOption(key: 'cursorStyle', value: 'block' | 'underline' | 'bar'): void; - public setOption(key: 'allowTransparency' | 'altClickMovesCursor' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'disableStdin' | 'macOptionIsMeta' | 'rightClickSelectsWord' | 'popOnBell' | 'visualBell', value: boolean): void; - public setOption(key: 'fontSize' | 'letterSpacing' | 'lineHeight' | 'tabStopWidth' | 'scrollback', value: number): void; - public setOption(key: 'cols' | 'rows', value: number): void; - public setOption(key: string, value: any): void; - public setOption(key: any, value: any): void { - this._core.optionsService.setOption(key, value); - } - public reset(): void { - this._core.reset(); - } - public loadAddon(addon: ITerminalAddon): void { - // TODO: This could cause issues if the addon calls renderer apis - return this._addonManager.loadAddon(this as any, addon); - } - - private _verifyIntegers(...values: number[]): void { - for (const value of values) { - if (value === Infinity || isNaN(value) || value % 1 !== 0) { - throw new Error('This API only accepts integers'); - } - } - } -} |