@xterm/xterm 5.4.0-beta.7 → 5.4.0-beta.9
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/lib/xterm.js +1 -1
- package/lib/xterm.js.map +1 -1
- package/package.json +1 -1
- package/src/browser/Terminal.ts +1 -1
- package/src/browser/renderer/dom/DomRenderer.ts +20 -9
- package/src/browser/renderer/shared/CellColorResolver.ts +16 -3
- package/src/browser/renderer/shared/RendererUtils.ts +4 -0
- package/src/browser/renderer/shared/SelectionRenderModel.ts +5 -3
- package/src/browser/renderer/shared/TextureAtlas.ts +18 -4
- package/src/browser/renderer/shared/Types.d.ts +2 -2
- package/src/common/Types.d.ts +2 -0
- package/src/common/buffer/AttributeData.ts +15 -0
- package/src/common/buffer/Constants.ts +10 -2
package/package.json
CHANGED
package/src/browser/Terminal.ts
CHANGED
|
@@ -575,7 +575,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
|
|
|
575
575
|
}
|
|
576
576
|
|
|
577
577
|
private _createRenderer(): IRenderer {
|
|
578
|
-
return this._instantiationService.createInstance(DomRenderer, this._document!, this.element!, this.screenElement!, this._viewportElement!, this._helperContainer!, this.linkifier2);
|
|
578
|
+
return this._instantiationService.createInstance(DomRenderer, this, this._document!, this.element!, this.screenElement!, this._viewportElement!, this._helperContainer!, this.linkifier2);
|
|
579
579
|
}
|
|
580
580
|
|
|
581
581
|
/**
|
|
@@ -7,9 +7,10 @@ import { DomRendererRowFactory, RowCss } from 'browser/renderer/dom/DomRendererR
|
|
|
7
7
|
import { WidthCache } from 'browser/renderer/dom/WidthCache';
|
|
8
8
|
import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/shared/Constants';
|
|
9
9
|
import { createRenderDimensions } from 'browser/renderer/shared/RendererUtils';
|
|
10
|
-
import {
|
|
10
|
+
import { createSelectionRenderModel } from 'browser/renderer/shared/SelectionRenderModel';
|
|
11
|
+
import { IRenderDimensions, IRenderer, IRequestRedrawEvent, ISelectionRenderModel } from 'browser/renderer/shared/Types';
|
|
11
12
|
import { ICharSizeService, ICoreBrowserService, IThemeService } from 'browser/services/Services';
|
|
12
|
-
import { ILinkifier2, ILinkifierEvent, ReadonlyColorSet } from 'browser/Types';
|
|
13
|
+
import { ILinkifier2, ILinkifierEvent, ITerminal, ReadonlyColorSet } from 'browser/Types';
|
|
13
14
|
import { color } from 'common/Color';
|
|
14
15
|
import { EventEmitter } from 'common/EventEmitter';
|
|
15
16
|
import { Disposable, toDisposable } from 'common/Lifecycle';
|
|
@@ -25,7 +26,6 @@ const SELECTION_CLASS = 'xterm-selection';
|
|
|
25
26
|
|
|
26
27
|
let nextTerminalId = 1;
|
|
27
28
|
|
|
28
|
-
|
|
29
29
|
/**
|
|
30
30
|
* A fallback renderer for when canvas is slow. This is not meant to be
|
|
31
31
|
* particularly fast or feature complete, more just stable and usable for when
|
|
@@ -41,12 +41,14 @@ export class DomRenderer extends Disposable implements IRenderer {
|
|
|
41
41
|
private _rowElements: HTMLElement[] = [];
|
|
42
42
|
private _selectionContainer: HTMLElement;
|
|
43
43
|
private _widthCache: WidthCache;
|
|
44
|
+
private _selectionRenderModel: ISelectionRenderModel = createSelectionRenderModel();
|
|
44
45
|
|
|
45
46
|
public dimensions: IRenderDimensions;
|
|
46
47
|
|
|
47
48
|
public readonly onRequestRedraw = this.register(new EventEmitter<IRequestRedrawEvent>()).event;
|
|
48
49
|
|
|
49
50
|
constructor(
|
|
51
|
+
private readonly _terminal: ITerminal,
|
|
50
52
|
private readonly _document: Document,
|
|
51
53
|
private readonly _element: HTMLElement,
|
|
52
54
|
private readonly _screenElement: HTMLElement,
|
|
@@ -291,6 +293,7 @@ export class DomRenderer extends Disposable implements IRenderer {
|
|
|
291
293
|
public handleResize(cols: number, rows: number): void {
|
|
292
294
|
this._refreshRowElements(cols, rows);
|
|
293
295
|
this._updateDimensions();
|
|
296
|
+
this.handleSelectionChanged(this._selectionRenderModel.selectionStart, this._selectionRenderModel.selectionEnd, this._selectionRenderModel.columnSelectMode);
|
|
294
297
|
}
|
|
295
298
|
|
|
296
299
|
public handleCharSizeChanged(): void {
|
|
@@ -320,11 +323,13 @@ export class DomRenderer extends Disposable implements IRenderer {
|
|
|
320
323
|
return;
|
|
321
324
|
}
|
|
322
325
|
|
|
326
|
+
this._selectionRenderModel.update(this._terminal, start, end, columnSelectMode);
|
|
327
|
+
|
|
323
328
|
// Translate from buffer position to viewport position
|
|
324
|
-
const viewportStartRow =
|
|
325
|
-
const viewportEndRow =
|
|
326
|
-
const viewportCappedStartRow =
|
|
327
|
-
const viewportCappedEndRow =
|
|
329
|
+
const viewportStartRow = this._selectionRenderModel.viewportStartRow;
|
|
330
|
+
const viewportEndRow = this._selectionRenderModel.viewportEndRow;
|
|
331
|
+
const viewportCappedStartRow = this._selectionRenderModel.viewportCappedStartRow;
|
|
332
|
+
const viewportCappedEndRow = this._selectionRenderModel.viewportCappedEndRow;
|
|
328
333
|
|
|
329
334
|
// No need to draw the selection
|
|
330
335
|
if (viewportCappedStartRow >= this._bufferService.rows || viewportCappedEndRow < 0) {
|
|
@@ -365,10 +370,16 @@ export class DomRenderer extends Disposable implements IRenderer {
|
|
|
365
370
|
*/
|
|
366
371
|
private _createSelectionElement(row: number, colStart: number, colEnd: number, rowCount: number = 1): HTMLElement {
|
|
367
372
|
const element = this._document.createElement('div');
|
|
373
|
+
const left = colStart * this.dimensions.css.cell.width;
|
|
374
|
+
let width = this.dimensions.css.cell.width * (colEnd - colStart);
|
|
375
|
+
if (left + width > this.dimensions.css.canvas.width) {
|
|
376
|
+
width = this.dimensions.css.canvas.width - left;
|
|
377
|
+
}
|
|
378
|
+
|
|
368
379
|
element.style.height = `${rowCount * this.dimensions.css.cell.height}px`;
|
|
369
380
|
element.style.top = `${row * this.dimensions.css.cell.height}px`;
|
|
370
|
-
element.style.left = `${
|
|
371
|
-
element.style.width = `${
|
|
381
|
+
element.style.left = `${left}px`;
|
|
382
|
+
element.style.width = `${width}px`;
|
|
372
383
|
return element;
|
|
373
384
|
}
|
|
374
385
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ISelectionRenderModel } from 'browser/renderer/shared/Types';
|
|
2
2
|
import { ICoreBrowserService, IThemeService } from 'browser/services/Services';
|
|
3
3
|
import { ReadonlyColorSet } from 'browser/Types';
|
|
4
|
-
import { Attributes, BgFlags, FgFlags } from 'common/buffer/Constants';
|
|
5
|
-
import { IDecorationService } from 'common/services/Services';
|
|
4
|
+
import { Attributes, BgFlags, ExtFlags, FgFlags, NULL_CELL_CODE, UnderlineStyle } from 'common/buffer/Constants';
|
|
5
|
+
import { IDecorationService, IOptionsService } from 'common/services/Services';
|
|
6
6
|
import { ICellData } from 'common/Types';
|
|
7
7
|
import { Terminal } from '@xterm/xterm';
|
|
8
8
|
|
|
@@ -13,6 +13,7 @@ let $hasFg = false;
|
|
|
13
13
|
let $hasBg = false;
|
|
14
14
|
let $isSelected = false;
|
|
15
15
|
let $colors: ReadonlyColorSet | undefined;
|
|
16
|
+
let $variantOffset = 0;
|
|
16
17
|
|
|
17
18
|
export class CellColorResolver {
|
|
18
19
|
/**
|
|
@@ -27,6 +28,7 @@ export class CellColorResolver {
|
|
|
27
28
|
|
|
28
29
|
constructor(
|
|
29
30
|
private readonly _terminal: Terminal,
|
|
31
|
+
private readonly _optionService: IOptionsService,
|
|
30
32
|
private readonly _selectionRenderModel: ISelectionRenderModel,
|
|
31
33
|
private readonly _decorationService: IDecorationService,
|
|
32
34
|
private readonly _coreBrowserService: ICoreBrowserService,
|
|
@@ -38,7 +40,7 @@ export class CellColorResolver {
|
|
|
38
40
|
* Resolves colors for the cell, putting the result into the shared {@link result}. This resolves
|
|
39
41
|
* overrides, inverse and selection for the cell which can then be used to feed into the renderer.
|
|
40
42
|
*/
|
|
41
|
-
public resolve(cell: ICellData, x: number, y: number): void {
|
|
43
|
+
public resolve(cell: ICellData, x: number, y: number, deviceCellWidth: number): void {
|
|
42
44
|
this.result.bg = cell.bg;
|
|
43
45
|
this.result.fg = cell.fg;
|
|
44
46
|
this.result.ext = cell.bg & BgFlags.HAS_EXTENDED ? cell.extended.ext : 0;
|
|
@@ -52,6 +54,13 @@ export class CellColorResolver {
|
|
|
52
54
|
$hasFg = false;
|
|
53
55
|
$isSelected = false;
|
|
54
56
|
$colors = this._themeService.colors;
|
|
57
|
+
$variantOffset = 0;
|
|
58
|
+
|
|
59
|
+
const code = cell.getCode();
|
|
60
|
+
if (code !== NULL_CELL_CODE && cell.extended.underlineStyle === UnderlineStyle.DOTTED) {
|
|
61
|
+
const lineWidth = Math.max(1, Math.floor(this._optionService.rawOptions.fontSize * this._coreBrowserService.dpr / 15));
|
|
62
|
+
$variantOffset = x * deviceCellWidth % (Math.round(lineWidth) * 2);
|
|
63
|
+
}
|
|
55
64
|
|
|
56
65
|
// Apply decorations on the bottom layer
|
|
57
66
|
this._decorationService.forEachDecorationAtCell(x, y, 'bottom', d => {
|
|
@@ -133,5 +142,9 @@ export class CellColorResolver {
|
|
|
133
142
|
// Use the override if it exists
|
|
134
143
|
this.result.bg = $hasBg ? $bg : this.result.bg;
|
|
135
144
|
this.result.fg = $hasFg ? $fg : this.result.fg;
|
|
145
|
+
|
|
146
|
+
// Reset overrides variantOffset
|
|
147
|
+
this.result.ext &= ~ExtFlags.VARIANT_OFFSET;
|
|
148
|
+
this.result.ext |= ($variantOffset << 29) & ExtFlags.VARIANT_OFFSET;
|
|
136
149
|
}
|
|
137
150
|
}
|
|
@@ -56,3 +56,7 @@ function createDimension(): IDimensions {
|
|
|
56
56
|
height: 0
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
|
+
|
|
60
|
+
export function computeNextVariantOffset(cellWidth: number, lineWidth: number, currentOffset: number = 0): number {
|
|
61
|
+
return (cellWidth - (Math.round(lineWidth) * 2 - currentOffset)) % (Math.round(lineWidth) * 2);
|
|
62
|
+
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* @license MIT
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { ITerminal } from 'browser/Types';
|
|
6
7
|
import { ISelectionRenderModel } from 'browser/renderer/shared/Types';
|
|
7
8
|
import { Terminal } from '@xterm/xterm';
|
|
8
9
|
|
|
@@ -35,7 +36,7 @@ class SelectionRenderModel implements ISelectionRenderModel {
|
|
|
35
36
|
this.selectionEnd = undefined;
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
public update(terminal:
|
|
39
|
+
public update(terminal: ITerminal, start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean = false): void {
|
|
39
40
|
this.selectionStart = start;
|
|
40
41
|
this.selectionEnd = end;
|
|
41
42
|
// Selection does not exist
|
|
@@ -45,8 +46,9 @@ class SelectionRenderModel implements ISelectionRenderModel {
|
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
// Translate from buffer position to viewport position
|
|
48
|
-
const
|
|
49
|
-
const
|
|
49
|
+
const viewportY = terminal.buffers.active.ydisp;
|
|
50
|
+
const viewportStartRow = start[1] - viewportY;
|
|
51
|
+
const viewportEndRow = end[1] - viewportY;
|
|
50
52
|
const viewportCappedStartRow = Math.max(viewportStartRow, 0);
|
|
51
53
|
const viewportCappedEndRow = Math.min(viewportEndRow, terminal.rows - 1);
|
|
52
54
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { IColorContrastCache } from 'browser/Types';
|
|
7
7
|
import { DIM_OPACITY, TEXT_BASELINE } from 'browser/renderer/shared/Constants';
|
|
8
8
|
import { tryDrawCustomChar } from 'browser/renderer/shared/CustomGlyphs';
|
|
9
|
-
import { excludeFromContrastRatioDemands, isPowerlineGlyph, isRestrictedPowerlineGlyph, throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
|
|
9
|
+
import { computeNextVariantOffset, excludeFromContrastRatioDemands, isPowerlineGlyph, isRestrictedPowerlineGlyph, throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
|
|
10
10
|
import { IBoundingBox, ICharAtlasConfig, IRasterizedGlyph, ITextureAtlas } from 'browser/renderer/shared/Types';
|
|
11
11
|
import { NULL_COLOR, color, rgba } from 'common/Color';
|
|
12
12
|
import { EventEmitter } from 'common/EventEmitter';
|
|
@@ -545,6 +545,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
545
545
|
const yTop = Math.ceil(padding + this._config.deviceCharHeight) - yOffset - (restrictToCellHeight ? lineWidth * 2 : 0);
|
|
546
546
|
const yMid = yTop + lineWidth;
|
|
547
547
|
const yBot = yTop + lineWidth * 2;
|
|
548
|
+
let nextOffset = this._workAttributeData.getUnderlineVariantOffset();
|
|
548
549
|
|
|
549
550
|
for (let i = 0; i < chWidth; i++) {
|
|
550
551
|
this._tmpCtx.save();
|
|
@@ -594,9 +595,22 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
594
595
|
);
|
|
595
596
|
break;
|
|
596
597
|
case UnderlineStyle.DOTTED:
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
598
|
+
const offsetWidth = nextOffset === 0 ? 0 :
|
|
599
|
+
(nextOffset >= lineWidth ? lineWidth * 2 - nextOffset : lineWidth - nextOffset);
|
|
600
|
+
// a line and a gap.
|
|
601
|
+
const isLineStart = nextOffset >= lineWidth ? false : true;
|
|
602
|
+
if (isLineStart === false || offsetWidth === 0) {
|
|
603
|
+
this._tmpCtx.setLineDash([Math.round(lineWidth), Math.round(lineWidth)]);
|
|
604
|
+
this._tmpCtx.moveTo(xChLeft + offsetWidth, yTop);
|
|
605
|
+
this._tmpCtx.lineTo(xChRight, yTop);
|
|
606
|
+
} else {
|
|
607
|
+
this._tmpCtx.setLineDash([Math.round(lineWidth), Math.round(lineWidth)]);
|
|
608
|
+
this._tmpCtx.moveTo(xChLeft, yTop);
|
|
609
|
+
this._tmpCtx.lineTo(xChLeft + offsetWidth, yTop);
|
|
610
|
+
this._tmpCtx.moveTo(xChLeft + offsetWidth + lineWidth, yTop);
|
|
611
|
+
this._tmpCtx.lineTo(xChRight, yTop);
|
|
612
|
+
}
|
|
613
|
+
nextOffset = computeNextVariantOffset(xChRight - xChLeft, lineWidth, nextOffset);
|
|
600
614
|
break;
|
|
601
615
|
case UnderlineStyle.DASHED:
|
|
602
616
|
this._tmpCtx.setLineDash([this._config.devicePixelRatio * 4, this._config.devicePixelRatio * 3]);
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { FontWeight, Terminal } from '@xterm/xterm';
|
|
7
|
-
import { IColorSet } from 'browser/Types';
|
|
7
|
+
import { IColorSet, ITerminal } from 'browser/Types';
|
|
8
8
|
import { IDisposable } from 'common/Types';
|
|
9
9
|
import { IEvent } from 'common/EventEmitter';
|
|
10
10
|
|
|
@@ -168,6 +168,6 @@ export interface ISelectionRenderModel {
|
|
|
168
168
|
readonly selectionStart: [number, number] | undefined;
|
|
169
169
|
readonly selectionEnd: [number, number] | undefined;
|
|
170
170
|
clear(): void;
|
|
171
|
-
update(terminal:
|
|
171
|
+
update(terminal: ITerminal, start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode?: boolean): void;
|
|
172
172
|
isCellSelected(terminal: Terminal, x: number, y: number): boolean;
|
|
173
173
|
}
|
package/src/common/Types.d.ts
CHANGED
|
@@ -119,6 +119,7 @@ export interface IExtendedAttrs {
|
|
|
119
119
|
ext: number;
|
|
120
120
|
underlineStyle: UnderlineStyle;
|
|
121
121
|
underlineColor: number;
|
|
122
|
+
underlineVariantOffset: number;
|
|
122
123
|
urlId: number;
|
|
123
124
|
clone(): IExtendedAttrs;
|
|
124
125
|
isEmpty(): boolean;
|
|
@@ -209,6 +210,7 @@ export interface IAttributeData {
|
|
|
209
210
|
isUnderlineColorPalette(): boolean;
|
|
210
211
|
isUnderlineColorDefault(): boolean;
|
|
211
212
|
getUnderlineStyle(): number;
|
|
213
|
+
getUnderlineVariantOffset(): number;
|
|
212
214
|
}
|
|
213
215
|
|
|
214
216
|
/** Cell data */
|
|
@@ -126,6 +126,9 @@ export class AttributeData implements IAttributeData {
|
|
|
126
126
|
? (this.bg & BgFlags.HAS_EXTENDED ? this.extended.underlineStyle : UnderlineStyle.SINGLE)
|
|
127
127
|
: UnderlineStyle.NONE;
|
|
128
128
|
}
|
|
129
|
+
public getUnderlineVariantOffset(): number {
|
|
130
|
+
return this.extended.underlineVariantOffset;
|
|
131
|
+
}
|
|
129
132
|
}
|
|
130
133
|
|
|
131
134
|
|
|
@@ -174,6 +177,18 @@ export class ExtendedAttrs implements IExtendedAttrs {
|
|
|
174
177
|
this._urlId = value;
|
|
175
178
|
}
|
|
176
179
|
|
|
180
|
+
public get underlineVariantOffset(): number {
|
|
181
|
+
const val = (this._ext & ExtFlags.VARIANT_OFFSET) >> 29;
|
|
182
|
+
if (val < 0) {
|
|
183
|
+
return val ^ 0xFFFFFFF8;
|
|
184
|
+
}
|
|
185
|
+
return val;
|
|
186
|
+
}
|
|
187
|
+
public set underlineVariantOffset(value: number) {
|
|
188
|
+
this._ext &= ~ExtFlags.VARIANT_OFFSET;
|
|
189
|
+
this._ext |= (value << 29) & ExtFlags.VARIANT_OFFSET;
|
|
190
|
+
}
|
|
191
|
+
|
|
177
192
|
constructor(
|
|
178
193
|
ext: number = 0,
|
|
179
194
|
urlId: number = 0
|
|
@@ -134,9 +134,17 @@ export const enum BgFlags {
|
|
|
134
134
|
|
|
135
135
|
export const enum ExtFlags {
|
|
136
136
|
/**
|
|
137
|
-
* bit 27..
|
|
137
|
+
* bit 27..29
|
|
138
138
|
*/
|
|
139
|
-
UNDERLINE_STYLE = 0x1C000000
|
|
139
|
+
UNDERLINE_STYLE = 0x1C000000,
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* bit 30..32
|
|
143
|
+
*
|
|
144
|
+
* An optional variant for the glyph, this can be used for example to offset underlines by a
|
|
145
|
+
* number of pixels to create a perfect pattern.
|
|
146
|
+
*/
|
|
147
|
+
VARIANT_OFFSET = 0xE0000000
|
|
140
148
|
}
|
|
141
149
|
|
|
142
150
|
export const enum UnderlineStyle {
|