@xterm/xterm 5.4.0-beta.3 → 5.4.0-beta.30

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.
Files changed (32) hide show
  1. package/css/xterm.css +10 -1
  2. package/lib/xterm.js +1 -1
  3. package/lib/xterm.js.map +1 -1
  4. package/package.json +3 -3
  5. package/src/browser/AccessibilityManager.ts +132 -3
  6. package/src/browser/{Linkifier2.ts → Linkifier.ts} +36 -61
  7. package/src/browser/OscLinkProvider.ts +2 -1
  8. package/src/browser/RenderDebouncer.ts +6 -5
  9. package/src/browser/Terminal.ts +41 -33
  10. package/src/browser/Types.d.ts +2 -9
  11. package/src/browser/public/Terminal.ts +3 -0
  12. package/src/browser/renderer/dom/DomRenderer.ts +20 -9
  13. package/src/browser/renderer/dom/DomRendererRowFactory.ts +5 -5
  14. package/src/browser/renderer/shared/CellColorResolver.ts +110 -11
  15. package/src/browser/renderer/shared/RendererUtils.ts +5 -1
  16. package/src/browser/renderer/shared/SelectionRenderModel.ts +5 -3
  17. package/src/browser/renderer/shared/TextureAtlas.ts +31 -13
  18. package/src/browser/renderer/shared/Types.d.ts +2 -2
  19. package/src/browser/services/CharSizeService.ts +53 -28
  20. package/src/browser/services/LinkProviderService.ts +28 -0
  21. package/src/browser/services/RenderService.ts +13 -8
  22. package/src/browser/services/Services.ts +12 -1
  23. package/src/common/Color.ts +28 -12
  24. package/src/common/CoreTerminal.ts +1 -0
  25. package/src/common/InputHandler.ts +15 -19
  26. package/src/common/Types.d.ts +9 -7
  27. package/src/common/buffer/AttributeData.ts +15 -0
  28. package/src/common/buffer/BufferLine.ts +47 -20
  29. package/src/common/buffer/Constants.ts +10 -2
  30. package/src/common/input/Keyboard.ts +2 -3
  31. package/src/common/services/OptionsService.ts +8 -1
  32. package/typings/xterm.d.ts +22 -0
@@ -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
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { CharData, IAttributeData, IBufferLine, ICellData, IExtendedAttrs } from 'common/Types';
7
- import { AttributeData, ExtendedAttrs } from 'common/buffer/AttributeData';
7
+ import { AttributeData } from 'common/buffer/AttributeData';
8
8
  import { CellData } from 'common/buffer/CellData';
9
9
  import { Attributes, BgFlags, CHAR_DATA_ATTR_INDEX, CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, Content, NULL_CELL_CHAR, NULL_CELL_CODE, NULL_CELL_WIDTH, WHITESPACE_CELL_CHAR } from 'common/buffer/Constants';
10
10
  import { stringFromCodePoint } from 'common/input/TextDecoder';
@@ -212,13 +212,13 @@ export class BufferLine implements IBufferLine {
212
212
  * Since the input handler see the incoming chars as UTF32 codepoints,
213
213
  * it gets an optimized access method.
214
214
  */
215
- public setCellFromCodePoint(index: number, codePoint: number, width: number, fg: number, bg: number, eAttrs: IExtendedAttrs): void {
216
- if (bg & BgFlags.HAS_EXTENDED) {
217
- this._extendedAttrs[index] = eAttrs;
215
+ public setCellFromCodepoint(index: number, codePoint: number, width: number, attrs: IAttributeData): void {
216
+ if (attrs.bg & BgFlags.HAS_EXTENDED) {
217
+ this._extendedAttrs[index] = attrs.extended;
218
218
  }
219
219
  this._data[index * CELL_SIZE + Cell.CONTENT] = codePoint | (width << Content.WIDTH_SHIFT);
220
- this._data[index * CELL_SIZE + Cell.FG] = fg;
221
- this._data[index * CELL_SIZE + Cell.BG] = bg;
220
+ this._data[index * CELL_SIZE + Cell.FG] = attrs.fg;
221
+ this._data[index * CELL_SIZE + Cell.BG] = attrs.bg;
222
222
  }
223
223
 
224
224
  /**
@@ -253,12 +253,12 @@ export class BufferLine implements IBufferLine {
253
253
  this._data[index * CELL_SIZE + Cell.CONTENT] = content;
254
254
  }
255
255
 
256
- public insertCells(pos: number, n: number, fillCellData: ICellData, eraseAttr?: IAttributeData): void {
256
+ public insertCells(pos: number, n: number, fillCellData: ICellData): void {
257
257
  pos %= this.length;
258
258
 
259
259
  // handle fullwidth at pos: reset cell one to the left if pos is second cell of a wide char
260
260
  if (pos && this.getWidth(pos - 1) === 2) {
261
- this.setCellFromCodePoint(pos - 1, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs());
261
+ this.setCellFromCodepoint(pos - 1, 0, 1, fillCellData);
262
262
  }
263
263
 
264
264
  if (n < this.length - pos) {
@@ -277,11 +277,11 @@ export class BufferLine implements IBufferLine {
277
277
 
278
278
  // handle fullwidth at line end: reset last cell if it is first cell of a wide char
279
279
  if (this.getWidth(this.length - 1) === 2) {
280
- this.setCellFromCodePoint(this.length - 1, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs());
280
+ this.setCellFromCodepoint(this.length - 1, 0, 1, fillCellData);
281
281
  }
282
282
  }
283
283
 
284
- public deleteCells(pos: number, n: number, fillCellData: ICellData, eraseAttr?: IAttributeData): void {
284
+ public deleteCells(pos: number, n: number, fillCellData: ICellData): void {
285
285
  pos %= this.length;
286
286
  if (n < this.length - pos) {
287
287
  const cell = new CellData();
@@ -301,21 +301,21 @@ export class BufferLine implements IBufferLine {
301
301
  // - reset pos-1 if wide char
302
302
  // - reset pos if width==0 (previous second cell of a wide char)
303
303
  if (pos && this.getWidth(pos - 1) === 2) {
304
- this.setCellFromCodePoint(pos - 1, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs());
304
+ this.setCellFromCodepoint(pos - 1, 0, 1, fillCellData);
305
305
  }
306
306
  if (this.getWidth(pos) === 0 && !this.hasContent(pos)) {
307
- this.setCellFromCodePoint(pos, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs());
307
+ this.setCellFromCodepoint(pos, 0, 1, fillCellData);
308
308
  }
309
309
  }
310
310
 
311
- public replaceCells(start: number, end: number, fillCellData: ICellData, eraseAttr?: IAttributeData, respectProtect: boolean = false): void {
311
+ public replaceCells(start: number, end: number, fillCellData: ICellData, respectProtect: boolean = false): void {
312
312
  // full branching on respectProtect==true, hopefully getting fast JIT for standard case
313
313
  if (respectProtect) {
314
314
  if (start && this.getWidth(start - 1) === 2 && !this.isProtected(start - 1)) {
315
- this.setCellFromCodePoint(start - 1, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs());
315
+ this.setCellFromCodepoint(start - 1, 0, 1, fillCellData);
316
316
  }
317
317
  if (end < this.length && this.getWidth(end - 1) === 2 && !this.isProtected(end)) {
318
- this.setCellFromCodePoint(end, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs());
318
+ this.setCellFromCodepoint(end, 0, 1, fillCellData);
319
319
  }
320
320
  while (start < end && start < this.length) {
321
321
  if (!this.isProtected(start)) {
@@ -328,11 +328,11 @@ export class BufferLine implements IBufferLine {
328
328
 
329
329
  // handle fullwidth at start: reset cell one to the left if start is second cell of a wide char
330
330
  if (start && this.getWidth(start - 1) === 2) {
331
- this.setCellFromCodePoint(start - 1, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs());
331
+ this.setCellFromCodepoint(start - 1, 0, 1, fillCellData);
332
332
  }
333
333
  // handle fullwidth at last cell + 1: reset to empty cell if it is second part of a wide char
334
334
  if (end < this.length && this.getWidth(end - 1) === 2) {
335
- this.setCellFromCodePoint(end, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs());
335
+ this.setCellFromCodepoint(end, 0, 1, fillCellData);
336
336
  }
337
337
 
338
338
  while (start < end && start < this.length) {
@@ -508,16 +508,43 @@ export class BufferLine implements IBufferLine {
508
508
  }
509
509
  }
510
510
 
511
- public translateToString(trimRight: boolean = false, startCol: number = 0, endCol: number = this.length): string {
511
+ /**
512
+ * Translates the buffer line to a string.
513
+ *
514
+ * @param trimRight Whether to trim any empty cells on the right.
515
+ * @param startCol The column to start the string (0-based inclusive).
516
+ * @param endCol The column to end the string (0-based exclusive).
517
+ * @param outColumns if specified, this array will be filled with column numbers such that
518
+ * `returnedString[i]` is displayed at `outColumns[i]` column. `outColumns[returnedString.length]`
519
+ * is where the character following `returnedString` will be displayed.
520
+ *
521
+ * When a single cell is translated to multiple UTF-16 code units (e.g. surrogate pair) in the
522
+ * returned string, the corresponding entries in `outColumns` will have the same column number.
523
+ */
524
+ public translateToString(trimRight?: boolean, startCol?: number, endCol?: number, outColumns?: number[]): string {
525
+ startCol = startCol ?? 0;
526
+ endCol = endCol ?? this.length;
512
527
  if (trimRight) {
513
528
  endCol = Math.min(endCol, this.getTrimmedLength());
514
529
  }
530
+ if (outColumns) {
531
+ outColumns.length = 0;
532
+ }
515
533
  let result = '';
516
534
  while (startCol < endCol) {
517
535
  const content = this._data[startCol * CELL_SIZE + Cell.CONTENT];
518
536
  const cp = content & Content.CODEPOINT_MASK;
519
- result += (content & Content.IS_COMBINED_MASK) ? this._combined[startCol] : (cp) ? stringFromCodePoint(cp) : WHITESPACE_CELL_CHAR;
520
- startCol += (content >> Content.WIDTH_SHIFT) || 1; // always advance by 1
537
+ const chars = (content & Content.IS_COMBINED_MASK) ? this._combined[startCol] : (cp) ? stringFromCodePoint(cp) : WHITESPACE_CELL_CHAR;
538
+ result += chars;
539
+ if (outColumns) {
540
+ for (let i = 0; i < chars.length; ++i) {
541
+ outColumns.push(startCol);
542
+ }
543
+ }
544
+ startCol += (content >> Content.WIDTH_SHIFT) || 1; // always advance by at least 1
545
+ }
546
+ if (outColumns) {
547
+ outColumns.push(startCol);
521
548
  }
522
549
  return result;
523
550
  }
@@ -134,9 +134,17 @@ export const enum BgFlags {
134
134
 
135
135
  export const enum ExtFlags {
136
136
  /**
137
- * bit 27..32 (upper 3 unused)
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 {
@@ -83,11 +83,10 @@ export function evaluateKeyboardEvent(
83
83
  break;
84
84
  case 8:
85
85
  // backspace
86
+ result.key = ev.ctrlKey ? '\b' : C0.DEL; // ^H or ^?
86
87
  if (ev.altKey) {
87
- result.key = C0.ESC + C0.DEL; // \e ^?
88
- break;
88
+ result.key = C0.ESC + result.key;
89
89
  }
90
- result.key = C0.DEL; // ^?
91
90
  break;
92
91
  case 9:
93
92
  // tab
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { EventEmitter } from 'common/EventEmitter';
7
- import { Disposable } from 'common/Lifecycle';
7
+ import { Disposable, toDisposable } from 'common/Lifecycle';
8
8
  import { isMac } from 'common/Platform';
9
9
  import { CursorStyle, IDisposable } from 'common/Types';
10
10
  import { FontWeight, IOptionsService, ITerminalOptions } from 'common/services/Services';
@@ -86,6 +86,13 @@ export class OptionsService extends Disposable implements IOptionsService {
86
86
  this.rawOptions = defaultOptions;
87
87
  this.options = { ... defaultOptions };
88
88
  this._setupOptions();
89
+
90
+ // Clear out options that could link outside xterm.js as they could easily cause an embedder
91
+ // memory leak
92
+ this.register(toDisposable(() => {
93
+ this.rawOptions.linkHandler = null;
94
+ this.rawOptions.documentOverride = null;
95
+ }));
89
96
  }
90
97
 
91
98
  // eslint-disable-next-line @typescript-eslint/naming-convention
@@ -1010,6 +1010,28 @@ declare module '@xterm/xterm' {
1010
1010
  */
1011
1011
  attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void;
1012
1012
 
1013
+ /**
1014
+ * Attaches a custom wheel event handler which is run before keys are
1015
+ * processed, giving consumers of xterm.js control over whether to proceed
1016
+ * or cancel terminal wheel events.
1017
+ * @param customWheelEventHandler The custom WheelEvent handler to attach.
1018
+ * This is a function that takes a WheelEvent, allowing consumers to stop
1019
+ * propagation and/or prevent the default action. The function returns
1020
+ * whether the event should be processed by xterm.js.
1021
+ *
1022
+ * @example A handler that prevents all wheel events while ctrl is held from
1023
+ * being processed.
1024
+ * ```ts
1025
+ * term.attachCustomWheelEventHandler(ev => {
1026
+ * if (ev.ctrlKey) {
1027
+ * return false;
1028
+ * }
1029
+ * return true;
1030
+ * });
1031
+ * ```
1032
+ */
1033
+ attachCustomWheelEventHandler(customWheelEventHandler: (event: WheelEvent) => boolean): void;
1034
+
1013
1035
  /**
1014
1036
  * Registers a link provider, allowing a custom parser to be used to match
1015
1037
  * and handle links. Multiple link providers can be used, they will be asked