@xterm/xterm 5.4.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +235 -0
- package/css/xterm.css +209 -0
- package/lib/xterm.js +2 -0
- package/lib/xterm.js.map +1 -0
- package/package.json +101 -0
- package/src/browser/AccessibilityManager.ts +278 -0
- package/src/browser/Clipboard.ts +93 -0
- package/src/browser/ColorContrastCache.ts +34 -0
- package/src/browser/Lifecycle.ts +33 -0
- package/src/browser/Linkifier2.ts +416 -0
- package/src/browser/LocalizableStrings.ts +12 -0
- package/src/browser/OscLinkProvider.ts +128 -0
- package/src/browser/RenderDebouncer.ts +83 -0
- package/src/browser/Terminal.ts +1317 -0
- package/src/browser/TimeBasedDebouncer.ts +86 -0
- package/src/browser/Types.d.ts +181 -0
- package/src/browser/Viewport.ts +401 -0
- package/src/browser/decorations/BufferDecorationRenderer.ts +134 -0
- package/src/browser/decorations/ColorZoneStore.ts +117 -0
- package/src/browser/decorations/OverviewRulerRenderer.ts +218 -0
- package/src/browser/input/CompositionHelper.ts +246 -0
- package/src/browser/input/Mouse.ts +54 -0
- package/src/browser/input/MoveToCell.ts +249 -0
- package/src/browser/public/Terminal.ts +260 -0
- package/src/browser/renderer/dom/DomRenderer.ts +509 -0
- package/src/browser/renderer/dom/DomRendererRowFactory.ts +526 -0
- package/src/browser/renderer/dom/WidthCache.ts +160 -0
- package/src/browser/renderer/shared/CellColorResolver.ts +137 -0
- package/src/browser/renderer/shared/CharAtlasCache.ts +96 -0
- package/src/browser/renderer/shared/CharAtlasUtils.ts +75 -0
- package/src/browser/renderer/shared/Constants.ts +14 -0
- package/src/browser/renderer/shared/CursorBlinkStateManager.ts +146 -0
- package/src/browser/renderer/shared/CustomGlyphs.ts +687 -0
- package/src/browser/renderer/shared/DevicePixelObserver.ts +41 -0
- package/src/browser/renderer/shared/README.md +1 -0
- package/src/browser/renderer/shared/RendererUtils.ts +58 -0
- package/src/browser/renderer/shared/SelectionRenderModel.ts +91 -0
- package/src/browser/renderer/shared/TextureAtlas.ts +1082 -0
- package/src/browser/renderer/shared/Types.d.ts +173 -0
- package/src/browser/selection/SelectionModel.ts +144 -0
- package/src/browser/selection/Types.d.ts +15 -0
- package/src/browser/services/CharSizeService.ts +102 -0
- package/src/browser/services/CharacterJoinerService.ts +339 -0
- package/src/browser/services/CoreBrowserService.ts +137 -0
- package/src/browser/services/MouseService.ts +46 -0
- package/src/browser/services/RenderService.ts +279 -0
- package/src/browser/services/SelectionService.ts +1031 -0
- package/src/browser/services/Services.ts +147 -0
- package/src/browser/services/ThemeService.ts +237 -0
- package/src/common/CircularList.ts +241 -0
- package/src/common/Clone.ts +23 -0
- package/src/common/Color.ts +357 -0
- package/src/common/CoreTerminal.ts +284 -0
- package/src/common/EventEmitter.ts +78 -0
- package/src/common/InputHandler.ts +3461 -0
- package/src/common/Lifecycle.ts +108 -0
- package/src/common/MultiKeyMap.ts +42 -0
- package/src/common/Platform.ts +44 -0
- package/src/common/SortedList.ts +118 -0
- package/src/common/TaskQueue.ts +166 -0
- package/src/common/TypedArrayUtils.ts +17 -0
- package/src/common/Types.d.ts +553 -0
- package/src/common/WindowsMode.ts +27 -0
- package/src/common/buffer/AttributeData.ts +196 -0
- package/src/common/buffer/Buffer.ts +654 -0
- package/src/common/buffer/BufferLine.ts +524 -0
- package/src/common/buffer/BufferRange.ts +13 -0
- package/src/common/buffer/BufferReflow.ts +223 -0
- package/src/common/buffer/BufferSet.ts +134 -0
- package/src/common/buffer/CellData.ts +94 -0
- package/src/common/buffer/Constants.ts +149 -0
- package/src/common/buffer/Marker.ts +43 -0
- package/src/common/buffer/Types.d.ts +52 -0
- package/src/common/data/Charsets.ts +256 -0
- package/src/common/data/EscapeSequences.ts +153 -0
- package/src/common/input/Keyboard.ts +398 -0
- package/src/common/input/TextDecoder.ts +346 -0
- package/src/common/input/UnicodeV6.ts +145 -0
- package/src/common/input/WriteBuffer.ts +246 -0
- package/src/common/input/XParseColor.ts +80 -0
- package/src/common/parser/Constants.ts +58 -0
- package/src/common/parser/DcsParser.ts +192 -0
- package/src/common/parser/EscapeSequenceParser.ts +792 -0
- package/src/common/parser/OscParser.ts +238 -0
- package/src/common/parser/Params.ts +229 -0
- package/src/common/parser/Types.d.ts +275 -0
- package/src/common/public/AddonManager.ts +53 -0
- package/src/common/public/BufferApiView.ts +35 -0
- package/src/common/public/BufferLineApiView.ts +29 -0
- package/src/common/public/BufferNamespaceApi.ts +36 -0
- package/src/common/public/ParserApi.ts +37 -0
- package/src/common/public/UnicodeApi.ts +27 -0
- package/src/common/services/BufferService.ts +151 -0
- package/src/common/services/CharsetService.ts +34 -0
- package/src/common/services/CoreMouseService.ts +318 -0
- package/src/common/services/CoreService.ts +87 -0
- package/src/common/services/DecorationService.ts +140 -0
- package/src/common/services/InstantiationService.ts +85 -0
- package/src/common/services/LogService.ts +124 -0
- package/src/common/services/OptionsService.ts +202 -0
- package/src/common/services/OscLinkService.ts +115 -0
- package/src/common/services/ServiceRegistry.ts +49 -0
- package/src/common/services/Services.ts +373 -0
- package/src/common/services/UnicodeService.ts +111 -0
- package/src/headless/Terminal.ts +136 -0
- package/src/headless/public/Terminal.ts +195 -0
- package/typings/xterm.d.ts +1857 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { IEvent } from 'common/EventEmitter';
|
|
7
|
+
import { IRenderDimensions, IRenderer } from 'browser/renderer/shared/Types';
|
|
8
|
+
import { IColorSet, ReadonlyColorSet } from 'browser/Types';
|
|
9
|
+
import { ISelectionRedrawRequestEvent as ISelectionRequestRedrawEvent, ISelectionRequestScrollLinesEvent } from 'browser/selection/Types';
|
|
10
|
+
import { createDecorator } from 'common/services/ServiceRegistry';
|
|
11
|
+
import { AllColorIndex, IDisposable } from 'common/Types';
|
|
12
|
+
|
|
13
|
+
export const ICharSizeService = createDecorator<ICharSizeService>('CharSizeService');
|
|
14
|
+
export interface ICharSizeService {
|
|
15
|
+
serviceBrand: undefined;
|
|
16
|
+
|
|
17
|
+
readonly width: number;
|
|
18
|
+
readonly height: number;
|
|
19
|
+
readonly hasValidSize: boolean;
|
|
20
|
+
|
|
21
|
+
readonly onCharSizeChange: IEvent<void>;
|
|
22
|
+
|
|
23
|
+
measure(): void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const ICoreBrowserService = createDecorator<ICoreBrowserService>('CoreBrowserService');
|
|
27
|
+
export interface ICoreBrowserService {
|
|
28
|
+
serviceBrand: undefined;
|
|
29
|
+
|
|
30
|
+
readonly isFocused: boolean;
|
|
31
|
+
|
|
32
|
+
readonly onDprChange: IEvent<number>;
|
|
33
|
+
readonly onWindowChange: IEvent<Window & typeof globalThis>;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Gets or sets the parent window that the terminal is rendered into. DOM and rendering APIs (e.g.
|
|
37
|
+
* requestAnimationFrame) should be invoked in the context of this window. This should be set when
|
|
38
|
+
* the window hosting the xterm.js instance changes.
|
|
39
|
+
*/
|
|
40
|
+
window: Window & typeof globalThis;
|
|
41
|
+
/**
|
|
42
|
+
* The document of the primary window to be used to create elements when working with multiple
|
|
43
|
+
* windows. This is defined by the documentOverride setting.
|
|
44
|
+
*/
|
|
45
|
+
readonly mainDocument: Document;
|
|
46
|
+
/**
|
|
47
|
+
* Helper for getting the devicePixelRatio of the parent window.
|
|
48
|
+
*/
|
|
49
|
+
readonly dpr: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const IMouseService = createDecorator<IMouseService>('MouseService');
|
|
53
|
+
export interface IMouseService {
|
|
54
|
+
serviceBrand: undefined;
|
|
55
|
+
|
|
56
|
+
getCoords(event: {clientX: number, clientY: number}, element: HTMLElement, colCount: number, rowCount: number, isSelection?: boolean): [number, number] | undefined;
|
|
57
|
+
getMouseReportCoords(event: MouseEvent, element: HTMLElement): { col: number, row: number, x: number, y: number } | undefined;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export const IRenderService = createDecorator<IRenderService>('RenderService');
|
|
61
|
+
export interface IRenderService extends IDisposable {
|
|
62
|
+
serviceBrand: undefined;
|
|
63
|
+
|
|
64
|
+
onDimensionsChange: IEvent<IRenderDimensions>;
|
|
65
|
+
/**
|
|
66
|
+
* Fires when buffer changes are rendered. This does not fire when only cursor
|
|
67
|
+
* or selections are rendered.
|
|
68
|
+
*/
|
|
69
|
+
onRenderedViewportChange: IEvent<{ start: number, end: number }>;
|
|
70
|
+
/**
|
|
71
|
+
* Fires on render
|
|
72
|
+
*/
|
|
73
|
+
onRender: IEvent<{ start: number, end: number }>;
|
|
74
|
+
onRefreshRequest: IEvent<{ start: number, end: number }>;
|
|
75
|
+
|
|
76
|
+
dimensions: IRenderDimensions;
|
|
77
|
+
|
|
78
|
+
addRefreshCallback(callback: FrameRequestCallback): number;
|
|
79
|
+
|
|
80
|
+
refreshRows(start: number, end: number): void;
|
|
81
|
+
clearTextureAtlas(): void;
|
|
82
|
+
resize(cols: number, rows: number): void;
|
|
83
|
+
hasRenderer(): boolean;
|
|
84
|
+
setRenderer(renderer: IRenderer): void;
|
|
85
|
+
handleDevicePixelRatioChange(): void;
|
|
86
|
+
handleResize(cols: number, rows: number): void;
|
|
87
|
+
handleCharSizeChanged(): void;
|
|
88
|
+
handleBlur(): void;
|
|
89
|
+
handleFocus(): void;
|
|
90
|
+
handleSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void;
|
|
91
|
+
handleCursorMove(): void;
|
|
92
|
+
clear(): void;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export const ISelectionService = createDecorator<ISelectionService>('SelectionService');
|
|
96
|
+
export interface ISelectionService {
|
|
97
|
+
serviceBrand: undefined;
|
|
98
|
+
|
|
99
|
+
readonly selectionText: string;
|
|
100
|
+
readonly hasSelection: boolean;
|
|
101
|
+
readonly selectionStart: [number, number] | undefined;
|
|
102
|
+
readonly selectionEnd: [number, number] | undefined;
|
|
103
|
+
|
|
104
|
+
readonly onLinuxMouseSelection: IEvent<string>;
|
|
105
|
+
readonly onRequestRedraw: IEvent<ISelectionRequestRedrawEvent>;
|
|
106
|
+
readonly onRequestScrollLines: IEvent<ISelectionRequestScrollLinesEvent>;
|
|
107
|
+
readonly onSelectionChange: IEvent<void>;
|
|
108
|
+
|
|
109
|
+
disable(): void;
|
|
110
|
+
enable(): void;
|
|
111
|
+
reset(): void;
|
|
112
|
+
setSelection(row: number, col: number, length: number): void;
|
|
113
|
+
selectAll(): void;
|
|
114
|
+
selectLines(start: number, end: number): void;
|
|
115
|
+
clearSelection(): void;
|
|
116
|
+
rightClickSelect(event: MouseEvent): void;
|
|
117
|
+
shouldColumnSelect(event: KeyboardEvent | MouseEvent): boolean;
|
|
118
|
+
shouldForceSelection(event: MouseEvent): boolean;
|
|
119
|
+
refresh(isLinuxMouseSelection?: boolean): void;
|
|
120
|
+
handleMouseDown(event: MouseEvent): void;
|
|
121
|
+
isCellInSelection(x: number, y: number): boolean;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export const ICharacterJoinerService = createDecorator<ICharacterJoinerService>('CharacterJoinerService');
|
|
125
|
+
export interface ICharacterJoinerService {
|
|
126
|
+
serviceBrand: undefined;
|
|
127
|
+
|
|
128
|
+
register(handler: (text: string) => [number, number][]): number;
|
|
129
|
+
deregister(joinerId: number): boolean;
|
|
130
|
+
getJoinedCharacters(row: number): [number, number][];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export const IThemeService = createDecorator<IThemeService>('ThemeService');
|
|
134
|
+
export interface IThemeService {
|
|
135
|
+
serviceBrand: undefined;
|
|
136
|
+
|
|
137
|
+
readonly colors: ReadonlyColorSet;
|
|
138
|
+
|
|
139
|
+
readonly onChangeColors: IEvent<ReadonlyColorSet>;
|
|
140
|
+
|
|
141
|
+
restoreColor(slot?: AllColorIndex): void;
|
|
142
|
+
/**
|
|
143
|
+
* Allows external modifying of colors in the theme, this is used instead of {@link colors} to
|
|
144
|
+
* prevent accidental writes.
|
|
145
|
+
*/
|
|
146
|
+
modifyColors(callback: (colors: IColorSet) => void): void;
|
|
147
|
+
}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2022 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ColorContrastCache } from 'browser/ColorContrastCache';
|
|
7
|
+
import { IThemeService } from 'browser/services/Services';
|
|
8
|
+
import { IColorContrastCache, IColorSet, ReadonlyColorSet } from 'browser/Types';
|
|
9
|
+
import { channels, color, css, NULL_COLOR } from 'common/Color';
|
|
10
|
+
import { EventEmitter } from 'common/EventEmitter';
|
|
11
|
+
import { Disposable } from 'common/Lifecycle';
|
|
12
|
+
import { IOptionsService, ITheme } from 'common/services/Services';
|
|
13
|
+
import { AllColorIndex, IColor, SpecialColorIndex } from 'common/Types';
|
|
14
|
+
|
|
15
|
+
interface IRestoreColorSet {
|
|
16
|
+
foreground: IColor;
|
|
17
|
+
background: IColor;
|
|
18
|
+
cursor: IColor;
|
|
19
|
+
ansi: IColor[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
const DEFAULT_FOREGROUND = css.toColor('#ffffff');
|
|
24
|
+
const DEFAULT_BACKGROUND = css.toColor('#000000');
|
|
25
|
+
const DEFAULT_CURSOR = css.toColor('#ffffff');
|
|
26
|
+
const DEFAULT_CURSOR_ACCENT = css.toColor('#000000');
|
|
27
|
+
const DEFAULT_SELECTION = {
|
|
28
|
+
css: 'rgba(255, 255, 255, 0.3)',
|
|
29
|
+
rgba: 0xFFFFFF4D
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// An IIFE to generate DEFAULT_ANSI_COLORS.
|
|
33
|
+
export const DEFAULT_ANSI_COLORS = Object.freeze((() => {
|
|
34
|
+
const colors = [
|
|
35
|
+
// dark:
|
|
36
|
+
css.toColor('#2e3436'),
|
|
37
|
+
css.toColor('#cc0000'),
|
|
38
|
+
css.toColor('#4e9a06'),
|
|
39
|
+
css.toColor('#c4a000'),
|
|
40
|
+
css.toColor('#3465a4'),
|
|
41
|
+
css.toColor('#75507b'),
|
|
42
|
+
css.toColor('#06989a'),
|
|
43
|
+
css.toColor('#d3d7cf'),
|
|
44
|
+
// bright:
|
|
45
|
+
css.toColor('#555753'),
|
|
46
|
+
css.toColor('#ef2929'),
|
|
47
|
+
css.toColor('#8ae234'),
|
|
48
|
+
css.toColor('#fce94f'),
|
|
49
|
+
css.toColor('#729fcf'),
|
|
50
|
+
css.toColor('#ad7fa8'),
|
|
51
|
+
css.toColor('#34e2e2'),
|
|
52
|
+
css.toColor('#eeeeec')
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
// Fill in the remaining 240 ANSI colors.
|
|
56
|
+
// Generate colors (16-231)
|
|
57
|
+
const v = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff];
|
|
58
|
+
for (let i = 0; i < 216; i++) {
|
|
59
|
+
const r = v[(i / 36) % 6 | 0];
|
|
60
|
+
const g = v[(i / 6) % 6 | 0];
|
|
61
|
+
const b = v[i % 6];
|
|
62
|
+
colors.push({
|
|
63
|
+
css: channels.toCss(r, g, b),
|
|
64
|
+
rgba: channels.toRgba(r, g, b)
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Generate greys (232-255)
|
|
69
|
+
for (let i = 0; i < 24; i++) {
|
|
70
|
+
const c = 8 + i * 10;
|
|
71
|
+
colors.push({
|
|
72
|
+
css: channels.toCss(c, c, c),
|
|
73
|
+
rgba: channels.toRgba(c, c, c)
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return colors;
|
|
78
|
+
})());
|
|
79
|
+
|
|
80
|
+
export class ThemeService extends Disposable implements IThemeService {
|
|
81
|
+
public serviceBrand: undefined;
|
|
82
|
+
|
|
83
|
+
private _colors: IColorSet;
|
|
84
|
+
private _contrastCache: IColorContrastCache = new ColorContrastCache();
|
|
85
|
+
private _halfContrastCache: IColorContrastCache = new ColorContrastCache();
|
|
86
|
+
private _restoreColors!: IRestoreColorSet;
|
|
87
|
+
|
|
88
|
+
public get colors(): ReadonlyColorSet { return this._colors; }
|
|
89
|
+
|
|
90
|
+
private readonly _onChangeColors = this.register(new EventEmitter<ReadonlyColorSet>());
|
|
91
|
+
public readonly onChangeColors = this._onChangeColors.event;
|
|
92
|
+
|
|
93
|
+
constructor(
|
|
94
|
+
@IOptionsService private readonly _optionsService: IOptionsService
|
|
95
|
+
) {
|
|
96
|
+
super();
|
|
97
|
+
|
|
98
|
+
this._colors = {
|
|
99
|
+
foreground: DEFAULT_FOREGROUND,
|
|
100
|
+
background: DEFAULT_BACKGROUND,
|
|
101
|
+
cursor: DEFAULT_CURSOR,
|
|
102
|
+
cursorAccent: DEFAULT_CURSOR_ACCENT,
|
|
103
|
+
selectionForeground: undefined,
|
|
104
|
+
selectionBackgroundTransparent: DEFAULT_SELECTION,
|
|
105
|
+
selectionBackgroundOpaque: color.blend(DEFAULT_BACKGROUND, DEFAULT_SELECTION),
|
|
106
|
+
selectionInactiveBackgroundTransparent: DEFAULT_SELECTION,
|
|
107
|
+
selectionInactiveBackgroundOpaque: color.blend(DEFAULT_BACKGROUND, DEFAULT_SELECTION),
|
|
108
|
+
ansi: DEFAULT_ANSI_COLORS.slice(),
|
|
109
|
+
contrastCache: this._contrastCache,
|
|
110
|
+
halfContrastCache: this._halfContrastCache
|
|
111
|
+
};
|
|
112
|
+
this._updateRestoreColors();
|
|
113
|
+
this._setTheme(this._optionsService.rawOptions.theme);
|
|
114
|
+
|
|
115
|
+
this.register(this._optionsService.onSpecificOptionChange('minimumContrastRatio', () => this._contrastCache.clear()));
|
|
116
|
+
this.register(this._optionsService.onSpecificOptionChange('theme', () => this._setTheme(this._optionsService.rawOptions.theme)));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Sets the terminal's theme.
|
|
121
|
+
* @param theme The theme to use. If a partial theme is provided then default
|
|
122
|
+
* colors will be used where colors are not defined.
|
|
123
|
+
*/
|
|
124
|
+
private _setTheme(theme: ITheme = {}): void {
|
|
125
|
+
const colors = this._colors;
|
|
126
|
+
colors.foreground = parseColor(theme.foreground, DEFAULT_FOREGROUND);
|
|
127
|
+
colors.background = parseColor(theme.background, DEFAULT_BACKGROUND);
|
|
128
|
+
colors.cursor = parseColor(theme.cursor, DEFAULT_CURSOR);
|
|
129
|
+
colors.cursorAccent = parseColor(theme.cursorAccent, DEFAULT_CURSOR_ACCENT);
|
|
130
|
+
colors.selectionBackgroundTransparent = parseColor(theme.selectionBackground, DEFAULT_SELECTION);
|
|
131
|
+
colors.selectionBackgroundOpaque = color.blend(colors.background, colors.selectionBackgroundTransparent);
|
|
132
|
+
colors.selectionInactiveBackgroundTransparent = parseColor(theme.selectionInactiveBackground, colors.selectionBackgroundTransparent);
|
|
133
|
+
colors.selectionInactiveBackgroundOpaque = color.blend(colors.background, colors.selectionInactiveBackgroundTransparent);
|
|
134
|
+
colors.selectionForeground = theme.selectionForeground ? parseColor(theme.selectionForeground, NULL_COLOR) : undefined;
|
|
135
|
+
if (colors.selectionForeground === NULL_COLOR) {
|
|
136
|
+
colors.selectionForeground = undefined;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* If selection color is opaque, blend it with background with 0.3 opacity
|
|
141
|
+
* Issue #2737
|
|
142
|
+
*/
|
|
143
|
+
if (color.isOpaque(colors.selectionBackgroundTransparent)) {
|
|
144
|
+
const opacity = 0.3;
|
|
145
|
+
colors.selectionBackgroundTransparent = color.opacity(colors.selectionBackgroundTransparent, opacity);
|
|
146
|
+
}
|
|
147
|
+
if (color.isOpaque(colors.selectionInactiveBackgroundTransparent)) {
|
|
148
|
+
const opacity = 0.3;
|
|
149
|
+
colors.selectionInactiveBackgroundTransparent = color.opacity(colors.selectionInactiveBackgroundTransparent, opacity);
|
|
150
|
+
}
|
|
151
|
+
colors.ansi = DEFAULT_ANSI_COLORS.slice();
|
|
152
|
+
colors.ansi[0] = parseColor(theme.black, DEFAULT_ANSI_COLORS[0]);
|
|
153
|
+
colors.ansi[1] = parseColor(theme.red, DEFAULT_ANSI_COLORS[1]);
|
|
154
|
+
colors.ansi[2] = parseColor(theme.green, DEFAULT_ANSI_COLORS[2]);
|
|
155
|
+
colors.ansi[3] = parseColor(theme.yellow, DEFAULT_ANSI_COLORS[3]);
|
|
156
|
+
colors.ansi[4] = parseColor(theme.blue, DEFAULT_ANSI_COLORS[4]);
|
|
157
|
+
colors.ansi[5] = parseColor(theme.magenta, DEFAULT_ANSI_COLORS[5]);
|
|
158
|
+
colors.ansi[6] = parseColor(theme.cyan, DEFAULT_ANSI_COLORS[6]);
|
|
159
|
+
colors.ansi[7] = parseColor(theme.white, DEFAULT_ANSI_COLORS[7]);
|
|
160
|
+
colors.ansi[8] = parseColor(theme.brightBlack, DEFAULT_ANSI_COLORS[8]);
|
|
161
|
+
colors.ansi[9] = parseColor(theme.brightRed, DEFAULT_ANSI_COLORS[9]);
|
|
162
|
+
colors.ansi[10] = parseColor(theme.brightGreen, DEFAULT_ANSI_COLORS[10]);
|
|
163
|
+
colors.ansi[11] = parseColor(theme.brightYellow, DEFAULT_ANSI_COLORS[11]);
|
|
164
|
+
colors.ansi[12] = parseColor(theme.brightBlue, DEFAULT_ANSI_COLORS[12]);
|
|
165
|
+
colors.ansi[13] = parseColor(theme.brightMagenta, DEFAULT_ANSI_COLORS[13]);
|
|
166
|
+
colors.ansi[14] = parseColor(theme.brightCyan, DEFAULT_ANSI_COLORS[14]);
|
|
167
|
+
colors.ansi[15] = parseColor(theme.brightWhite, DEFAULT_ANSI_COLORS[15]);
|
|
168
|
+
if (theme.extendedAnsi) {
|
|
169
|
+
const colorCount = Math.min(colors.ansi.length - 16, theme.extendedAnsi.length);
|
|
170
|
+
for (let i = 0; i < colorCount; i++) {
|
|
171
|
+
colors.ansi[i + 16] = parseColor(theme.extendedAnsi[i], DEFAULT_ANSI_COLORS[i + 16]);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// Clear our the cache
|
|
175
|
+
this._contrastCache.clear();
|
|
176
|
+
this._halfContrastCache.clear();
|
|
177
|
+
this._updateRestoreColors();
|
|
178
|
+
this._onChangeColors.fire(this.colors);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
public restoreColor(slot?: AllColorIndex): void {
|
|
182
|
+
this._restoreColor(slot);
|
|
183
|
+
this._onChangeColors.fire(this.colors);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
private _restoreColor(slot: AllColorIndex | undefined): void {
|
|
187
|
+
// unset slot restores all ansi colors
|
|
188
|
+
if (slot === undefined) {
|
|
189
|
+
for (let i = 0; i < this._restoreColors.ansi.length; ++i) {
|
|
190
|
+
this._colors.ansi[i] = this._restoreColors.ansi[i];
|
|
191
|
+
}
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
switch (slot) {
|
|
195
|
+
case SpecialColorIndex.FOREGROUND:
|
|
196
|
+
this._colors.foreground = this._restoreColors.foreground;
|
|
197
|
+
break;
|
|
198
|
+
case SpecialColorIndex.BACKGROUND:
|
|
199
|
+
this._colors.background = this._restoreColors.background;
|
|
200
|
+
break;
|
|
201
|
+
case SpecialColorIndex.CURSOR:
|
|
202
|
+
this._colors.cursor = this._restoreColors.cursor;
|
|
203
|
+
break;
|
|
204
|
+
default:
|
|
205
|
+
this._colors.ansi[slot] = this._restoreColors.ansi[slot];
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
public modifyColors(callback: (colors: IColorSet) => void): void {
|
|
210
|
+
callback(this._colors);
|
|
211
|
+
// Assume the change happened
|
|
212
|
+
this._onChangeColors.fire(this.colors);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
private _updateRestoreColors(): void {
|
|
216
|
+
this._restoreColors = {
|
|
217
|
+
foreground: this._colors.foreground,
|
|
218
|
+
background: this._colors.background,
|
|
219
|
+
cursor: this._colors.cursor,
|
|
220
|
+
ansi: this._colors.ansi.slice()
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function parseColor(
|
|
226
|
+
cssString: string | undefined,
|
|
227
|
+
fallback: IColor
|
|
228
|
+
): IColor {
|
|
229
|
+
if (cssString !== undefined) {
|
|
230
|
+
try {
|
|
231
|
+
return css.toColor(cssString);
|
|
232
|
+
} catch {
|
|
233
|
+
// no-op
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return fallback;
|
|
237
|
+
}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2016 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ICircularList } from 'common/Types';
|
|
7
|
+
import { EventEmitter } from 'common/EventEmitter';
|
|
8
|
+
import { Disposable } from 'common/Lifecycle';
|
|
9
|
+
|
|
10
|
+
export interface IInsertEvent {
|
|
11
|
+
index: number;
|
|
12
|
+
amount: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface IDeleteEvent {
|
|
16
|
+
index: number;
|
|
17
|
+
amount: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Represents a circular list; a list with a maximum size that wraps around when push is called,
|
|
22
|
+
* overriding values at the start of the list.
|
|
23
|
+
*/
|
|
24
|
+
export class CircularList<T> extends Disposable implements ICircularList<T> {
|
|
25
|
+
protected _array: (T | undefined)[];
|
|
26
|
+
private _startIndex: number;
|
|
27
|
+
private _length: number;
|
|
28
|
+
|
|
29
|
+
public readonly onDeleteEmitter = this.register(new EventEmitter<IDeleteEvent>());
|
|
30
|
+
public readonly onDelete = this.onDeleteEmitter.event;
|
|
31
|
+
public readonly onInsertEmitter = this.register(new EventEmitter<IInsertEvent>());
|
|
32
|
+
public readonly onInsert = this.onInsertEmitter.event;
|
|
33
|
+
public readonly onTrimEmitter = this.register(new EventEmitter<number>());
|
|
34
|
+
public readonly onTrim = this.onTrimEmitter.event;
|
|
35
|
+
|
|
36
|
+
constructor(
|
|
37
|
+
private _maxLength: number
|
|
38
|
+
) {
|
|
39
|
+
super();
|
|
40
|
+
this._array = new Array<T>(this._maxLength);
|
|
41
|
+
this._startIndex = 0;
|
|
42
|
+
this._length = 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public get maxLength(): number {
|
|
46
|
+
return this._maxLength;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public set maxLength(newMaxLength: number) {
|
|
50
|
+
// There was no change in maxLength, return early.
|
|
51
|
+
if (this._maxLength === newMaxLength) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Reconstruct array, starting at index 0. Only transfer values from the
|
|
56
|
+
// indexes 0 to length.
|
|
57
|
+
const newArray = new Array<T | undefined>(newMaxLength);
|
|
58
|
+
for (let i = 0; i < Math.min(newMaxLength, this.length); i++) {
|
|
59
|
+
newArray[i] = this._array[this._getCyclicIndex(i)];
|
|
60
|
+
}
|
|
61
|
+
this._array = newArray;
|
|
62
|
+
this._maxLength = newMaxLength;
|
|
63
|
+
this._startIndex = 0;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public get length(): number {
|
|
67
|
+
return this._length;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public set length(newLength: number) {
|
|
71
|
+
if (newLength > this._length) {
|
|
72
|
+
for (let i = this._length; i < newLength; i++) {
|
|
73
|
+
this._array[i] = undefined;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
this._length = newLength;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Gets the value at an index.
|
|
81
|
+
*
|
|
82
|
+
* Note that for performance reasons there is no bounds checking here, the index reference is
|
|
83
|
+
* circular so this should always return a value and never throw.
|
|
84
|
+
* @param index The index of the value to get.
|
|
85
|
+
* @returns The value corresponding to the index.
|
|
86
|
+
*/
|
|
87
|
+
public get(index: number): T | undefined {
|
|
88
|
+
return this._array[this._getCyclicIndex(index)];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Sets the value at an index.
|
|
93
|
+
*
|
|
94
|
+
* Note that for performance reasons there is no bounds checking here, the index reference is
|
|
95
|
+
* circular so this should always return a value and never throw.
|
|
96
|
+
* @param index The index to set.
|
|
97
|
+
* @param value The value to set.
|
|
98
|
+
*/
|
|
99
|
+
public set(index: number, value: T | undefined): void {
|
|
100
|
+
this._array[this._getCyclicIndex(index)] = value;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Pushes a new value onto the list, wrapping around to the start of the array, overriding index 0
|
|
105
|
+
* if the maximum length is reached.
|
|
106
|
+
* @param value The value to push onto the list.
|
|
107
|
+
*/
|
|
108
|
+
public push(value: T): void {
|
|
109
|
+
this._array[this._getCyclicIndex(this._length)] = value;
|
|
110
|
+
if (this._length === this._maxLength) {
|
|
111
|
+
this._startIndex = ++this._startIndex % this._maxLength;
|
|
112
|
+
this.onTrimEmitter.fire(1);
|
|
113
|
+
} else {
|
|
114
|
+
this._length++;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Advance ringbuffer index and return current element for recycling.
|
|
120
|
+
* Note: The buffer must be full for this method to work.
|
|
121
|
+
* @throws When the buffer is not full.
|
|
122
|
+
*/
|
|
123
|
+
public recycle(): T {
|
|
124
|
+
if (this._length !== this._maxLength) {
|
|
125
|
+
throw new Error('Can only recycle when the buffer is full');
|
|
126
|
+
}
|
|
127
|
+
this._startIndex = ++this._startIndex % this._maxLength;
|
|
128
|
+
this.onTrimEmitter.fire(1);
|
|
129
|
+
return this._array[this._getCyclicIndex(this._length - 1)]!;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Ringbuffer is at max length.
|
|
134
|
+
*/
|
|
135
|
+
public get isFull(): boolean {
|
|
136
|
+
return this._length === this._maxLength;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Removes and returns the last value on the list.
|
|
141
|
+
* @returns The popped value.
|
|
142
|
+
*/
|
|
143
|
+
public pop(): T | undefined {
|
|
144
|
+
return this._array[this._getCyclicIndex(this._length-- - 1)];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Deletes and/or inserts items at a particular index (in that order). Unlike
|
|
149
|
+
* Array.prototype.splice, this operation does not return the deleted items as a new array in
|
|
150
|
+
* order to save creating a new array. Note that this operation may shift all values in the list
|
|
151
|
+
* in the worst case.
|
|
152
|
+
* @param start The index to delete and/or insert.
|
|
153
|
+
* @param deleteCount The number of elements to delete.
|
|
154
|
+
* @param items The items to insert.
|
|
155
|
+
*/
|
|
156
|
+
public splice(start: number, deleteCount: number, ...items: T[]): void {
|
|
157
|
+
// Delete items
|
|
158
|
+
if (deleteCount) {
|
|
159
|
+
for (let i = start; i < this._length - deleteCount; i++) {
|
|
160
|
+
this._array[this._getCyclicIndex(i)] = this._array[this._getCyclicIndex(i + deleteCount)];
|
|
161
|
+
}
|
|
162
|
+
this._length -= deleteCount;
|
|
163
|
+
this.onDeleteEmitter.fire({ index: start, amount: deleteCount });
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Add items
|
|
167
|
+
for (let i = this._length - 1; i >= start; i--) {
|
|
168
|
+
this._array[this._getCyclicIndex(i + items.length)] = this._array[this._getCyclicIndex(i)];
|
|
169
|
+
}
|
|
170
|
+
for (let i = 0; i < items.length; i++) {
|
|
171
|
+
this._array[this._getCyclicIndex(start + i)] = items[i];
|
|
172
|
+
}
|
|
173
|
+
if (items.length) {
|
|
174
|
+
this.onInsertEmitter.fire({ index: start, amount: items.length });
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Adjust length as needed
|
|
178
|
+
if (this._length + items.length > this._maxLength) {
|
|
179
|
+
const countToTrim = (this._length + items.length) - this._maxLength;
|
|
180
|
+
this._startIndex += countToTrim;
|
|
181
|
+
this._length = this._maxLength;
|
|
182
|
+
this.onTrimEmitter.fire(countToTrim);
|
|
183
|
+
} else {
|
|
184
|
+
this._length += items.length;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Trims a number of items from the start of the list.
|
|
190
|
+
* @param count The number of items to remove.
|
|
191
|
+
*/
|
|
192
|
+
public trimStart(count: number): void {
|
|
193
|
+
if (count > this._length) {
|
|
194
|
+
count = this._length;
|
|
195
|
+
}
|
|
196
|
+
this._startIndex += count;
|
|
197
|
+
this._length -= count;
|
|
198
|
+
this.onTrimEmitter.fire(count);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
public shiftElements(start: number, count: number, offset: number): void {
|
|
202
|
+
if (count <= 0) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (start < 0 || start >= this._length) {
|
|
206
|
+
throw new Error('start argument out of range');
|
|
207
|
+
}
|
|
208
|
+
if (start + offset < 0) {
|
|
209
|
+
throw new Error('Cannot shift elements in list beyond index 0');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (offset > 0) {
|
|
213
|
+
for (let i = count - 1; i >= 0; i--) {
|
|
214
|
+
this.set(start + i + offset, this.get(start + i));
|
|
215
|
+
}
|
|
216
|
+
const expandListBy = (start + count + offset) - this._length;
|
|
217
|
+
if (expandListBy > 0) {
|
|
218
|
+
this._length += expandListBy;
|
|
219
|
+
while (this._length > this._maxLength) {
|
|
220
|
+
this._length--;
|
|
221
|
+
this._startIndex++;
|
|
222
|
+
this.onTrimEmitter.fire(1);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
} else {
|
|
226
|
+
for (let i = 0; i < count; i++) {
|
|
227
|
+
this.set(start + i + offset, this.get(start + i));
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Gets the cyclic index for the specified regular index. The cyclic index can then be used on the
|
|
234
|
+
* backing array to get the element associated with the regular index.
|
|
235
|
+
* @param index The regular index.
|
|
236
|
+
* @returns The cyclic index.
|
|
237
|
+
*/
|
|
238
|
+
private _getCyclicIndex(index: number): number {
|
|
239
|
+
return (this._startIndex + index) % this._maxLength;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2016 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* A simple utility for cloning values
|
|
8
|
+
*/
|
|
9
|
+
export function clone<T>(val: T, depth: number = 5): T {
|
|
10
|
+
if (typeof val !== 'object') {
|
|
11
|
+
return val;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// If we're cloning an array, use an array as the base, otherwise use an object
|
|
15
|
+
const clonedObject: any = Array.isArray(val) ? [] : {};
|
|
16
|
+
|
|
17
|
+
for (const key in val) {
|
|
18
|
+
// Recursively clone eack item unless we're at the maximum depth
|
|
19
|
+
clonedObject[key] = depth <= 1 ? val[key] : (val[key] && clone(val[key], depth - 1));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return clonedObject as T;
|
|
23
|
+
}
|