@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,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { BufferLine } from 'common/buffer/BufferLine';
|
|
7
|
+
import { CircularList } from 'common/CircularList';
|
|
8
|
+
import { IBufferLine, ICellData } from 'common/Types';
|
|
9
|
+
|
|
10
|
+
export interface INewLayoutResult {
|
|
11
|
+
layout: number[];
|
|
12
|
+
countRemoved: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Evaluates and returns indexes to be removed after a reflow larger occurs. Lines will be removed
|
|
17
|
+
* when a wrapped line unwraps.
|
|
18
|
+
* @param lines The buffer lines.
|
|
19
|
+
* @param oldCols The columns before resize
|
|
20
|
+
* @param newCols The columns after resize.
|
|
21
|
+
* @param bufferAbsoluteY The absolute y position of the cursor (baseY + cursorY).
|
|
22
|
+
* @param nullCell The cell data to use when filling in empty cells.
|
|
23
|
+
*/
|
|
24
|
+
export function reflowLargerGetLinesToRemove(lines: CircularList<IBufferLine>, oldCols: number, newCols: number, bufferAbsoluteY: number, nullCell: ICellData): number[] {
|
|
25
|
+
// Gather all BufferLines that need to be removed from the Buffer here so that they can be
|
|
26
|
+
// batched up and only committed once
|
|
27
|
+
const toRemove: number[] = [];
|
|
28
|
+
|
|
29
|
+
for (let y = 0; y < lines.length - 1; y++) {
|
|
30
|
+
// Check if this row is wrapped
|
|
31
|
+
let i = y;
|
|
32
|
+
let nextLine = lines.get(++i) as BufferLine;
|
|
33
|
+
if (!nextLine.isWrapped) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Check how many lines it's wrapped for
|
|
38
|
+
const wrappedLines: BufferLine[] = [lines.get(y) as BufferLine];
|
|
39
|
+
while (i < lines.length && nextLine.isWrapped) {
|
|
40
|
+
wrappedLines.push(nextLine);
|
|
41
|
+
nextLine = lines.get(++i) as BufferLine;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// If these lines contain the cursor don't touch them, the program will handle fixing up wrapped
|
|
45
|
+
// lines with the cursor
|
|
46
|
+
if (bufferAbsoluteY >= y && bufferAbsoluteY < i) {
|
|
47
|
+
y += wrappedLines.length - 1;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Copy buffer data to new locations
|
|
52
|
+
let destLineIndex = 0;
|
|
53
|
+
let destCol = getWrappedLineTrimmedLength(wrappedLines, destLineIndex, oldCols);
|
|
54
|
+
let srcLineIndex = 1;
|
|
55
|
+
let srcCol = 0;
|
|
56
|
+
while (srcLineIndex < wrappedLines.length) {
|
|
57
|
+
const srcTrimmedTineLength = getWrappedLineTrimmedLength(wrappedLines, srcLineIndex, oldCols);
|
|
58
|
+
const srcRemainingCells = srcTrimmedTineLength - srcCol;
|
|
59
|
+
const destRemainingCells = newCols - destCol;
|
|
60
|
+
const cellsToCopy = Math.min(srcRemainingCells, destRemainingCells);
|
|
61
|
+
|
|
62
|
+
wrappedLines[destLineIndex].copyCellsFrom(wrappedLines[srcLineIndex], srcCol, destCol, cellsToCopy, false);
|
|
63
|
+
|
|
64
|
+
destCol += cellsToCopy;
|
|
65
|
+
if (destCol === newCols) {
|
|
66
|
+
destLineIndex++;
|
|
67
|
+
destCol = 0;
|
|
68
|
+
}
|
|
69
|
+
srcCol += cellsToCopy;
|
|
70
|
+
if (srcCol === srcTrimmedTineLength) {
|
|
71
|
+
srcLineIndex++;
|
|
72
|
+
srcCol = 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Make sure the last cell isn't wide, if it is copy it to the current dest
|
|
76
|
+
if (destCol === 0 && destLineIndex !== 0) {
|
|
77
|
+
if (wrappedLines[destLineIndex - 1].getWidth(newCols - 1) === 2) {
|
|
78
|
+
wrappedLines[destLineIndex].copyCellsFrom(wrappedLines[destLineIndex - 1], newCols - 1, destCol++, 1, false);
|
|
79
|
+
// Null out the end of the last row
|
|
80
|
+
wrappedLines[destLineIndex - 1].setCell(newCols - 1, nullCell);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Clear out remaining cells or fragments could remain;
|
|
86
|
+
wrappedLines[destLineIndex].replaceCells(destCol, newCols, nullCell);
|
|
87
|
+
|
|
88
|
+
// Work backwards and remove any rows at the end that only contain null cells
|
|
89
|
+
let countToRemove = 0;
|
|
90
|
+
for (let i = wrappedLines.length - 1; i > 0; i--) {
|
|
91
|
+
if (i > destLineIndex || wrappedLines[i].getTrimmedLength() === 0) {
|
|
92
|
+
countToRemove++;
|
|
93
|
+
} else {
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (countToRemove > 0) {
|
|
99
|
+
toRemove.push(y + wrappedLines.length - countToRemove); // index
|
|
100
|
+
toRemove.push(countToRemove);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
y += wrappedLines.length - 1;
|
|
104
|
+
}
|
|
105
|
+
return toRemove;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Creates and return the new layout for lines given an array of indexes to be removed.
|
|
110
|
+
* @param lines The buffer lines.
|
|
111
|
+
* @param toRemove The indexes to remove.
|
|
112
|
+
*/
|
|
113
|
+
export function reflowLargerCreateNewLayout(lines: CircularList<IBufferLine>, toRemove: number[]): INewLayoutResult {
|
|
114
|
+
const layout: number[] = [];
|
|
115
|
+
// First iterate through the list and get the actual indexes to use for rows
|
|
116
|
+
let nextToRemoveIndex = 0;
|
|
117
|
+
let nextToRemoveStart = toRemove[nextToRemoveIndex];
|
|
118
|
+
let countRemovedSoFar = 0;
|
|
119
|
+
for (let i = 0; i < lines.length; i++) {
|
|
120
|
+
if (nextToRemoveStart === i) {
|
|
121
|
+
const countToRemove = toRemove[++nextToRemoveIndex];
|
|
122
|
+
|
|
123
|
+
// Tell markers that there was a deletion
|
|
124
|
+
lines.onDeleteEmitter.fire({
|
|
125
|
+
index: i - countRemovedSoFar,
|
|
126
|
+
amount: countToRemove
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
i += countToRemove - 1;
|
|
130
|
+
countRemovedSoFar += countToRemove;
|
|
131
|
+
nextToRemoveStart = toRemove[++nextToRemoveIndex];
|
|
132
|
+
} else {
|
|
133
|
+
layout.push(i);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
layout,
|
|
138
|
+
countRemoved: countRemovedSoFar
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Applies a new layout to the buffer. This essentially does the same as many splice calls but it's
|
|
144
|
+
* done all at once in a single iteration through the list since splice is very expensive.
|
|
145
|
+
* @param lines The buffer lines.
|
|
146
|
+
* @param newLayout The new layout to apply.
|
|
147
|
+
*/
|
|
148
|
+
export function reflowLargerApplyNewLayout(lines: CircularList<IBufferLine>, newLayout: number[]): void {
|
|
149
|
+
// Record original lines so they don't get overridden when we rearrange the list
|
|
150
|
+
const newLayoutLines: BufferLine[] = [];
|
|
151
|
+
for (let i = 0; i < newLayout.length; i++) {
|
|
152
|
+
newLayoutLines.push(lines.get(newLayout[i]) as BufferLine);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Rearrange the list
|
|
156
|
+
for (let i = 0; i < newLayoutLines.length; i++) {
|
|
157
|
+
lines.set(i, newLayoutLines[i]);
|
|
158
|
+
}
|
|
159
|
+
lines.length = newLayout.length;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Gets the new line lengths for a given wrapped line. The purpose of this function it to pre-
|
|
164
|
+
* compute the wrapping points since wide characters may need to be wrapped onto the following line.
|
|
165
|
+
* This function will return an array of numbers of where each line wraps to, the resulting array
|
|
166
|
+
* will only contain the values `newCols` (when the line does not end with a wide character) and
|
|
167
|
+
* `newCols - 1` (when the line does end with a wide character), except for the last value which
|
|
168
|
+
* will contain the remaining items to fill the line.
|
|
169
|
+
*
|
|
170
|
+
* Calling this with a `newCols` value of `1` will lock up.
|
|
171
|
+
*
|
|
172
|
+
* @param wrappedLines The wrapped lines to evaluate.
|
|
173
|
+
* @param oldCols The columns before resize.
|
|
174
|
+
* @param newCols The columns after resize.
|
|
175
|
+
*/
|
|
176
|
+
export function reflowSmallerGetNewLineLengths(wrappedLines: BufferLine[], oldCols: number, newCols: number): number[] {
|
|
177
|
+
const newLineLengths: number[] = [];
|
|
178
|
+
const cellsNeeded = wrappedLines.map((l, i) => getWrappedLineTrimmedLength(wrappedLines, i, oldCols)).reduce((p, c) => p + c);
|
|
179
|
+
|
|
180
|
+
// Use srcCol and srcLine to find the new wrapping point, use that to get the cellsAvailable and
|
|
181
|
+
// linesNeeded
|
|
182
|
+
let srcCol = 0;
|
|
183
|
+
let srcLine = 0;
|
|
184
|
+
let cellsAvailable = 0;
|
|
185
|
+
while (cellsAvailable < cellsNeeded) {
|
|
186
|
+
if (cellsNeeded - cellsAvailable < newCols) {
|
|
187
|
+
// Add the final line and exit the loop
|
|
188
|
+
newLineLengths.push(cellsNeeded - cellsAvailable);
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
srcCol += newCols;
|
|
192
|
+
const oldTrimmedLength = getWrappedLineTrimmedLength(wrappedLines, srcLine, oldCols);
|
|
193
|
+
if (srcCol > oldTrimmedLength) {
|
|
194
|
+
srcCol -= oldTrimmedLength;
|
|
195
|
+
srcLine++;
|
|
196
|
+
}
|
|
197
|
+
const endsWithWide = wrappedLines[srcLine].getWidth(srcCol - 1) === 2;
|
|
198
|
+
if (endsWithWide) {
|
|
199
|
+
srcCol--;
|
|
200
|
+
}
|
|
201
|
+
const lineLength = endsWithWide ? newCols - 1 : newCols;
|
|
202
|
+
newLineLengths.push(lineLength);
|
|
203
|
+
cellsAvailable += lineLength;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return newLineLengths;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function getWrappedLineTrimmedLength(lines: BufferLine[], i: number, cols: number): number {
|
|
210
|
+
// If this is the last row in the wrapped line, get the actual trimmed length
|
|
211
|
+
if (i === lines.length - 1) {
|
|
212
|
+
return lines[i].getTrimmedLength();
|
|
213
|
+
}
|
|
214
|
+
// Detect whether the following line starts with a wide character and the end of the current line
|
|
215
|
+
// is null, if so then we can be pretty sure the null character should be excluded from the line
|
|
216
|
+
// length]
|
|
217
|
+
const endsInNull = !(lines[i].hasContent(cols - 1)) && lines[i].getWidth(cols - 1) === 1;
|
|
218
|
+
const followingLineStartsWithWide = lines[i + 1].getWidth(0) === 2;
|
|
219
|
+
if (endsInNull && followingLineStartsWithWide) {
|
|
220
|
+
return cols - 1;
|
|
221
|
+
}
|
|
222
|
+
return cols;
|
|
223
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { EventEmitter } from 'common/EventEmitter';
|
|
7
|
+
import { Disposable } from 'common/Lifecycle';
|
|
8
|
+
import { IAttributeData } from 'common/Types';
|
|
9
|
+
import { Buffer } from 'common/buffer/Buffer';
|
|
10
|
+
import { IBuffer, IBufferSet } from 'common/buffer/Types';
|
|
11
|
+
import { IBufferService, IOptionsService } from 'common/services/Services';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The BufferSet represents the set of two buffers used by xterm terminals (normal and alt) and
|
|
15
|
+
* provides also utilities for working with them.
|
|
16
|
+
*/
|
|
17
|
+
export class BufferSet extends Disposable implements IBufferSet {
|
|
18
|
+
private _normal!: Buffer;
|
|
19
|
+
private _alt!: Buffer;
|
|
20
|
+
private _activeBuffer!: Buffer;
|
|
21
|
+
|
|
22
|
+
private readonly _onBufferActivate = this.register(new EventEmitter<{activeBuffer: IBuffer, inactiveBuffer: IBuffer}>());
|
|
23
|
+
public readonly onBufferActivate = this._onBufferActivate.event;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Create a new BufferSet for the given terminal.
|
|
27
|
+
*/
|
|
28
|
+
constructor(
|
|
29
|
+
private readonly _optionsService: IOptionsService,
|
|
30
|
+
private readonly _bufferService: IBufferService
|
|
31
|
+
) {
|
|
32
|
+
super();
|
|
33
|
+
this.reset();
|
|
34
|
+
this.register(this._optionsService.onSpecificOptionChange('scrollback', () => this.resize(this._bufferService.cols, this._bufferService.rows)));
|
|
35
|
+
this.register(this._optionsService.onSpecificOptionChange('tabStopWidth', () => this.setupTabStops()));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public reset(): void {
|
|
39
|
+
this._normal = new Buffer(true, this._optionsService, this._bufferService);
|
|
40
|
+
this._normal.fillViewportRows();
|
|
41
|
+
|
|
42
|
+
// The alt buffer should never have scrollback.
|
|
43
|
+
// See http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer
|
|
44
|
+
this._alt = new Buffer(false, this._optionsService, this._bufferService);
|
|
45
|
+
this._activeBuffer = this._normal;
|
|
46
|
+
this._onBufferActivate.fire({
|
|
47
|
+
activeBuffer: this._normal,
|
|
48
|
+
inactiveBuffer: this._alt
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
this.setupTabStops();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Returns the alt Buffer of the BufferSet
|
|
56
|
+
*/
|
|
57
|
+
public get alt(): Buffer {
|
|
58
|
+
return this._alt;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Returns the currently active Buffer of the BufferSet
|
|
63
|
+
*/
|
|
64
|
+
public get active(): Buffer {
|
|
65
|
+
return this._activeBuffer;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Returns the normal Buffer of the BufferSet
|
|
70
|
+
*/
|
|
71
|
+
public get normal(): Buffer {
|
|
72
|
+
return this._normal;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Sets the normal Buffer of the BufferSet as its currently active Buffer
|
|
77
|
+
*/
|
|
78
|
+
public activateNormalBuffer(): void {
|
|
79
|
+
if (this._activeBuffer === this._normal) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
this._normal.x = this._alt.x;
|
|
83
|
+
this._normal.y = this._alt.y;
|
|
84
|
+
// The alt buffer should always be cleared when we switch to the normal
|
|
85
|
+
// buffer. This frees up memory since the alt buffer should always be new
|
|
86
|
+
// when activated.
|
|
87
|
+
this._alt.clearAllMarkers();
|
|
88
|
+
this._alt.clear();
|
|
89
|
+
this._activeBuffer = this._normal;
|
|
90
|
+
this._onBufferActivate.fire({
|
|
91
|
+
activeBuffer: this._normal,
|
|
92
|
+
inactiveBuffer: this._alt
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Sets the alt Buffer of the BufferSet as its currently active Buffer
|
|
98
|
+
*/
|
|
99
|
+
public activateAltBuffer(fillAttr?: IAttributeData): void {
|
|
100
|
+
if (this._activeBuffer === this._alt) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
// Since the alt buffer is always cleared when the normal buffer is
|
|
104
|
+
// activated, we want to fill it when switching to it.
|
|
105
|
+
this._alt.fillViewportRows(fillAttr);
|
|
106
|
+
this._alt.x = this._normal.x;
|
|
107
|
+
this._alt.y = this._normal.y;
|
|
108
|
+
this._activeBuffer = this._alt;
|
|
109
|
+
this._onBufferActivate.fire({
|
|
110
|
+
activeBuffer: this._alt,
|
|
111
|
+
inactiveBuffer: this._normal
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Resizes both normal and alt buffers, adjusting their data accordingly.
|
|
117
|
+
* @param newCols The new number of columns.
|
|
118
|
+
* @param newRows The new number of rows.
|
|
119
|
+
*/
|
|
120
|
+
public resize(newCols: number, newRows: number): void {
|
|
121
|
+
this._normal.resize(newCols, newRows);
|
|
122
|
+
this._alt.resize(newCols, newRows);
|
|
123
|
+
this.setupTabStops(newCols);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Setup the tab stops.
|
|
128
|
+
* @param i The index to start setting up tab stops from.
|
|
129
|
+
*/
|
|
130
|
+
public setupTabStops(i?: number): void {
|
|
131
|
+
this._normal.setupTabStops(i);
|
|
132
|
+
this._alt.setupTabStops(i);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { CharData, ICellData, IExtendedAttrs } from 'common/Types';
|
|
7
|
+
import { stringFromCodePoint } from 'common/input/TextDecoder';
|
|
8
|
+
import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, CHAR_DATA_ATTR_INDEX, Content } from 'common/buffer/Constants';
|
|
9
|
+
import { AttributeData, ExtendedAttrs } from 'common/buffer/AttributeData';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* CellData - represents a single Cell in the terminal buffer.
|
|
13
|
+
*/
|
|
14
|
+
export class CellData extends AttributeData implements ICellData {
|
|
15
|
+
/** Helper to create CellData from CharData. */
|
|
16
|
+
public static fromCharData(value: CharData): CellData {
|
|
17
|
+
const obj = new CellData();
|
|
18
|
+
obj.setFromCharData(value);
|
|
19
|
+
return obj;
|
|
20
|
+
}
|
|
21
|
+
/** Primitives from terminal buffer. */
|
|
22
|
+
public content = 0;
|
|
23
|
+
public fg = 0;
|
|
24
|
+
public bg = 0;
|
|
25
|
+
public extended: IExtendedAttrs = new ExtendedAttrs();
|
|
26
|
+
public combinedData = '';
|
|
27
|
+
/** Whether cell contains a combined string. */
|
|
28
|
+
public isCombined(): number {
|
|
29
|
+
return this.content & Content.IS_COMBINED_MASK;
|
|
30
|
+
}
|
|
31
|
+
/** Width of the cell. */
|
|
32
|
+
public getWidth(): number {
|
|
33
|
+
return this.content >> Content.WIDTH_SHIFT;
|
|
34
|
+
}
|
|
35
|
+
/** JS string of the content. */
|
|
36
|
+
public getChars(): string {
|
|
37
|
+
if (this.content & Content.IS_COMBINED_MASK) {
|
|
38
|
+
return this.combinedData;
|
|
39
|
+
}
|
|
40
|
+
if (this.content & Content.CODEPOINT_MASK) {
|
|
41
|
+
return stringFromCodePoint(this.content & Content.CODEPOINT_MASK);
|
|
42
|
+
}
|
|
43
|
+
return '';
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Codepoint of cell
|
|
47
|
+
* Note this returns the UTF32 codepoint of single chars,
|
|
48
|
+
* if content is a combined string it returns the codepoint
|
|
49
|
+
* of the last char in string to be in line with code in CharData.
|
|
50
|
+
*/
|
|
51
|
+
public getCode(): number {
|
|
52
|
+
return (this.isCombined())
|
|
53
|
+
? this.combinedData.charCodeAt(this.combinedData.length - 1)
|
|
54
|
+
: this.content & Content.CODEPOINT_MASK;
|
|
55
|
+
}
|
|
56
|
+
/** Set data from CharData */
|
|
57
|
+
public setFromCharData(value: CharData): void {
|
|
58
|
+
this.fg = value[CHAR_DATA_ATTR_INDEX];
|
|
59
|
+
this.bg = 0;
|
|
60
|
+
let combined = false;
|
|
61
|
+
// surrogates and combined strings need special treatment
|
|
62
|
+
if (value[CHAR_DATA_CHAR_INDEX].length > 2) {
|
|
63
|
+
combined = true;
|
|
64
|
+
}
|
|
65
|
+
else if (value[CHAR_DATA_CHAR_INDEX].length === 2) {
|
|
66
|
+
const code = value[CHAR_DATA_CHAR_INDEX].charCodeAt(0);
|
|
67
|
+
// if the 2-char string is a surrogate create single codepoint
|
|
68
|
+
// everything else is combined
|
|
69
|
+
if (0xD800 <= code && code <= 0xDBFF) {
|
|
70
|
+
const second = value[CHAR_DATA_CHAR_INDEX].charCodeAt(1);
|
|
71
|
+
if (0xDC00 <= second && second <= 0xDFFF) {
|
|
72
|
+
this.content = ((code - 0xD800) * 0x400 + second - 0xDC00 + 0x10000) | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
combined = true;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
combined = true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
this.content = value[CHAR_DATA_CHAR_INDEX].charCodeAt(0) | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
|
|
84
|
+
}
|
|
85
|
+
if (combined) {
|
|
86
|
+
this.combinedData = value[CHAR_DATA_CHAR_INDEX];
|
|
87
|
+
this.content = Content.IS_COMBINED_MASK | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/** Get data as CharData. */
|
|
91
|
+
public getAsCharData(): CharData {
|
|
92
|
+
return [this.fg, this.getChars(), this.getWidth(), this.getCode()];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const DEFAULT_COLOR = 0;
|
|
7
|
+
export const DEFAULT_ATTR = (0 << 18) | (DEFAULT_COLOR << 9) | (256 << 0);
|
|
8
|
+
export const DEFAULT_EXT = 0;
|
|
9
|
+
|
|
10
|
+
export const CHAR_DATA_ATTR_INDEX = 0;
|
|
11
|
+
export const CHAR_DATA_CHAR_INDEX = 1;
|
|
12
|
+
export const CHAR_DATA_WIDTH_INDEX = 2;
|
|
13
|
+
export const CHAR_DATA_CODE_INDEX = 3;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Null cell - a real empty cell (containing nothing).
|
|
17
|
+
* Note that code should always be 0 for a null cell as
|
|
18
|
+
* several test condition of the buffer line rely on this.
|
|
19
|
+
*/
|
|
20
|
+
export const NULL_CELL_CHAR = '';
|
|
21
|
+
export const NULL_CELL_WIDTH = 1;
|
|
22
|
+
export const NULL_CELL_CODE = 0;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Whitespace cell.
|
|
26
|
+
* This is meant as a replacement for empty cells when needed
|
|
27
|
+
* during rendering lines to preserve correct aligment.
|
|
28
|
+
*/
|
|
29
|
+
export const WHITESPACE_CELL_CHAR = ' ';
|
|
30
|
+
export const WHITESPACE_CELL_WIDTH = 1;
|
|
31
|
+
export const WHITESPACE_CELL_CODE = 32;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Bitmasks for accessing data in `content`.
|
|
35
|
+
*/
|
|
36
|
+
export const enum Content {
|
|
37
|
+
/**
|
|
38
|
+
* bit 1..21 codepoint, max allowed in UTF32 is 0x10FFFF (21 bits taken)
|
|
39
|
+
* read: `codepoint = content & Content.codepointMask;`
|
|
40
|
+
* write: `content |= codepoint & Content.codepointMask;`
|
|
41
|
+
* shortcut if precondition `codepoint <= 0x10FFFF` is met:
|
|
42
|
+
* `content |= codepoint;`
|
|
43
|
+
*/
|
|
44
|
+
CODEPOINT_MASK = 0x1FFFFF,
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* bit 22 flag indication whether a cell contains combined content
|
|
48
|
+
* read: `isCombined = content & Content.isCombined;`
|
|
49
|
+
* set: `content |= Content.isCombined;`
|
|
50
|
+
* clear: `content &= ~Content.isCombined;`
|
|
51
|
+
*/
|
|
52
|
+
IS_COMBINED_MASK = 0x200000, // 1 << 21
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* bit 1..22 mask to check whether a cell contains any string data
|
|
56
|
+
* we need to check for codepoint and isCombined bits to see
|
|
57
|
+
* whether a cell contains anything
|
|
58
|
+
* read: `isEmpty = !(content & Content.hasContent)`
|
|
59
|
+
*/
|
|
60
|
+
HAS_CONTENT_MASK = 0x3FFFFF,
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* bit 23..24 wcwidth value of cell, takes 2 bits (ranges from 0..2)
|
|
64
|
+
* read: `width = (content & Content.widthMask) >> Content.widthShift;`
|
|
65
|
+
* `hasWidth = content & Content.widthMask;`
|
|
66
|
+
* as long as wcwidth is highest value in `content`:
|
|
67
|
+
* `width = content >> Content.widthShift;`
|
|
68
|
+
* write: `content |= (width << Content.widthShift) & Content.widthMask;`
|
|
69
|
+
* shortcut if precondition `0 <= width <= 3` is met:
|
|
70
|
+
* `content |= width << Content.widthShift;`
|
|
71
|
+
*/
|
|
72
|
+
WIDTH_MASK = 0xC00000, // 3 << 22
|
|
73
|
+
WIDTH_SHIFT = 22
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export const enum Attributes {
|
|
77
|
+
/**
|
|
78
|
+
* bit 1..8 blue in RGB, color in P256 and P16
|
|
79
|
+
*/
|
|
80
|
+
BLUE_MASK = 0xFF,
|
|
81
|
+
BLUE_SHIFT = 0,
|
|
82
|
+
PCOLOR_MASK = 0xFF,
|
|
83
|
+
PCOLOR_SHIFT = 0,
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* bit 9..16 green in RGB
|
|
87
|
+
*/
|
|
88
|
+
GREEN_MASK = 0xFF00,
|
|
89
|
+
GREEN_SHIFT = 8,
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* bit 17..24 red in RGB
|
|
93
|
+
*/
|
|
94
|
+
RED_MASK = 0xFF0000,
|
|
95
|
+
RED_SHIFT = 16,
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* bit 25..26 color mode: DEFAULT (0) | P16 (1) | P256 (2) | RGB (3)
|
|
99
|
+
*/
|
|
100
|
+
CM_MASK = 0x3000000,
|
|
101
|
+
CM_DEFAULT = 0,
|
|
102
|
+
CM_P16 = 0x1000000,
|
|
103
|
+
CM_P256 = 0x2000000,
|
|
104
|
+
CM_RGB = 0x3000000,
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* bit 1..24 RGB room
|
|
108
|
+
*/
|
|
109
|
+
RGB_MASK = 0xFFFFFF
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export const enum FgFlags {
|
|
113
|
+
/**
|
|
114
|
+
* bit 27..32
|
|
115
|
+
*/
|
|
116
|
+
INVERSE = 0x4000000,
|
|
117
|
+
BOLD = 0x8000000,
|
|
118
|
+
UNDERLINE = 0x10000000,
|
|
119
|
+
BLINK = 0x20000000,
|
|
120
|
+
INVISIBLE = 0x40000000,
|
|
121
|
+
STRIKETHROUGH = 0x80000000,
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export const enum BgFlags {
|
|
125
|
+
/**
|
|
126
|
+
* bit 27..32 (upper 2 unused)
|
|
127
|
+
*/
|
|
128
|
+
ITALIC = 0x4000000,
|
|
129
|
+
DIM = 0x8000000,
|
|
130
|
+
HAS_EXTENDED = 0x10000000,
|
|
131
|
+
PROTECTED = 0x20000000,
|
|
132
|
+
OVERLINE = 0x40000000
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export const enum ExtFlags {
|
|
136
|
+
/**
|
|
137
|
+
* bit 27..32 (upper 3 unused)
|
|
138
|
+
*/
|
|
139
|
+
UNDERLINE_STYLE = 0x1C000000
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export const enum UnderlineStyle {
|
|
143
|
+
NONE = 0,
|
|
144
|
+
SINGLE = 1,
|
|
145
|
+
DOUBLE = 2,
|
|
146
|
+
CURLY = 3,
|
|
147
|
+
DOTTED = 4,
|
|
148
|
+
DASHED = 5
|
|
149
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { EventEmitter } from 'common/EventEmitter';
|
|
7
|
+
import { disposeArray } from 'common/Lifecycle';
|
|
8
|
+
import { IDisposable, IMarker } from 'common/Types';
|
|
9
|
+
|
|
10
|
+
export class Marker implements IMarker {
|
|
11
|
+
private static _nextId = 1;
|
|
12
|
+
|
|
13
|
+
public isDisposed: boolean = false;
|
|
14
|
+
private readonly _disposables: IDisposable[] = [];
|
|
15
|
+
|
|
16
|
+
private readonly _id: number = Marker._nextId++;
|
|
17
|
+
public get id(): number { return this._id; }
|
|
18
|
+
|
|
19
|
+
private readonly _onDispose = this.register(new EventEmitter<void>());
|
|
20
|
+
public readonly onDispose = this._onDispose.event;
|
|
21
|
+
|
|
22
|
+
constructor(
|
|
23
|
+
public line: number
|
|
24
|
+
) {
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public dispose(): void {
|
|
28
|
+
if (this.isDisposed) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
this.isDisposed = true;
|
|
32
|
+
this.line = -1;
|
|
33
|
+
// Emit before super.dispose such that dispose listeners get a change to react
|
|
34
|
+
this._onDispose.fire();
|
|
35
|
+
disposeArray(this._disposables);
|
|
36
|
+
this._disposables.length = 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public register<T extends IDisposable>(disposable: T): T {
|
|
40
|
+
this._disposables.push(disposable);
|
|
41
|
+
return disposable;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { IAttributeData, ICircularList, IBufferLine, ICellData, IMarker, ICharset, IDisposable } from 'common/Types';
|
|
7
|
+
import { IEvent } from 'common/EventEmitter';
|
|
8
|
+
|
|
9
|
+
// BufferIndex denotes a position in the buffer: [rowIndex, colIndex]
|
|
10
|
+
export type BufferIndex = [number, number];
|
|
11
|
+
|
|
12
|
+
export interface IBuffer {
|
|
13
|
+
readonly lines: ICircularList<IBufferLine>;
|
|
14
|
+
ydisp: number;
|
|
15
|
+
ybase: number;
|
|
16
|
+
y: number;
|
|
17
|
+
x: number;
|
|
18
|
+
tabs: any;
|
|
19
|
+
scrollBottom: number;
|
|
20
|
+
scrollTop: number;
|
|
21
|
+
hasScrollback: boolean;
|
|
22
|
+
savedY: number;
|
|
23
|
+
savedX: number;
|
|
24
|
+
savedCharset: ICharset | undefined;
|
|
25
|
+
savedCurAttrData: IAttributeData;
|
|
26
|
+
isCursorInViewport: boolean;
|
|
27
|
+
markers: IMarker[];
|
|
28
|
+
translateBufferLineToString(lineIndex: number, trimRight: boolean, startCol?: number, endCol?: number): string;
|
|
29
|
+
getWrappedRangeForLine(y: number): { first: number, last: number };
|
|
30
|
+
nextStop(x?: number): number;
|
|
31
|
+
prevStop(x?: number): number;
|
|
32
|
+
getBlankLine(attr: IAttributeData, isWrapped?: boolean): IBufferLine;
|
|
33
|
+
getNullCell(attr?: IAttributeData): ICellData;
|
|
34
|
+
getWhitespaceCell(attr?: IAttributeData): ICellData;
|
|
35
|
+
addMarker(y: number): IMarker;
|
|
36
|
+
clearMarkers(y: number): void;
|
|
37
|
+
clearAllMarkers(): void;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface IBufferSet extends IDisposable {
|
|
41
|
+
alt: IBuffer;
|
|
42
|
+
normal: IBuffer;
|
|
43
|
+
active: IBuffer;
|
|
44
|
+
|
|
45
|
+
onBufferActivate: IEvent<{ activeBuffer: IBuffer, inactiveBuffer: IBuffer }>;
|
|
46
|
+
|
|
47
|
+
activateNormalBuffer(): void;
|
|
48
|
+
activateAltBuffer(fillAttr?: IAttributeData): void;
|
|
49
|
+
reset(): void;
|
|
50
|
+
resize(newCols: number, newRows: number): void;
|
|
51
|
+
setupTabStops(i?: number): void;
|
|
52
|
+
}
|