aboutsummaryrefslogtreecommitdiffstats
path: root/node_modules/xterm/src/browser
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/xterm/src/browser')
-rw-r--r--node_modules/xterm/src/browser/AccessibilityManager.ts301
-rw-r--r--node_modules/xterm/src/browser/Clipboard.ts99
-rw-r--r--node_modules/xterm/src/browser/Color.ts236
-rw-r--r--node_modules/xterm/src/browser/ColorContrastCache.ts38
-rw-r--r--node_modules/xterm/src/browser/ColorManager.ts258
-rw-r--r--node_modules/xterm/src/browser/Dom.ts10
-rw-r--r--node_modules/xterm/src/browser/Lifecycle.ts30
-rw-r--r--node_modules/xterm/src/browser/Linkifier.ts356
-rw-r--r--node_modules/xterm/src/browser/Linkifier2.ts392
-rw-r--r--node_modules/xterm/src/browser/LocalizableStrings.ts10
-rw-r--r--node_modules/xterm/src/browser/MouseZoneManager.ts236
-rw-r--r--node_modules/xterm/src/browser/RenderDebouncer.ts63
-rw-r--r--node_modules/xterm/src/browser/ScreenDprMonitor.ts69
-rw-r--r--node_modules/xterm/src/browser/Terminal.ts1408
-rw-r--r--node_modules/xterm/src/browser/TimeBasedDebouncer.ts86
-rw-r--r--node_modules/xterm/src/browser/Types.d.ts316
-rw-r--r--node_modules/xterm/src/browser/Viewport.ts294
-rw-r--r--node_modules/xterm/src/browser/input/CompositionHelper.ts237
-rw-r--r--node_modules/xterm/src/browser/input/Mouse.ts58
-rw-r--r--node_modules/xterm/src/browser/input/MoveToCell.ts249
-rw-r--r--node_modules/xterm/src/browser/public/Terminal.ts297
-rw-r--r--node_modules/xterm/src/browser/renderer/BaseRenderLayer.ts513
-rw-r--r--node_modules/xterm/src/browser/renderer/CursorRenderLayer.ts377
-rw-r--r--node_modules/xterm/src/browser/renderer/CustomGlyphs.ts563
-rw-r--r--node_modules/xterm/src/browser/renderer/GridCache.ts33
-rw-r--r--node_modules/xterm/src/browser/renderer/LinkRenderLayer.ts83
-rw-r--r--node_modules/xterm/src/browser/renderer/Renderer.ts216
-rw-r--r--node_modules/xterm/src/browser/renderer/RendererUtils.ts11
-rw-r--r--node_modules/xterm/src/browser/renderer/SelectionRenderLayer.ts128
-rw-r--r--node_modules/xterm/src/browser/renderer/TextRenderLayer.ts330
-rw-r--r--node_modules/xterm/src/browser/renderer/Types.d.ts109
-rw-r--r--node_modules/xterm/src/browser/renderer/atlas/BaseCharAtlas.ts58
-rw-r--r--node_modules/xterm/src/browser/renderer/atlas/CharAtlasCache.ts95
-rw-r--r--node_modules/xterm/src/browser/renderer/atlas/CharAtlasUtils.ts54
-rw-r--r--node_modules/xterm/src/browser/renderer/atlas/Constants.ts15
-rw-r--r--node_modules/xterm/src/browser/renderer/atlas/DynamicCharAtlas.ts404
-rw-r--r--node_modules/xterm/src/browser/renderer/atlas/LRUMap.ts136
-rw-r--r--node_modules/xterm/src/browser/renderer/atlas/Types.d.ts29
-rw-r--r--node_modules/xterm/src/browser/renderer/dom/DomRenderer.ts400
-rw-r--r--node_modules/xterm/src/browser/renderer/dom/DomRendererRowFactory.ts259
-rw-r--r--node_modules/xterm/src/browser/selection/SelectionModel.ts139
-rw-r--r--node_modules/xterm/src/browser/selection/Types.d.ts15
-rw-r--r--node_modules/xterm/src/browser/services/CharSizeService.ts87
-rw-r--r--node_modules/xterm/src/browser/services/CharacterJoinerService.ts339
-rw-r--r--node_modules/xterm/src/browser/services/CoreBrowserService.ts20
-rw-r--r--node_modules/xterm/src/browser/services/MouseService.ts35
-rw-r--r--node_modules/xterm/src/browser/services/RenderService.ts223
-rw-r--r--node_modules/xterm/src/browser/services/SelectionService.ts1009
-rw-r--r--node_modules/xterm/src/browser/services/Services.ts125
-rw-r--r--node_modules/xterm/src/browser/services/SoundService.ts63
50 files changed, 0 insertions, 10911 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];
- }
-}