@xterm/xterm 6.1.0-beta.24 → 6.1.0-beta.240

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 (162) hide show
  1. package/README.md +62 -38
  2. package/css/xterm.css +29 -22
  3. package/lib/xterm.js +1 -1
  4. package/lib/xterm.js.map +1 -1
  5. package/lib/xterm.mjs +8 -34
  6. package/lib/xterm.mjs.map +4 -4
  7. package/package.json +25 -22
  8. package/src/browser/AccessibilityManager.ts +11 -6
  9. package/src/browser/Clipboard.ts +6 -3
  10. package/src/browser/CoreBrowserTerminal.ts +149 -319
  11. package/src/browser/Dom.ts +178 -0
  12. package/src/browser/Linkifier.ts +11 -11
  13. package/src/browser/OscLinkProvider.ts +82 -14
  14. package/src/browser/RenderDebouncer.ts +2 -2
  15. package/src/browser/TimeBasedDebouncer.ts +2 -2
  16. package/src/browser/Types.ts +12 -11
  17. package/src/browser/Viewport.ts +55 -20
  18. package/src/browser/decorations/BufferDecorationRenderer.ts +1 -1
  19. package/src/browser/decorations/OverviewRulerRenderer.ts +33 -17
  20. package/src/browser/input/CompositionHelper.ts +44 -8
  21. package/src/browser/public/Terminal.ts +25 -28
  22. package/src/browser/renderer/dom/DomRenderer.ts +242 -76
  23. package/src/browser/renderer/dom/DomRendererRowFactory.ts +19 -13
  24. package/src/browser/renderer/dom/WidthCache.ts +54 -52
  25. package/src/browser/renderer/shared/Constants.ts +7 -0
  26. package/src/browser/renderer/shared/TextBlinkStateManager.ts +97 -0
  27. package/src/browser/renderer/shared/Types.ts +8 -2
  28. package/src/browser/scrollable/abstractScrollbar.ts +300 -0
  29. package/src/browser/scrollable/fastDomNode.ts +126 -0
  30. package/src/browser/scrollable/globalPointerMoveMonitor.ts +90 -0
  31. package/src/browser/scrollable/horizontalScrollbar.ts +85 -0
  32. package/src/browser/scrollable/mouseEvent.ts +292 -0
  33. package/src/browser/scrollable/scrollable.ts +486 -0
  34. package/src/browser/scrollable/scrollableElement.ts +581 -0
  35. package/src/browser/scrollable/scrollableElementOptions.ts +161 -0
  36. package/src/browser/scrollable/scrollbarArrow.ts +110 -0
  37. package/src/browser/scrollable/scrollbarState.ts +246 -0
  38. package/src/browser/scrollable/scrollbarVisibilityController.ts +113 -0
  39. package/src/browser/scrollable/touch.ts +485 -0
  40. package/src/browser/scrollable/verticalScrollbar.ts +143 -0
  41. package/src/browser/scrollable/widget.ts +23 -0
  42. package/src/browser/services/CharSizeService.ts +2 -2
  43. package/src/browser/services/CoreBrowserService.ts +7 -5
  44. package/src/browser/services/KeyboardService.ts +67 -0
  45. package/src/browser/services/LinkProviderService.ts +1 -1
  46. package/src/browser/services/MouseCoordsService.ts +47 -0
  47. package/src/browser/services/MouseService.ts +518 -25
  48. package/src/browser/services/RenderService.ts +28 -16
  49. package/src/browser/services/SelectionService.ts +45 -39
  50. package/src/browser/services/Services.ts +40 -17
  51. package/src/browser/services/ThemeService.ts +2 -2
  52. package/src/common/Async.ts +141 -0
  53. package/src/common/CircularList.ts +2 -2
  54. package/src/common/Color.ts +8 -0
  55. package/src/common/CoreTerminal.ts +31 -21
  56. package/src/common/Event.ts +118 -0
  57. package/src/common/InputHandler.ts +283 -85
  58. package/src/common/Lifecycle.ts +113 -0
  59. package/src/common/Platform.ts +13 -3
  60. package/src/common/SortedList.ts +7 -3
  61. package/src/common/StringBuilder.ts +67 -0
  62. package/src/common/TaskQueue.ts +14 -5
  63. package/src/common/Types.ts +51 -31
  64. package/src/common/Version.ts +9 -0
  65. package/src/common/buffer/Buffer.ts +34 -19
  66. package/src/common/buffer/BufferLine.ts +133 -65
  67. package/src/common/buffer/BufferLineStringCache.ts +69 -0
  68. package/src/common/buffer/BufferSet.ts +11 -6
  69. package/src/common/buffer/CellData.ts +57 -0
  70. package/src/common/buffer/Marker.ts +2 -2
  71. package/src/common/buffer/Types.ts +6 -2
  72. package/src/common/data/EscapeSequences.ts +71 -70
  73. package/src/common/input/Keyboard.ts +14 -7
  74. package/src/common/input/KittyKeyboard.ts +526 -0
  75. package/src/common/input/Win32InputMode.ts +297 -0
  76. package/src/common/input/WriteBuffer.ts +69 -32
  77. package/src/common/input/XParseColor.ts +2 -2
  78. package/src/common/parser/ApcParser.ts +196 -0
  79. package/src/common/parser/Constants.ts +14 -4
  80. package/src/common/parser/DcsParser.ts +11 -12
  81. package/src/common/parser/EscapeSequenceParser.ts +205 -63
  82. package/src/common/parser/OscParser.ts +11 -12
  83. package/src/common/parser/Params.ts +27 -8
  84. package/src/common/parser/Types.ts +36 -2
  85. package/src/common/public/BufferLineApiView.ts +2 -2
  86. package/src/common/public/BufferNamespaceApi.ts +3 -3
  87. package/src/common/public/ParserApi.ts +3 -0
  88. package/src/common/services/BufferService.ts +14 -9
  89. package/src/common/services/CharsetService.ts +4 -0
  90. package/src/common/services/CoreService.ts +22 -9
  91. package/src/common/services/DecorationService.ts +258 -8
  92. package/src/common/services/LogService.ts +1 -31
  93. package/src/common/services/{CoreMouseService.ts → MouseStateService.ts} +21 -132
  94. package/src/common/services/OptionsService.ts +13 -4
  95. package/src/common/services/ServiceRegistry.ts +9 -7
  96. package/src/common/services/Services.ts +49 -40
  97. package/src/common/services/UnicodeService.ts +1 -1
  98. package/typings/xterm.d.ts +318 -34
  99. package/src/common/Clone.ts +0 -23
  100. package/src/common/TypedArrayUtils.ts +0 -17
  101. package/src/vs/base/browser/browser.ts +0 -141
  102. package/src/vs/base/browser/canIUse.ts +0 -49
  103. package/src/vs/base/browser/dom.ts +0 -2369
  104. package/src/vs/base/browser/fastDomNode.ts +0 -316
  105. package/src/vs/base/browser/globalPointerMoveMonitor.ts +0 -112
  106. package/src/vs/base/browser/iframe.ts +0 -135
  107. package/src/vs/base/browser/keyboardEvent.ts +0 -213
  108. package/src/vs/base/browser/mouseEvent.ts +0 -229
  109. package/src/vs/base/browser/touch.ts +0 -372
  110. package/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts +0 -303
  111. package/src/vs/base/browser/ui/scrollbar/horizontalScrollbar.ts +0 -114
  112. package/src/vs/base/browser/ui/scrollbar/scrollableElement.ts +0 -720
  113. package/src/vs/base/browser/ui/scrollbar/scrollableElementOptions.ts +0 -165
  114. package/src/vs/base/browser/ui/scrollbar/scrollbarArrow.ts +0 -114
  115. package/src/vs/base/browser/ui/scrollbar/scrollbarState.ts +0 -243
  116. package/src/vs/base/browser/ui/scrollbar/scrollbarVisibilityController.ts +0 -118
  117. package/src/vs/base/browser/ui/scrollbar/verticalScrollbar.ts +0 -116
  118. package/src/vs/base/browser/ui/widget.ts +0 -57
  119. package/src/vs/base/browser/window.ts +0 -14
  120. package/src/vs/base/common/arrays.ts +0 -887
  121. package/src/vs/base/common/arraysFind.ts +0 -202
  122. package/src/vs/base/common/assert.ts +0 -71
  123. package/src/vs/base/common/async.ts +0 -1992
  124. package/src/vs/base/common/cancellation.ts +0 -148
  125. package/src/vs/base/common/charCode.ts +0 -450
  126. package/src/vs/base/common/collections.ts +0 -140
  127. package/src/vs/base/common/decorators.ts +0 -130
  128. package/src/vs/base/common/equals.ts +0 -146
  129. package/src/vs/base/common/errors.ts +0 -303
  130. package/src/vs/base/common/event.ts +0 -1778
  131. package/src/vs/base/common/functional.ts +0 -32
  132. package/src/vs/base/common/hash.ts +0 -316
  133. package/src/vs/base/common/iterator.ts +0 -159
  134. package/src/vs/base/common/keyCodes.ts +0 -526
  135. package/src/vs/base/common/keybindings.ts +0 -284
  136. package/src/vs/base/common/lazy.ts +0 -47
  137. package/src/vs/base/common/lifecycle.ts +0 -801
  138. package/src/vs/base/common/linkedList.ts +0 -142
  139. package/src/vs/base/common/map.ts +0 -202
  140. package/src/vs/base/common/numbers.ts +0 -98
  141. package/src/vs/base/common/observable.ts +0 -76
  142. package/src/vs/base/common/observableInternal/api.ts +0 -31
  143. package/src/vs/base/common/observableInternal/autorun.ts +0 -281
  144. package/src/vs/base/common/observableInternal/base.ts +0 -489
  145. package/src/vs/base/common/observableInternal/debugName.ts +0 -145
  146. package/src/vs/base/common/observableInternal/derived.ts +0 -428
  147. package/src/vs/base/common/observableInternal/lazyObservableValue.ts +0 -146
  148. package/src/vs/base/common/observableInternal/logging.ts +0 -328
  149. package/src/vs/base/common/observableInternal/promise.ts +0 -209
  150. package/src/vs/base/common/observableInternal/utils.ts +0 -610
  151. package/src/vs/base/common/platform.ts +0 -281
  152. package/src/vs/base/common/scrollable.ts +0 -522
  153. package/src/vs/base/common/sequence.ts +0 -34
  154. package/src/vs/base/common/stopwatch.ts +0 -43
  155. package/src/vs/base/common/strings.ts +0 -557
  156. package/src/vs/base/common/symbols.ts +0 -9
  157. package/src/vs/base/common/uint.ts +0 -59
  158. package/src/vs/patches/nls.ts +0 -90
  159. package/src/vs/typings/base-common.d.ts +0 -20
  160. package/src/vs/typings/require.d.ts +0 -42
  161. package/src/vs/typings/vscode-globals-nls.d.ts +0 -36
  162. package/src/vs/typings/vscode-globals-product.d.ts +0 -33
@@ -3,6 +3,7 @@
3
3
  * @license MIT
4
4
  */
5
5
 
6
+ import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
6
7
  import { IDisposable } from 'common/Types';
7
8
  import { FontWeight } from 'common/services/Services';
8
9
 
@@ -24,6 +25,10 @@ const enum FontVariant {
24
25
  BOLD_ITALIC = 3
25
26
  }
26
27
 
28
+ export interface IWidthCacheFontVariantCanvas {
29
+ setFont(fontFamily: string, fontSize: number, fontWeight: FontWeight, italic: boolean): void;
30
+ measure(c: string): number;
31
+ }
27
32
 
28
33
  export class WidthCache implements IDisposable {
29
34
  // flat cache for regular variant up to CacheSettings.FLAT_SIZE
@@ -42,50 +47,24 @@ export class WidthCache implements IDisposable {
42
47
  private _fontSize = 0;
43
48
  private _weight: FontWeight = 'normal';
44
49
  private _weightBold: FontWeight = 'bold';
45
- private _container: HTMLDivElement;
46
- private _measureElements: HTMLSpanElement[] = [];
47
-
48
- constructor(_document: Document, _helperContainer: HTMLElement) {
49
- this._container = _document.createElement('div');
50
- this._container.classList.add('xterm-width-cache-measure-container');
51
- this._container.setAttribute('aria-hidden', 'true');
52
- // SP should stack in spans
53
- this._container.style.whiteSpace = 'pre';
54
- // avoid undercuts in non-monospace fonts from kerning
55
- this._container.style.fontKerning = 'none';
56
-
57
- const regular = _document.createElement('span');
58
- regular.classList.add('xterm-char-measure-element');
59
-
60
- const bold = _document.createElement('span');
61
- bold.classList.add('xterm-char-measure-element');
62
- bold.style.fontWeight = 'bold';
63
-
64
- const italic = _document.createElement('span');
65
- italic.classList.add('xterm-char-measure-element');
66
- italic.style.fontStyle = 'italic';
67
-
68
- const boldItalic = _document.createElement('span');
69
- boldItalic.classList.add('xterm-char-measure-element');
70
- boldItalic.style.fontWeight = 'bold';
71
- boldItalic.style.fontStyle = 'italic';
72
-
73
- // NOTE: must be in order of FontVariant
74
- this._measureElements = [regular, bold, italic, boldItalic];
75
- this._container.appendChild(regular);
76
- this._container.appendChild(bold);
77
- this._container.appendChild(italic);
78
- this._container.appendChild(boldItalic);
79
-
80
- _helperContainer.appendChild(this._container);
50
+ private _canvasElements: IWidthCacheFontVariantCanvas[] = [];
51
+
52
+ constructor(
53
+ canvasFactory: () => IWidthCacheFontVariantCanvas = () => new WidthCacheFontVariantCanvas()
54
+ ) {
55
+ this._canvasElements = [
56
+ canvasFactory(),
57
+ canvasFactory(),
58
+ canvasFactory(),
59
+ canvasFactory()
60
+ ];
81
61
 
82
62
  this.clear();
83
63
  }
84
64
 
85
65
  public dispose(): void {
86
- this._container.remove(); // remove elements from DOM
87
- this._measureElements.length = 0; // release element refs
88
- this._holey = undefined; // free cache memory via GC
66
+ this._canvasElements.length = 0;
67
+ this._holey = undefined; // free cache memory via GC
89
68
  }
90
69
 
91
70
  /**
@@ -104,10 +83,11 @@ export class WidthCache implements IDisposable {
104
83
  */
105
84
  public setFont(font: string, fontSize: number, weight: FontWeight, weightBold: FontWeight): void {
106
85
  // skip if nothing changed
107
- if (font === this._font
108
- && fontSize === this._fontSize
109
- && weight === this._weight
110
- && weightBold === this._weightBold
86
+ if (
87
+ font === this._font &&
88
+ fontSize === this._fontSize &&
89
+ weight === this._weight &&
90
+ weightBold === this._weightBold
111
91
  ) {
112
92
  return;
113
93
  }
@@ -117,12 +97,10 @@ export class WidthCache implements IDisposable {
117
97
  this._weight = weight;
118
98
  this._weightBold = weightBold;
119
99
 
120
- this._container.style.fontFamily = this._font;
121
- this._container.style.fontSize = `${this._fontSize}px`;
122
- this._measureElements[FontVariant.REGULAR].style.fontWeight = `${weight}`;
123
- this._measureElements[FontVariant.BOLD].style.fontWeight = `${weightBold}`;
124
- this._measureElements[FontVariant.ITALIC].style.fontWeight = `${weight}`;
125
- this._measureElements[FontVariant.BOLD_ITALIC].style.fontWeight = `${weightBold}`;
100
+ this._canvasElements[FontVariant.REGULAR].setFont(font, fontSize, weight, false);
101
+ this._canvasElements[FontVariant.BOLD].setFont(font, fontSize, weightBold, false);
102
+ this._canvasElements[FontVariant.ITALIC].setFont(font, fontSize, weight, true);
103
+ this._canvasElements[FontVariant.BOLD_ITALIC].setFont(font, fontSize, weightBold, true);
126
104
 
127
105
  this.clear();
128
106
  }
@@ -160,8 +138,32 @@ export class WidthCache implements IDisposable {
160
138
  }
161
139
 
162
140
  protected _measure(c: string, variant: FontVariant): number {
163
- const el = this._measureElements[variant];
164
- el.textContent = c.repeat(WidthCacheSettings.REPEAT);
165
- return el.offsetWidth / WidthCacheSettings.REPEAT;
141
+ return this._canvasElements[variant].measure(c);
142
+ }
143
+ }
144
+
145
+ class WidthCacheFontVariantCanvas implements IWidthCacheFontVariantCanvas {
146
+ private _canvas: OffscreenCanvas | HTMLCanvasElement;
147
+ private _ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D;
148
+
149
+ constructor() {
150
+ if (typeof OffscreenCanvas !== 'undefined') {
151
+ this._canvas = new OffscreenCanvas(1, 1);
152
+ this._ctx = throwIfFalsy(this._canvas.getContext('2d'));
153
+ } else {
154
+ this._canvas = document.createElement('canvas');
155
+ this._canvas.width = 1;
156
+ this._canvas.height = 1;
157
+ this._ctx = throwIfFalsy(this._canvas.getContext('2d'));
158
+ }
159
+ }
160
+
161
+ public setFont(fontFamily: string, fontSize: number, fontWeight: FontWeight, italic: boolean): void {
162
+ const fontStyle = italic ? 'italic' : '';
163
+ this._ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`.trim();
164
+ }
165
+
166
+ public measure(c: string): number {
167
+ return this._ctx.measureText(c).width;
166
168
  }
167
169
  }
@@ -4,3 +4,10 @@
4
4
  */
5
5
 
6
6
  export const INVERTED_DEFAULT_COLOR = 257;
7
+
8
+ export const enum RendererConstants {
9
+ /**
10
+ * The idle time after which cursor blinking stops.
11
+ */
12
+ CURSOR_BLINK_IDLE_TIMEOUT = 5 * 60 * 1000
13
+ }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Copyright (c) 2026 The xterm.js authors. All rights reserved.
3
+ * @license MIT
4
+ */
5
+
6
+ import { ICoreBrowserService } from 'browser/services/Services';
7
+ import { Disposable, toDisposable } from 'common/Lifecycle';
8
+ import { IOptionsService } from 'common/services/Services';
9
+
10
+ export class TextBlinkStateManager extends Disposable {
11
+ private _intervalDuration: number = 0;
12
+ private _interval: number | undefined;
13
+ private _blinkOn: boolean = true;
14
+ private _needsBlinkInViewport: boolean = false;
15
+ private _isViewportVisible: boolean = true;
16
+
17
+ constructor(
18
+ private readonly _renderCallback: () => void,
19
+ private readonly _coreBrowserService: ICoreBrowserService,
20
+ private readonly _optionsService: IOptionsService
21
+ ) {
22
+ super();
23
+ this._register(this._optionsService.onSpecificOptionChange('blinkIntervalDuration', duration => {
24
+ this.setIntervalDuration(duration);
25
+ }));
26
+ this.setIntervalDuration(this._optionsService.rawOptions.blinkIntervalDuration);
27
+ this._register(toDisposable(() => this._clearInterval()));
28
+ }
29
+
30
+ public get isBlinkOn(): boolean {
31
+ return this._blinkOn;
32
+ }
33
+
34
+ public get isEnabled(): boolean {
35
+ return this._intervalDuration > 0;
36
+ }
37
+
38
+ public setNeedsBlinkInViewport(needsBlinkInViewport: boolean): void {
39
+ if (this._needsBlinkInViewport === needsBlinkInViewport) {
40
+ return;
41
+ }
42
+
43
+ this._needsBlinkInViewport = needsBlinkInViewport;
44
+ this._updateIntervalState();
45
+ }
46
+
47
+ public setViewportVisible(isVisible: boolean): void {
48
+ if (this._isViewportVisible === isVisible) {
49
+ return;
50
+ }
51
+
52
+ this._isViewportVisible = isVisible;
53
+ this._updateIntervalState();
54
+ }
55
+
56
+ public setIntervalDuration(duration: number): void {
57
+ if (duration === this._intervalDuration) {
58
+ return;
59
+ }
60
+
61
+ this._intervalDuration = duration;
62
+ this._clearInterval();
63
+ this._updateIntervalState();
64
+ }
65
+
66
+ private _updateIntervalState(): void {
67
+ const shouldBlink = this._intervalDuration > 0 && this._needsBlinkInViewport && this._isViewportVisible;
68
+ if (shouldBlink) {
69
+ if (this._interval !== undefined) {
70
+ return;
71
+ }
72
+ const wasBlinkOn = this._blinkOn;
73
+ this._blinkOn = true;
74
+ this._interval = this._coreBrowserService.window.setInterval(() => {
75
+ this._blinkOn = !this._blinkOn;
76
+ this._renderCallback();
77
+ }, this._intervalDuration);
78
+ if (!wasBlinkOn) {
79
+ this._renderCallback();
80
+ }
81
+ return;
82
+ }
83
+
84
+ this._clearInterval();
85
+ if (!this._blinkOn) {
86
+ this._blinkOn = true;
87
+ this._renderCallback();
88
+ }
89
+ }
90
+
91
+ private _clearInterval(): void {
92
+ if (this._interval !== undefined) {
93
+ this._coreBrowserService.window.clearInterval(this._interval);
94
+ this._interval = undefined;
95
+ }
96
+ }
97
+ }
@@ -6,7 +6,7 @@
6
6
  import { Terminal } from '@xterm/xterm';
7
7
  import { ITerminal } from 'browser/Types';
8
8
  import { IDisposable } from 'common/Types';
9
- import type { Event } from 'vs/base/common/event';
9
+ import type { IEvent } from 'common/Event';
10
10
 
11
11
  export interface IDimensions {
12
12
  width: number;
@@ -39,6 +39,11 @@ export interface IRenderDimensions {
39
39
  export interface IRequestRedrawEvent {
40
40
  start: number;
41
41
  end: number;
42
+ /**
43
+ * Whether the redraw should happen synchronously. This is used to avoid
44
+ * flicker when the canvas is resized.
45
+ */
46
+ sync?: boolean;
42
47
  }
43
48
 
44
49
  /**
@@ -52,7 +57,7 @@ export interface IRenderer extends IDisposable {
52
57
  * Fires when the renderer is requesting to be redrawn on the next animation
53
58
  * frame but is _not_ a result of content changing (eg. selection changes).
54
59
  */
55
- readonly onRequestRedraw: Event<IRequestRedrawEvent>;
60
+ readonly onRequestRedraw: IEvent<IRequestRedrawEvent>;
56
61
 
57
62
  dispose(): void;
58
63
  handleDevicePixelRatioChange(): void;
@@ -60,6 +65,7 @@ export interface IRenderer extends IDisposable {
60
65
  handleCharSizeChanged(): void;
61
66
  handleBlur(): void;
62
67
  handleFocus(): void;
68
+ handleViewportVisibilityChange?(isVisible: boolean): void;
63
69
  handleSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void;
64
70
  handleCursorMove(): void;
65
71
  clear(): void;
@@ -0,0 +1,300 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License. See License.txt in the project root for license information.
4
+ *--------------------------------------------------------------------------------------------*/
5
+
6
+ import * as dom from '../Dom';
7
+ import { FastDomNode } from './fastDomNode';
8
+ import { GlobalPointerMoveMonitor } from './globalPointerMoveMonitor';
9
+ import { StandardWheelEvent } from './mouseEvent';
10
+ import { ScrollbarArrow, IScrollbarArrowOptions } from './scrollbarArrow';
11
+ import { ScrollbarState } from './scrollbarState';
12
+ import { ScrollbarVisibilityController } from './scrollbarVisibilityController';
13
+ import { Widget } from './widget';
14
+ import * as platform from 'common/Platform';
15
+ import { INewScrollPosition, Scrollable, ScrollbarVisibility } from './scrollable';
16
+
17
+ /**
18
+ * The orthogonal distance to the slider at which dragging "resets". This implements "snapping"
19
+ */
20
+ const POINTER_DRAG_RESET_DISTANCE = 140;
21
+
22
+ export interface ISimplifiedPointerEvent {
23
+ buttons: number;
24
+ pageX: number;
25
+ pageY: number;
26
+ }
27
+
28
+ export interface IScrollbarHost {
29
+ handleMouseWheel(mouseWheelEvent: StandardWheelEvent): void;
30
+ handleDragStart(): void;
31
+ handleDragEnd(): void;
32
+ }
33
+
34
+ interface IAbstractScrollbarOptions {
35
+ lazyRender: boolean;
36
+ host: IScrollbarHost;
37
+ scrollbarState: ScrollbarState;
38
+ visibility: ScrollbarVisibility;
39
+ extraScrollbarClassName: string;
40
+ scrollable: Scrollable;
41
+ scrollByPage: boolean;
42
+ }
43
+
44
+ export abstract class AbstractScrollbar extends Widget {
45
+
46
+ protected _host: IScrollbarHost;
47
+ protected _scrollable: Scrollable;
48
+ protected _scrollByPage: boolean;
49
+ private _lazyRender: boolean;
50
+ protected _scrollbarState: ScrollbarState;
51
+ protected _visibilityController: ScrollbarVisibilityController;
52
+ private _pointerMoveMonitor: GlobalPointerMoveMonitor;
53
+
54
+ public domNode: FastDomNode<HTMLElement>;
55
+ public slider!: FastDomNode<HTMLElement>;
56
+
57
+ protected _shouldRender: boolean;
58
+
59
+ constructor(opts: IAbstractScrollbarOptions) {
60
+ super();
61
+ this._lazyRender = opts.lazyRender;
62
+ this._host = opts.host;
63
+ this._scrollable = opts.scrollable;
64
+ this._scrollByPage = opts.scrollByPage;
65
+ this._scrollbarState = opts.scrollbarState;
66
+ this._visibilityController = this._register(new ScrollbarVisibilityController(opts.visibility, 'xterm-visible xterm-scrollbar ' + opts.extraScrollbarClassName, 'xterm-invisible xterm-scrollbar ' + opts.extraScrollbarClassName));
67
+ this._visibilityController.setIsNeeded(this._scrollbarState.isNeeded());
68
+ this._pointerMoveMonitor = this._register(new GlobalPointerMoveMonitor());
69
+ this._shouldRender = true;
70
+ this.domNode = new FastDomNode(document.createElement('div'));
71
+ this.domNode.setAttribute('role', 'presentation');
72
+ this.domNode.setAttribute('aria-hidden', 'true');
73
+
74
+ this._visibilityController.setDomNode(this.domNode);
75
+ this.domNode.setPosition('absolute');
76
+
77
+ this._register(dom.addDisposableListener(this.domNode.domNode, dom.eventType.POINTER_DOWN, (e: PointerEvent) => this._domNodePointerDown(e)));
78
+ }
79
+
80
+ // ----------------- creation
81
+
82
+ /**
83
+ * Creates the dom node for an arrow & adds it to the container
84
+ */
85
+ protected _createArrow(opts: IScrollbarArrowOptions): ScrollbarArrow {
86
+ const arrow = this._register(new ScrollbarArrow(opts));
87
+ this.domNode.domNode.appendChild(arrow.bgDomNode);
88
+ this.domNode.domNode.appendChild(arrow.domNode);
89
+ return arrow;
90
+ }
91
+
92
+ /**
93
+ * Creates the slider dom node, adds it to the container & hooks up the events
94
+ */
95
+ protected _createSlider(top: number, left: number, width: number | undefined, height: number | undefined): void {
96
+ this.slider = new FastDomNode(document.createElement('div'));
97
+ this.slider.setClassName('xterm-slider');
98
+ this.slider.setPosition('absolute');
99
+ this.slider.setTop(top);
100
+ this.slider.setLeft(left);
101
+ if (typeof width === 'number') {
102
+ this.slider.setWidth(width);
103
+ }
104
+ if (typeof height === 'number') {
105
+ this.slider.setHeight(height);
106
+ }
107
+ this.slider.setLayerHinting(true);
108
+ this.slider.setContain('strict');
109
+
110
+ this.domNode.domNode.appendChild(this.slider.domNode);
111
+
112
+ this._register(dom.addDisposableListener(
113
+ this.slider.domNode,
114
+ dom.eventType.POINTER_DOWN,
115
+ (e: PointerEvent) => {
116
+ if (e.button === 0) {
117
+ e.preventDefault();
118
+ this._sliderPointerDown(e);
119
+ }
120
+ }
121
+ ));
122
+
123
+ this._onclick(this.slider.domNode, e => {
124
+ if (e.leftButton) {
125
+ e.stopPropagation();
126
+ }
127
+ });
128
+ }
129
+
130
+ // ----------------- Update state
131
+
132
+ protected _handleElementSize(visibleSize: number): boolean {
133
+ if (this._scrollbarState.setVisibleSize(visibleSize)) {
134
+ this._visibilityController.setIsNeeded(this._scrollbarState.isNeeded());
135
+ this._shouldRender = true;
136
+ if (!this._lazyRender) {
137
+ this.render();
138
+ }
139
+ }
140
+ return this._shouldRender;
141
+ }
142
+
143
+ protected _handleElementScrollSize(elementScrollSize: number): boolean {
144
+ if (this._scrollbarState.setScrollSize(elementScrollSize)) {
145
+ this._visibilityController.setIsNeeded(this._scrollbarState.isNeeded());
146
+ this._shouldRender = true;
147
+ if (!this._lazyRender) {
148
+ this.render();
149
+ }
150
+ }
151
+ return this._shouldRender;
152
+ }
153
+
154
+ protected _handleElementScrollPosition(elementScrollPosition: number): boolean {
155
+ if (this._scrollbarState.setScrollPosition(elementScrollPosition)) {
156
+ this._visibilityController.setIsNeeded(this._scrollbarState.isNeeded());
157
+ this._shouldRender = true;
158
+ if (!this._lazyRender) {
159
+ this.render();
160
+ }
161
+ }
162
+ return this._shouldRender;
163
+ }
164
+
165
+ // ----------------- rendering
166
+
167
+ public beginReveal(): void {
168
+ this._visibilityController.setShouldBeVisible(true);
169
+ }
170
+
171
+ public beginHide(): void {
172
+ this._visibilityController.setShouldBeVisible(false);
173
+ }
174
+
175
+ public render(): void {
176
+ if (!this._shouldRender) {
177
+ return;
178
+ }
179
+ this._shouldRender = false;
180
+
181
+ this._renderDomNode(this._scrollbarState.getRectangleLargeSize(), this._scrollbarState.getRectangleSmallSize());
182
+ this._updateSlider(this._scrollbarState.getSliderSize(), this._scrollbarState.getArrowSize() + this._scrollbarState.getSliderPosition());
183
+ }
184
+ // ----------------- DOM events
185
+
186
+ private _domNodePointerDown(e: PointerEvent): void {
187
+ if (e.target !== this.domNode.domNode) {
188
+ return;
189
+ }
190
+ this._handlePointerDown(e);
191
+ }
192
+
193
+ public delegatePointerDown(e: PointerEvent): void {
194
+ const domTop = this.domNode.domNode.getClientRects()[0].top;
195
+ const sliderStart = domTop + this._scrollbarState.getSliderPosition();
196
+ const sliderStop = domTop + this._scrollbarState.getSliderPosition() + this._scrollbarState.getSliderSize();
197
+ const pointerPos = this._sliderPointerPosition(e);
198
+ if (sliderStart <= pointerPos && pointerPos <= sliderStop) {
199
+ if (e.button === 0) {
200
+ e.preventDefault();
201
+ this._sliderPointerDown(e);
202
+ }
203
+ } else {
204
+ this._handlePointerDown(e);
205
+ }
206
+ }
207
+
208
+ private _handlePointerDown(e: PointerEvent): void {
209
+ let offsetX: number;
210
+ let offsetY: number;
211
+ if (e.target === this.domNode.domNode && typeof e.offsetX === 'number' && typeof e.offsetY === 'number') {
212
+ offsetX = e.offsetX;
213
+ offsetY = e.offsetY;
214
+ } else {
215
+ const domNodePosition = dom.getDomNodePagePosition(this.domNode.domNode);
216
+ offsetX = e.pageX - domNodePosition.left;
217
+ offsetY = e.pageY - domNodePosition.top;
218
+ }
219
+
220
+ const offset = this._pointerDownRelativePosition(offsetX, offsetY);
221
+ this._setDesiredScrollPositionNow(
222
+ this._scrollByPage
223
+ ? this._scrollbarState.getDesiredScrollPositionFromOffsetPaged(offset)
224
+ : this._scrollbarState.getDesiredScrollPositionFromOffset(offset)
225
+ );
226
+
227
+ if (e.button === 0) {
228
+ e.preventDefault();
229
+ this._sliderPointerDown(e);
230
+ }
231
+ }
232
+
233
+ private _sliderPointerDown(e: PointerEvent): void {
234
+ if (!e.target || !(e.target instanceof Element)) {
235
+ return;
236
+ }
237
+ const initialPointerPosition = this._sliderPointerPosition(e);
238
+ const initialPointerOrthogonalPosition = this._sliderOrthogonalPointerPosition(e);
239
+ const initialScrollbarState = this._scrollbarState.clone();
240
+ this.slider.toggleClassName('xterm-active', true);
241
+
242
+ this._pointerMoveMonitor.startMonitoring(
243
+ e.target,
244
+ e.pointerId,
245
+ e.buttons,
246
+ (pointerMoveData: PointerEvent) => {
247
+ const pointerOrthogonalPosition = this._sliderOrthogonalPointerPosition(pointerMoveData);
248
+ const pointerOrthogonalDelta = Math.abs(pointerOrthogonalPosition - initialPointerOrthogonalPosition);
249
+
250
+ if (platform.isWindows && pointerOrthogonalDelta > POINTER_DRAG_RESET_DISTANCE) {
251
+ this._setDesiredScrollPositionNow(initialScrollbarState.getScrollPosition());
252
+ return;
253
+ }
254
+
255
+ const pointerPosition = this._sliderPointerPosition(pointerMoveData);
256
+ const pointerDelta = pointerPosition - initialPointerPosition;
257
+ this._setDesiredScrollPositionNow(initialScrollbarState.getDesiredScrollPositionFromDelta(pointerDelta));
258
+ },
259
+ () => {
260
+ this.slider.toggleClassName('xterm-active', false);
261
+ this._host.handleDragEnd();
262
+ }
263
+ );
264
+
265
+ this._host.handleDragStart();
266
+ }
267
+
268
+ private _setDesiredScrollPositionNow(_desiredScrollPosition: number): void {
269
+
270
+ const desiredScrollPosition: INewScrollPosition = {};
271
+ this.writeScrollPosition(desiredScrollPosition, _desiredScrollPosition);
272
+
273
+ this._scrollable.setScrollPositionNow(desiredScrollPosition);
274
+ }
275
+
276
+ public updateScrollbarSize(scrollbarSize: number): void {
277
+ this._updateScrollbarSize(scrollbarSize);
278
+ this._scrollbarState.setScrollbarSize(scrollbarSize);
279
+ this._shouldRender = true;
280
+ if (!this._lazyRender) {
281
+ this.render();
282
+ }
283
+ }
284
+
285
+ public isNeeded(): boolean {
286
+ return this._scrollbarState.isNeeded();
287
+ }
288
+
289
+ // ----------------- Overwrite these
290
+
291
+ protected abstract _renderDomNode(largeSize: number, smallSize: number): void;
292
+ protected abstract _updateSlider(sliderSize: number, sliderPosition: number): void;
293
+
294
+ protected abstract _pointerDownRelativePosition(offsetX: number, offsetY: number): number;
295
+ protected abstract _sliderPointerPosition(e: ISimplifiedPointerEvent): number;
296
+ protected abstract _sliderOrthogonalPointerPosition(e: ISimplifiedPointerEvent): number;
297
+ protected abstract _updateScrollbarSize(size: number): void;
298
+
299
+ public abstract writeScrollPosition(target: INewScrollPosition, scrollPosition: number): void;
300
+ }