@xterm/xterm 5.4.0-beta.22 → 5.4.0-beta.24
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/services/CharSizeService.ts +53 -28
- package/typings/xterm.d.ts +2 -2
package/package.json
CHANGED
|
@@ -8,12 +8,6 @@ import { EventEmitter } from 'common/EventEmitter';
|
|
|
8
8
|
import { ICharSizeService } from 'browser/services/Services';
|
|
9
9
|
import { Disposable } from 'common/Lifecycle';
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
const enum MeasureSettings {
|
|
13
|
-
REPEAT = 32
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
11
|
export class CharSizeService extends Disposable implements ICharSizeService {
|
|
18
12
|
public serviceBrand: undefined;
|
|
19
13
|
|
|
@@ -32,7 +26,11 @@ export class CharSizeService extends Disposable implements ICharSizeService {
|
|
|
32
26
|
@IOptionsService private readonly _optionsService: IOptionsService
|
|
33
27
|
) {
|
|
34
28
|
super();
|
|
35
|
-
|
|
29
|
+
try {
|
|
30
|
+
this._measureStrategy = this.register(new TextMetricsMeasureStrategy(this._optionsService));
|
|
31
|
+
} catch {
|
|
32
|
+
this._measureStrategy = this.register(new DomMeasureStrategy(document, parentElement, this._optionsService));
|
|
33
|
+
}
|
|
36
34
|
this.register(this._optionsService.onMultipleOptionChange(['fontFamily', 'fontSize'], () => this.measure()));
|
|
37
35
|
}
|
|
38
36
|
|
|
@@ -47,12 +45,7 @@ export class CharSizeService extends Disposable implements ICharSizeService {
|
|
|
47
45
|
}
|
|
48
46
|
|
|
49
47
|
interface IMeasureStrategy {
|
|
50
|
-
measure():
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
interface IReadonlyMeasureResult {
|
|
54
|
-
readonly width: number;
|
|
55
|
-
readonly height: number;
|
|
48
|
+
measure(): Readonly<IMeasureResult>;
|
|
56
49
|
}
|
|
57
50
|
|
|
58
51
|
interface IMeasureResult {
|
|
@@ -60,10 +53,26 @@ interface IMeasureResult {
|
|
|
60
53
|
height: number;
|
|
61
54
|
}
|
|
62
55
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
56
|
+
const enum DomMeasureStrategyConstants {
|
|
57
|
+
REPEAT = 32
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
abstract class BaseMeasureStategy extends Disposable implements IMeasureStrategy {
|
|
61
|
+
protected _result: IMeasureResult = { width: 0, height: 0 };
|
|
62
|
+
|
|
63
|
+
protected _validateAndSet(width: number | undefined, height: number | undefined): void {
|
|
64
|
+
// If values are 0 then the element is likely currently display:none, in which case we should
|
|
65
|
+
// retain the previous value.
|
|
66
|
+
if (width !== undefined && width > 0 && height !== undefined && height > 0) {
|
|
67
|
+
this._result.width = width;
|
|
68
|
+
this._result.height = height;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public abstract measure(): Readonly<IMeasureResult>;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
class DomMeasureStrategy extends BaseMeasureStategy {
|
|
67
76
|
private _measureElement: HTMLElement;
|
|
68
77
|
|
|
69
78
|
constructor(
|
|
@@ -71,32 +80,48 @@ class DomMeasureStrategy implements IMeasureStrategy {
|
|
|
71
80
|
private _parentElement: HTMLElement,
|
|
72
81
|
private _optionsService: IOptionsService
|
|
73
82
|
) {
|
|
83
|
+
super();
|
|
74
84
|
this._measureElement = this._document.createElement('span');
|
|
75
85
|
this._measureElement.classList.add('xterm-char-measure-element');
|
|
76
|
-
this._measureElement.textContent = 'W'.repeat(
|
|
86
|
+
this._measureElement.textContent = 'W'.repeat(DomMeasureStrategyConstants.REPEAT);
|
|
77
87
|
this._measureElement.setAttribute('aria-hidden', 'true');
|
|
78
88
|
this._measureElement.style.whiteSpace = 'pre';
|
|
79
89
|
this._measureElement.style.fontKerning = 'none';
|
|
80
90
|
this._parentElement.appendChild(this._measureElement);
|
|
81
91
|
}
|
|
82
92
|
|
|
83
|
-
public measure():
|
|
93
|
+
public measure(): Readonly<IMeasureResult> {
|
|
84
94
|
this._measureElement.style.fontFamily = this._optionsService.rawOptions.fontFamily;
|
|
85
95
|
this._measureElement.style.fontSize = `${this._optionsService.rawOptions.fontSize}px`;
|
|
86
96
|
|
|
87
97
|
// Note that this triggers a synchronous layout
|
|
88
|
-
|
|
89
|
-
height: Number(this._measureElement.offsetHeight),
|
|
90
|
-
width: Number(this._measureElement.offsetWidth)
|
|
91
|
-
};
|
|
98
|
+
this._validateAndSet(Number(this._measureElement.offsetWidth) / DomMeasureStrategyConstants.REPEAT, Number(this._measureElement.offsetHeight));
|
|
92
99
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
100
|
+
return this._result;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
class TextMetricsMeasureStrategy extends BaseMeasureStategy {
|
|
105
|
+
private _canvas: OffscreenCanvas;
|
|
106
|
+
private _ctx: OffscreenCanvasRenderingContext2D;
|
|
107
|
+
|
|
108
|
+
constructor(
|
|
109
|
+
private _optionsService: IOptionsService
|
|
110
|
+
) {
|
|
111
|
+
super();
|
|
112
|
+
// This will throw if any required API is not supported
|
|
113
|
+
this._canvas = new OffscreenCanvas(100, 100);
|
|
114
|
+
this._ctx = this._canvas.getContext('2d')!;
|
|
115
|
+
const a = this._ctx.measureText('W');
|
|
116
|
+
if (!('width' in a && 'fontBoundingBoxAscent' in a && 'fontBoundingBoxDescent' in a)) {
|
|
117
|
+
throw new Error('Required font metrics not supported');
|
|
98
118
|
}
|
|
119
|
+
}
|
|
99
120
|
|
|
121
|
+
public measure(): Readonly<IMeasureResult> {
|
|
122
|
+
this._ctx.font = `${this._optionsService.rawOptions.fontSize}px ${this._optionsService.rawOptions.fontFamily}`;
|
|
123
|
+
const metrics = this._ctx.measureText('W');
|
|
124
|
+
this._validateAndSet(metrics.width, metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent);
|
|
100
125
|
return this._result;
|
|
101
126
|
}
|
|
102
127
|
}
|
package/typings/xterm.d.ts
CHANGED
|
@@ -1014,7 +1014,7 @@ declare module '@xterm/xterm' {
|
|
|
1014
1014
|
* Attaches a custom wheel event handler which is run before keys are
|
|
1015
1015
|
* processed, giving consumers of xterm.js control over whether to proceed
|
|
1016
1016
|
* or cancel terminal wheel events.
|
|
1017
|
-
* @param
|
|
1017
|
+
* @param customWheelEventHandler The custom WheelEvent handler to attach.
|
|
1018
1018
|
* This is a function that takes a WheelEvent, allowing consumers to stop
|
|
1019
1019
|
* propagation and/or prevent the default action. The function returns
|
|
1020
1020
|
* whether the event should be processed by xterm.js.
|
|
@@ -1022,7 +1022,7 @@ declare module '@xterm/xterm' {
|
|
|
1022
1022
|
* @example A handler that prevents all wheel events while ctrl is held from
|
|
1023
1023
|
* being processed.
|
|
1024
1024
|
* ```ts
|
|
1025
|
-
* term.
|
|
1025
|
+
* term.attachCustomWheelEventHandler(ev => {
|
|
1026
1026
|
* if (ev.ctrlKey) {
|
|
1027
1027
|
* return false;
|
|
1028
1028
|
* }
|