@xterm/xterm 5.6.0-beta.6 → 5.6.0-beta.61

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 (118) hide show
  1. package/README.md +7 -3
  2. package/css/xterm.css +71 -4
  3. package/lib/xterm.js +1 -1
  4. package/lib/xterm.js.map +1 -1
  5. package/lib/xterm.mjs +53 -0
  6. package/lib/xterm.mjs.map +7 -0
  7. package/package.json +43 -33
  8. package/src/browser/AccessibilityManager.ts +53 -25
  9. package/src/browser/{Terminal.ts → CoreBrowserTerminal.ts} +132 -144
  10. package/src/browser/Linkifier.ts +15 -13
  11. package/src/browser/LocalizableStrings.ts +15 -4
  12. package/src/browser/{Types.d.ts → Types.ts} +67 -15
  13. package/src/browser/Viewport.ts +142 -370
  14. package/src/browser/decorations/BufferDecorationRenderer.ts +14 -9
  15. package/src/browser/decorations/OverviewRulerRenderer.ts +40 -44
  16. package/src/browser/public/Terminal.ts +25 -19
  17. package/src/browser/renderer/dom/DomRenderer.ts +14 -16
  18. package/src/browser/renderer/shared/CharAtlasUtils.ts +4 -0
  19. package/src/browser/renderer/shared/CustomGlyphs.ts +6 -0
  20. package/src/browser/renderer/shared/DevicePixelObserver.ts +1 -2
  21. package/src/browser/renderer/shared/TextureAtlas.ts +3 -3
  22. package/src/browser/renderer/shared/{Types.d.ts → Types.ts} +4 -4
  23. package/src/browser/services/CharSizeService.ts +6 -6
  24. package/src/browser/services/CoreBrowserService.ts +15 -15
  25. package/src/browser/services/LinkProviderService.ts +2 -2
  26. package/src/browser/services/RenderService.ts +20 -20
  27. package/src/browser/services/SelectionService.ts +8 -8
  28. package/src/browser/services/Services.ts +13 -13
  29. package/src/browser/services/ThemeService.ts +17 -56
  30. package/src/browser/shared/Constants.ts +8 -0
  31. package/src/common/CircularList.ts +5 -5
  32. package/src/common/CoreTerminal.ts +35 -41
  33. package/src/common/InputHandler.ts +34 -28
  34. package/src/common/{Types.d.ts → Types.ts} +11 -17
  35. package/src/common/buffer/Buffer.ts +5 -1
  36. package/src/common/buffer/BufferSet.ts +5 -5
  37. package/src/common/buffer/Marker.ts +4 -4
  38. package/src/common/buffer/{Types.d.ts → Types.ts} +2 -2
  39. package/src/common/input/WriteBuffer.ts +3 -3
  40. package/src/common/parser/EscapeSequenceParser.ts +4 -4
  41. package/src/common/public/BufferNamespaceApi.ts +3 -3
  42. package/src/common/services/BufferService.ts +7 -7
  43. package/src/common/services/CoreMouseService.ts +5 -3
  44. package/src/common/services/CoreService.ts +6 -6
  45. package/src/common/services/DecorationService.ts +8 -9
  46. package/src/common/services/LogService.ts +2 -2
  47. package/src/common/services/OptionsService.ts +5 -5
  48. package/src/common/services/Services.ts +24 -17
  49. package/src/common/services/UnicodeService.ts +2 -2
  50. package/src/vs/base/browser/browser.ts +141 -0
  51. package/src/vs/base/browser/canIUse.ts +49 -0
  52. package/src/vs/base/browser/dom.ts +2369 -0
  53. package/src/vs/base/browser/fastDomNode.ts +316 -0
  54. package/src/vs/base/browser/globalPointerMoveMonitor.ts +112 -0
  55. package/src/vs/base/browser/iframe.ts +135 -0
  56. package/src/vs/base/browser/keyboardEvent.ts +213 -0
  57. package/src/vs/base/browser/mouseEvent.ts +229 -0
  58. package/src/vs/base/browser/touch.ts +372 -0
  59. package/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts +303 -0
  60. package/src/vs/base/browser/ui/scrollbar/horizontalScrollbar.ts +114 -0
  61. package/src/vs/base/browser/ui/scrollbar/scrollableElement.ts +720 -0
  62. package/src/vs/base/browser/ui/scrollbar/scrollableElementOptions.ts +165 -0
  63. package/src/vs/base/browser/ui/scrollbar/scrollbarArrow.ts +114 -0
  64. package/src/vs/base/browser/ui/scrollbar/scrollbarState.ts +243 -0
  65. package/src/vs/base/browser/ui/scrollbar/scrollbarVisibilityController.ts +118 -0
  66. package/src/vs/base/browser/ui/scrollbar/verticalScrollbar.ts +116 -0
  67. package/src/vs/base/browser/ui/widget.ts +57 -0
  68. package/src/vs/base/browser/window.ts +14 -0
  69. package/src/vs/base/common/arrays.ts +887 -0
  70. package/src/vs/base/common/arraysFind.ts +202 -0
  71. package/src/vs/base/common/assert.ts +71 -0
  72. package/src/vs/base/common/async.ts +1992 -0
  73. package/src/vs/base/common/cancellation.ts +148 -0
  74. package/src/vs/base/common/charCode.ts +450 -0
  75. package/src/vs/base/common/collections.ts +140 -0
  76. package/src/vs/base/common/decorators.ts +130 -0
  77. package/src/vs/base/common/equals.ts +146 -0
  78. package/src/vs/base/common/errors.ts +303 -0
  79. package/src/vs/base/common/event.ts +1778 -0
  80. package/src/vs/base/common/functional.ts +32 -0
  81. package/src/vs/base/common/hash.ts +316 -0
  82. package/src/vs/base/common/iterator.ts +159 -0
  83. package/src/vs/base/common/keyCodes.ts +526 -0
  84. package/src/vs/base/common/keybindings.ts +284 -0
  85. package/src/vs/base/common/lazy.ts +47 -0
  86. package/src/vs/base/common/lifecycle.ts +801 -0
  87. package/src/vs/base/common/linkedList.ts +142 -0
  88. package/src/vs/base/common/map.ts +202 -0
  89. package/src/vs/base/common/numbers.ts +98 -0
  90. package/src/vs/base/common/observable.ts +76 -0
  91. package/src/vs/base/common/observableInternal/api.ts +31 -0
  92. package/src/vs/base/common/observableInternal/autorun.ts +281 -0
  93. package/src/vs/base/common/observableInternal/base.ts +489 -0
  94. package/src/vs/base/common/observableInternal/debugName.ts +145 -0
  95. package/src/vs/base/common/observableInternal/derived.ts +428 -0
  96. package/src/vs/base/common/observableInternal/lazyObservableValue.ts +146 -0
  97. package/src/vs/base/common/observableInternal/logging.ts +328 -0
  98. package/src/vs/base/common/observableInternal/promise.ts +209 -0
  99. package/src/vs/base/common/observableInternal/utils.ts +610 -0
  100. package/src/vs/base/common/platform.ts +281 -0
  101. package/src/vs/base/common/scrollable.ts +522 -0
  102. package/src/vs/base/common/sequence.ts +34 -0
  103. package/src/vs/base/common/stopwatch.ts +43 -0
  104. package/src/vs/base/common/strings.ts +557 -0
  105. package/src/vs/base/common/symbols.ts +9 -0
  106. package/src/vs/base/common/uint.ts +59 -0
  107. package/src/vs/patches/nls.ts +90 -0
  108. package/src/vs/typings/base-common.d.ts +20 -0
  109. package/src/vs/typings/require.d.ts +42 -0
  110. package/src/vs/typings/thenable.d.ts +12 -0
  111. package/src/vs/typings/vscode-globals-nls.d.ts +36 -0
  112. package/src/vs/typings/vscode-globals-product.d.ts +33 -0
  113. package/typings/xterm.d.ts +59 -15
  114. package/src/browser/Lifecycle.ts +0 -33
  115. package/src/common/EventEmitter.ts +0 -78
  116. package/src/common/Lifecycle.ts +0 -108
  117. /package/src/browser/selection/{Types.d.ts → Types.ts} +0 -0
  118. /package/src/common/parser/{Types.d.ts → Types.ts} +0 -0
@@ -0,0 +1,720 @@
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 { getZoomFactor, isChrome } from 'vs/base/browser/browser';
7
+ import * as dom from 'vs/base/browser/dom';
8
+ import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
9
+ import { IMouseEvent, IMouseWheelEvent, StandardWheelEvent } from 'vs/base/browser/mouseEvent';
10
+ import { ScrollbarHost } from 'vs/base/browser/ui/scrollbar/abstractScrollbar';
11
+ import { HorizontalScrollbar } from 'vs/base/browser/ui/scrollbar/horizontalScrollbar';
12
+ import { ScrollableElementChangeOptions, ScrollableElementCreationOptions, ScrollableElementResolvedOptions } from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';
13
+ import { VerticalScrollbar } from 'vs/base/browser/ui/scrollbar/verticalScrollbar';
14
+ import { Widget } from 'vs/base/browser/ui/widget';
15
+ import { TimeoutTimer } from 'vs/base/common/async';
16
+ import { Emitter, Event } from 'vs/base/common/event';
17
+ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
18
+ import * as platform from 'vs/base/common/platform';
19
+ import { INewScrollDimensions, INewScrollPosition, IScrollDimensions, IScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable';
20
+ // import 'vs/css!./media/scrollbars';
21
+
22
+ const HIDE_TIMEOUT = 500;
23
+ const SCROLL_WHEEL_SENSITIVITY = 50;
24
+ const SCROLL_WHEEL_SMOOTH_SCROLL_ENABLED = true;
25
+
26
+ export interface IOverviewRulerLayoutInfo {
27
+ parent: HTMLElement;
28
+ insertBefore: HTMLElement;
29
+ }
30
+
31
+ class MouseWheelClassifierItem {
32
+ public timestamp: number;
33
+ public deltaX: number;
34
+ public deltaY: number;
35
+ public score: number;
36
+
37
+ constructor(timestamp: number, deltaX: number, deltaY: number) {
38
+ this.timestamp = timestamp;
39
+ this.deltaX = deltaX;
40
+ this.deltaY = deltaY;
41
+ this.score = 0;
42
+ }
43
+ }
44
+
45
+ export class MouseWheelClassifier {
46
+
47
+ public static readonly INSTANCE = new MouseWheelClassifier();
48
+
49
+ private readonly _capacity: number;
50
+ private _memory: MouseWheelClassifierItem[];
51
+ private _front: number;
52
+ private _rear: number;
53
+
54
+ constructor() {
55
+ this._capacity = 5;
56
+ this._memory = [];
57
+ this._front = -1;
58
+ this._rear = -1;
59
+ }
60
+
61
+ public isPhysicalMouseWheel(): boolean {
62
+ if (this._front === -1 && this._rear === -1) {
63
+ // no elements
64
+ return false;
65
+ }
66
+
67
+ // 0.5 * last + 0.25 * 2nd last + 0.125 * 3rd last + ...
68
+ let remainingInfluence = 1;
69
+ let score = 0;
70
+ let iteration = 1;
71
+
72
+ let index = this._rear;
73
+ do {
74
+ const influence = (index === this._front ? remainingInfluence : Math.pow(2, -iteration));
75
+ remainingInfluence -= influence;
76
+ score += this._memory[index].score * influence;
77
+
78
+ if (index === this._front) {
79
+ break;
80
+ }
81
+
82
+ index = (this._capacity + index - 1) % this._capacity;
83
+ iteration++;
84
+ } while (true);
85
+
86
+ return (score <= 0.5);
87
+ }
88
+
89
+ public acceptStandardWheelEvent(e: StandardWheelEvent): void {
90
+ if (isChrome) {
91
+ const targetWindow = dom.getWindow(e.browserEvent);
92
+ const pageZoomFactor = getZoomFactor(targetWindow);
93
+ // On Chrome, the incoming delta events are multiplied with the OS zoom factor.
94
+ // The OS zoom factor can be reverse engineered by using the device pixel ratio and the configured zoom factor into account.
95
+ this.accept(Date.now(), e.deltaX * pageZoomFactor, e.deltaY * pageZoomFactor);
96
+ } else {
97
+ this.accept(Date.now(), e.deltaX, e.deltaY);
98
+ }
99
+ }
100
+
101
+ public accept(timestamp: number, deltaX: number, deltaY: number): void {
102
+ let previousItem = null;
103
+ const item = new MouseWheelClassifierItem(timestamp, deltaX, deltaY);
104
+
105
+ if (this._front === -1 && this._rear === -1) {
106
+ this._memory[0] = item;
107
+ this._front = 0;
108
+ this._rear = 0;
109
+ } else {
110
+ previousItem = this._memory[this._rear];
111
+
112
+ this._rear = (this._rear + 1) % this._capacity;
113
+ if (this._rear === this._front) {
114
+ // Drop oldest
115
+ this._front = (this._front + 1) % this._capacity;
116
+ }
117
+ this._memory[this._rear] = item;
118
+ }
119
+
120
+ item.score = this._computeScore(item, previousItem);
121
+ }
122
+
123
+ /**
124
+ * A score between 0 and 1 for `item`.
125
+ * - a score towards 0 indicates that the source appears to be a physical mouse wheel
126
+ * - a score towards 1 indicates that the source appears to be a touchpad or magic mouse, etc.
127
+ */
128
+ private _computeScore(item: MouseWheelClassifierItem, previousItem: MouseWheelClassifierItem | null): number {
129
+
130
+ if (Math.abs(item.deltaX) > 0 && Math.abs(item.deltaY) > 0) {
131
+ // both axes exercised => definitely not a physical mouse wheel
132
+ return 1;
133
+ }
134
+
135
+ let score: number = 0.5;
136
+
137
+ if (!this._isAlmostInt(item.deltaX) || !this._isAlmostInt(item.deltaY)) {
138
+ // non-integer deltas => indicator that this is not a physical mouse wheel
139
+ score += 0.25;
140
+ }
141
+
142
+ // Non-accelerating scroll => indicator that this is a physical mouse wheel
143
+ // These can be identified by seeing whether they are the module of one another.
144
+ if (previousItem) {
145
+ const absDeltaX = Math.abs(item.deltaX);
146
+ const absDeltaY = Math.abs(item.deltaY);
147
+
148
+ const absPreviousDeltaX = Math.abs(previousItem.deltaX);
149
+ const absPreviousDeltaY = Math.abs(previousItem.deltaY);
150
+
151
+ // Min 1 to avoid division by zero, module 1 will still be 0.
152
+ const minDeltaX = Math.max(Math.min(absDeltaX, absPreviousDeltaX), 1);
153
+ const minDeltaY = Math.max(Math.min(absDeltaY, absPreviousDeltaY), 1);
154
+
155
+ const maxDeltaX = Math.max(absDeltaX, absPreviousDeltaX);
156
+ const maxDeltaY = Math.max(absDeltaY, absPreviousDeltaY);
157
+
158
+ const isSameModulo = (maxDeltaX % minDeltaX === 0 && maxDeltaY % minDeltaY === 0);
159
+ if (isSameModulo) {
160
+ score -= 0.5;
161
+ }
162
+ }
163
+
164
+ return Math.min(Math.max(score, 0), 1);
165
+ }
166
+
167
+ private _isAlmostInt(value: number): boolean {
168
+ const delta = Math.abs(Math.round(value) - value);
169
+ return (delta < 0.01);
170
+ }
171
+ }
172
+
173
+ export abstract class AbstractScrollableElement extends Widget {
174
+
175
+ private readonly _options: ScrollableElementResolvedOptions;
176
+ protected readonly _scrollable: Scrollable;
177
+ private readonly _verticalScrollbar: VerticalScrollbar;
178
+ private readonly _horizontalScrollbar: HorizontalScrollbar;
179
+ private readonly _domNode: HTMLElement;
180
+
181
+ private readonly _leftShadowDomNode: FastDomNode<HTMLElement> | null;
182
+ private readonly _topShadowDomNode: FastDomNode<HTMLElement> | null;
183
+ private readonly _topLeftShadowDomNode: FastDomNode<HTMLElement> | null;
184
+
185
+ private readonly _listenOnDomNode: HTMLElement;
186
+
187
+ private _mouseWheelToDispose: IDisposable[];
188
+
189
+ private _isDragging: boolean;
190
+ private _mouseIsOver: boolean;
191
+
192
+ private readonly _hideTimeout: TimeoutTimer;
193
+ private _shouldRender: boolean;
194
+
195
+ private _revealOnScroll: boolean;
196
+
197
+ private readonly _onScroll = this._register(new Emitter<ScrollEvent>());
198
+ public readonly onScroll: Event<ScrollEvent> = this._onScroll.event;
199
+
200
+ private readonly _onWillScroll = this._register(new Emitter<ScrollEvent>());
201
+ public readonly onWillScroll: Event<ScrollEvent> = this._onWillScroll.event;
202
+
203
+ public get options(): Readonly<ScrollableElementResolvedOptions> {
204
+ return this._options;
205
+ }
206
+
207
+ protected constructor(element: HTMLElement, options: ScrollableElementCreationOptions, scrollable: Scrollable) {
208
+ super();
209
+ // HACK: xterm.js currnetly requires overflow to allow decorations to escape the container
210
+ // element.style.overflow = 'hidden';
211
+ this._options = resolveOptions(options);
212
+ this._scrollable = scrollable;
213
+
214
+ this._register(this._scrollable.onScroll((e) => {
215
+ this._onWillScroll.fire(e);
216
+ this._onDidScroll(e);
217
+ this._onScroll.fire(e);
218
+ }));
219
+
220
+ const scrollbarHost: ScrollbarHost = {
221
+ onMouseWheel: (mouseWheelEvent: StandardWheelEvent) => this._onMouseWheel(mouseWheelEvent),
222
+ onDragStart: () => this._onDragStart(),
223
+ onDragEnd: () => this._onDragEnd(),
224
+ };
225
+ this._verticalScrollbar = this._register(new VerticalScrollbar(this._scrollable, this._options, scrollbarHost));
226
+ this._horizontalScrollbar = this._register(new HorizontalScrollbar(this._scrollable, this._options, scrollbarHost));
227
+
228
+ this._domNode = document.createElement('div');
229
+ this._domNode.className = 'xterm-scrollable-element ' + this._options.className;
230
+ this._domNode.setAttribute('role', 'presentation');
231
+ this._domNode.style.position = 'relative';
232
+ // HACK: xterm.js currnetly requires overflow to allow decorations to escape the container
233
+ // this._domNode.style.overflow = 'hidden';
234
+ this._domNode.appendChild(element);
235
+ this._domNode.appendChild(this._horizontalScrollbar.domNode.domNode);
236
+ this._domNode.appendChild(this._verticalScrollbar.domNode.domNode);
237
+
238
+ if (this._options.useShadows) {
239
+ this._leftShadowDomNode = createFastDomNode(document.createElement('div'));
240
+ this._leftShadowDomNode.setClassName('shadow');
241
+ this._domNode.appendChild(this._leftShadowDomNode.domNode);
242
+
243
+ this._topShadowDomNode = createFastDomNode(document.createElement('div'));
244
+ this._topShadowDomNode.setClassName('shadow');
245
+ this._domNode.appendChild(this._topShadowDomNode.domNode);
246
+
247
+ this._topLeftShadowDomNode = createFastDomNode(document.createElement('div'));
248
+ this._topLeftShadowDomNode.setClassName('shadow');
249
+ this._domNode.appendChild(this._topLeftShadowDomNode.domNode);
250
+ } else {
251
+ this._leftShadowDomNode = null;
252
+ this._topShadowDomNode = null;
253
+ this._topLeftShadowDomNode = null;
254
+ }
255
+
256
+ this._listenOnDomNode = this._options.listenOnDomNode || this._domNode;
257
+
258
+ this._mouseWheelToDispose = [];
259
+ this._setListeningToMouseWheel(this._options.handleMouseWheel);
260
+
261
+ this.onmouseover(this._listenOnDomNode, (e) => this._onMouseOver(e));
262
+ this.onmouseleave(this._listenOnDomNode, (e) => this._onMouseLeave(e));
263
+
264
+ this._hideTimeout = this._register(new TimeoutTimer());
265
+ this._isDragging = false;
266
+ this._mouseIsOver = false;
267
+
268
+ this._shouldRender = true;
269
+
270
+ this._revealOnScroll = true;
271
+ }
272
+
273
+ public override dispose(): void {
274
+ this._mouseWheelToDispose = dispose(this._mouseWheelToDispose);
275
+ super.dispose();
276
+ }
277
+
278
+ /**
279
+ * Get the generated 'scrollable' dom node
280
+ */
281
+ public getDomNode(): HTMLElement {
282
+ return this._domNode;
283
+ }
284
+
285
+ public getOverviewRulerLayoutInfo(): IOverviewRulerLayoutInfo {
286
+ return {
287
+ parent: this._domNode,
288
+ insertBefore: this._verticalScrollbar.domNode.domNode,
289
+ };
290
+ }
291
+
292
+ /**
293
+ * Delegate a pointer down event to the vertical scrollbar.
294
+ * This is to help with clicking somewhere else and having the scrollbar react.
295
+ */
296
+ public delegateVerticalScrollbarPointerDown(browserEvent: PointerEvent): void {
297
+ this._verticalScrollbar.delegatePointerDown(browserEvent);
298
+ }
299
+
300
+ public getScrollDimensions(): IScrollDimensions {
301
+ return this._scrollable.getScrollDimensions();
302
+ }
303
+
304
+ public setScrollDimensions(dimensions: INewScrollDimensions): void {
305
+ this._scrollable.setScrollDimensions(dimensions, false);
306
+ }
307
+
308
+ /**
309
+ * Update the class name of the scrollable element.
310
+ */
311
+ public updateClassName(newClassName: string): void {
312
+ this._options.className = newClassName;
313
+ // Defaults are different on Macs
314
+ if (platform.isMacintosh) {
315
+ this._options.className += ' mac';
316
+ }
317
+ this._domNode.className = 'xterm-scrollable-element ' + this._options.className;
318
+ }
319
+
320
+ /**
321
+ * Update configuration options for the scrollbar.
322
+ */
323
+ public updateOptions(newOptions: ScrollableElementChangeOptions): void {
324
+ if (typeof newOptions.handleMouseWheel !== 'undefined') {
325
+ this._options.handleMouseWheel = newOptions.handleMouseWheel;
326
+ this._setListeningToMouseWheel(this._options.handleMouseWheel);
327
+ }
328
+ if (typeof newOptions.mouseWheelScrollSensitivity !== 'undefined') {
329
+ this._options.mouseWheelScrollSensitivity = newOptions.mouseWheelScrollSensitivity;
330
+ }
331
+ if (typeof newOptions.fastScrollSensitivity !== 'undefined') {
332
+ this._options.fastScrollSensitivity = newOptions.fastScrollSensitivity;
333
+ }
334
+ if (typeof newOptions.scrollPredominantAxis !== 'undefined') {
335
+ this._options.scrollPredominantAxis = newOptions.scrollPredominantAxis;
336
+ }
337
+ if (typeof newOptions.horizontal !== 'undefined') {
338
+ this._options.horizontal = newOptions.horizontal;
339
+ }
340
+ if (typeof newOptions.vertical !== 'undefined') {
341
+ this._options.vertical = newOptions.vertical;
342
+ }
343
+ if (typeof newOptions.horizontalScrollbarSize !== 'undefined') {
344
+ this._options.horizontalScrollbarSize = newOptions.horizontalScrollbarSize;
345
+ }
346
+ if (typeof newOptions.verticalScrollbarSize !== 'undefined') {
347
+ this._options.verticalScrollbarSize = newOptions.verticalScrollbarSize;
348
+ }
349
+ if (typeof newOptions.scrollByPage !== 'undefined') {
350
+ this._options.scrollByPage = newOptions.scrollByPage;
351
+ }
352
+ this._horizontalScrollbar.updateOptions(this._options);
353
+ this._verticalScrollbar.updateOptions(this._options);
354
+
355
+ if (!this._options.lazyRender) {
356
+ this._render();
357
+ }
358
+ }
359
+
360
+ public setRevealOnScroll(value: boolean) {
361
+ this._revealOnScroll = value;
362
+ }
363
+
364
+ public delegateScrollFromMouseWheelEvent(browserEvent: IMouseWheelEvent) {
365
+ this._onMouseWheel(new StandardWheelEvent(browserEvent));
366
+ }
367
+
368
+ // -------------------- mouse wheel scrolling --------------------
369
+
370
+ private _setListeningToMouseWheel(shouldListen: boolean): void {
371
+ const isListening = (this._mouseWheelToDispose.length > 0);
372
+
373
+ if (isListening === shouldListen) {
374
+ // No change
375
+ return;
376
+ }
377
+
378
+ // Stop listening (if necessary)
379
+ this._mouseWheelToDispose = dispose(this._mouseWheelToDispose);
380
+
381
+ // Start listening (if necessary)
382
+ if (shouldListen) {
383
+ const onMouseWheel = (browserEvent: IMouseWheelEvent) => {
384
+ this._onMouseWheel(new StandardWheelEvent(browserEvent));
385
+ };
386
+
387
+ this._mouseWheelToDispose.push(dom.addDisposableListener(this._listenOnDomNode, dom.EventType.MOUSE_WHEEL, onMouseWheel, { passive: false }));
388
+ }
389
+ }
390
+
391
+ private _onMouseWheel(e: StandardWheelEvent): void {
392
+ if (e.browserEvent?.defaultPrevented) {
393
+ return;
394
+ }
395
+
396
+ const classifier = MouseWheelClassifier.INSTANCE;
397
+ if (SCROLL_WHEEL_SMOOTH_SCROLL_ENABLED) {
398
+ classifier.acceptStandardWheelEvent(e);
399
+ }
400
+
401
+ // useful for creating unit tests:
402
+ // console.log(`${Date.now()}, ${e.deltaY}, ${e.deltaX}`);
403
+
404
+ let didScroll = false;
405
+
406
+ if (e.deltaY || e.deltaX) {
407
+ let deltaY = e.deltaY * this._options.mouseWheelScrollSensitivity;
408
+ let deltaX = e.deltaX * this._options.mouseWheelScrollSensitivity;
409
+
410
+ if (this._options.scrollPredominantAxis) {
411
+ if (this._options.scrollYToX && deltaX + deltaY === 0) {
412
+ // when configured to map Y to X and we both see
413
+ // no dominant axis and X and Y are competing with
414
+ // identical values into opposite directions, we
415
+ // ignore the delta as we cannot make a decision then
416
+ deltaX = deltaY = 0;
417
+ } else if (Math.abs(deltaY) >= Math.abs(deltaX)) {
418
+ deltaX = 0;
419
+ } else {
420
+ deltaY = 0;
421
+ }
422
+ }
423
+
424
+ if (this._options.flipAxes) {
425
+ [deltaY, deltaX] = [deltaX, deltaY];
426
+ }
427
+
428
+ // Convert vertical scrolling to horizontal if shift is held, this
429
+ // is handled at a higher level on Mac
430
+ const shiftConvert = !platform.isMacintosh && e.browserEvent && e.browserEvent.shiftKey;
431
+ if ((this._options.scrollYToX || shiftConvert) && !deltaX) {
432
+ deltaX = deltaY;
433
+ deltaY = 0;
434
+ }
435
+
436
+ if (e.browserEvent && e.browserEvent.altKey) {
437
+ // fastScrolling
438
+ deltaX = deltaX * this._options.fastScrollSensitivity;
439
+ deltaY = deltaY * this._options.fastScrollSensitivity;
440
+ }
441
+
442
+ const futureScrollPosition = this._scrollable.getFutureScrollPosition();
443
+
444
+ let desiredScrollPosition: INewScrollPosition = {};
445
+ if (deltaY) {
446
+ const deltaScrollTop = SCROLL_WHEEL_SENSITIVITY * deltaY;
447
+ // Here we convert values such as -0.3 to -1 or 0.3 to 1, otherwise low speed scrolling will never scroll
448
+ const desiredScrollTop = futureScrollPosition.scrollTop - (deltaScrollTop < 0 ? Math.floor(deltaScrollTop) : Math.ceil(deltaScrollTop));
449
+ this._verticalScrollbar.writeScrollPosition(desiredScrollPosition, desiredScrollTop);
450
+ }
451
+ if (deltaX) {
452
+ const deltaScrollLeft = SCROLL_WHEEL_SENSITIVITY * deltaX;
453
+ // Here we convert values such as -0.3 to -1 or 0.3 to 1, otherwise low speed scrolling will never scroll
454
+ const desiredScrollLeft = futureScrollPosition.scrollLeft - (deltaScrollLeft < 0 ? Math.floor(deltaScrollLeft) : Math.ceil(deltaScrollLeft));
455
+ this._horizontalScrollbar.writeScrollPosition(desiredScrollPosition, desiredScrollLeft);
456
+ }
457
+
458
+ // Check that we are scrolling towards a location which is valid
459
+ desiredScrollPosition = this._scrollable.validateScrollPosition(desiredScrollPosition);
460
+
461
+ if (futureScrollPosition.scrollLeft !== desiredScrollPosition.scrollLeft || futureScrollPosition.scrollTop !== desiredScrollPosition.scrollTop) {
462
+
463
+ const canPerformSmoothScroll = (
464
+ SCROLL_WHEEL_SMOOTH_SCROLL_ENABLED
465
+ && this._options.mouseWheelSmoothScroll
466
+ && classifier.isPhysicalMouseWheel()
467
+ );
468
+
469
+ if (canPerformSmoothScroll) {
470
+ this._scrollable.setScrollPositionSmooth(desiredScrollPosition);
471
+ } else {
472
+ this._scrollable.setScrollPositionNow(desiredScrollPosition);
473
+ }
474
+
475
+ didScroll = true;
476
+ }
477
+ }
478
+
479
+ let consumeMouseWheel = didScroll;
480
+ if (!consumeMouseWheel && this._options.alwaysConsumeMouseWheel) {
481
+ consumeMouseWheel = true;
482
+ }
483
+ if (!consumeMouseWheel && this._options.consumeMouseWheelIfScrollbarIsNeeded && (this._verticalScrollbar.isNeeded() || this._horizontalScrollbar.isNeeded())) {
484
+ consumeMouseWheel = true;
485
+ }
486
+
487
+ if (consumeMouseWheel) {
488
+ e.preventDefault();
489
+ e.stopPropagation();
490
+ }
491
+ }
492
+
493
+ private _onDidScroll(e: ScrollEvent): void {
494
+ this._shouldRender = this._horizontalScrollbar.onDidScroll(e) || this._shouldRender;
495
+ this._shouldRender = this._verticalScrollbar.onDidScroll(e) || this._shouldRender;
496
+
497
+ if (this._options.useShadows) {
498
+ this._shouldRender = true;
499
+ }
500
+
501
+ if (this._revealOnScroll) {
502
+ this._reveal();
503
+ }
504
+
505
+ if (!this._options.lazyRender) {
506
+ this._render();
507
+ }
508
+ }
509
+
510
+ /**
511
+ * Render / mutate the DOM now.
512
+ * Should be used together with the ctor option `lazyRender`.
513
+ */
514
+ public renderNow(): void {
515
+ if (!this._options.lazyRender) {
516
+ throw new Error('Please use `lazyRender` together with `renderNow`!');
517
+ }
518
+
519
+ this._render();
520
+ }
521
+
522
+ private _render(): void {
523
+ if (!this._shouldRender) {
524
+ return;
525
+ }
526
+
527
+ this._shouldRender = false;
528
+
529
+ this._horizontalScrollbar.render();
530
+ this._verticalScrollbar.render();
531
+
532
+ if (this._options.useShadows) {
533
+ const scrollState = this._scrollable.getCurrentScrollPosition();
534
+ const enableTop = scrollState.scrollTop > 0;
535
+ const enableLeft = scrollState.scrollLeft > 0;
536
+
537
+ const leftClassName = (enableLeft ? ' left' : '');
538
+ const topClassName = (enableTop ? ' top' : '');
539
+ const topLeftClassName = (enableLeft || enableTop ? ' top-left-corner' : '');
540
+ this._leftShadowDomNode!.setClassName(`shadow${leftClassName}`);
541
+ this._topShadowDomNode!.setClassName(`shadow${topClassName}`);
542
+ this._topLeftShadowDomNode!.setClassName(`shadow${topLeftClassName}${topClassName}${leftClassName}`);
543
+ }
544
+ }
545
+
546
+ // -------------------- fade in / fade out --------------------
547
+
548
+ private _onDragStart(): void {
549
+ this._isDragging = true;
550
+ this._reveal();
551
+ }
552
+
553
+ private _onDragEnd(): void {
554
+ this._isDragging = false;
555
+ this._hide();
556
+ }
557
+
558
+ private _onMouseLeave(e: IMouseEvent): void {
559
+ this._mouseIsOver = false;
560
+ this._hide();
561
+ }
562
+
563
+ private _onMouseOver(e: IMouseEvent): void {
564
+ this._mouseIsOver = true;
565
+ this._reveal();
566
+ }
567
+
568
+ private _reveal(): void {
569
+ this._verticalScrollbar.beginReveal();
570
+ this._horizontalScrollbar.beginReveal();
571
+ this._scheduleHide();
572
+ }
573
+
574
+ private _hide(): void {
575
+ if (!this._mouseIsOver && !this._isDragging) {
576
+ this._verticalScrollbar.beginHide();
577
+ this._horizontalScrollbar.beginHide();
578
+ }
579
+ }
580
+
581
+ private _scheduleHide(): void {
582
+ if (!this._mouseIsOver && !this._isDragging) {
583
+ this._hideTimeout.cancelAndSet(() => this._hide(), HIDE_TIMEOUT);
584
+ }
585
+ }
586
+ }
587
+
588
+ export class ScrollableElement extends AbstractScrollableElement {
589
+
590
+ constructor(element: HTMLElement, options: ScrollableElementCreationOptions) {
591
+ options = options || {};
592
+ options.mouseWheelSmoothScroll = false;
593
+ const scrollable = new Scrollable({
594
+ forceIntegerValues: true,
595
+ smoothScrollDuration: 0,
596
+ scheduleAtNextAnimationFrame: (callback) => dom.scheduleAtNextAnimationFrame(dom.getWindow(element), callback)
597
+ });
598
+ super(element, options, scrollable);
599
+ this._register(scrollable);
600
+ }
601
+
602
+ public setScrollPosition(update: INewScrollPosition): void {
603
+ this._scrollable.setScrollPositionNow(update);
604
+ }
605
+
606
+ public getScrollPosition(): IScrollPosition {
607
+ return this._scrollable.getCurrentScrollPosition();
608
+ }
609
+ }
610
+
611
+ export class SmoothScrollableElement extends AbstractScrollableElement {
612
+
613
+ constructor(element: HTMLElement, options: ScrollableElementCreationOptions, scrollable: Scrollable) {
614
+ super(element, options, scrollable);
615
+ }
616
+
617
+ public setScrollPosition(update: INewScrollPosition & { reuseAnimation?: boolean }): void {
618
+ if (update.reuseAnimation) {
619
+ this._scrollable.setScrollPositionSmooth(update, update.reuseAnimation);
620
+ } else {
621
+ this._scrollable.setScrollPositionNow(update);
622
+ }
623
+ }
624
+
625
+ public getScrollPosition(): IScrollPosition {
626
+ return this._scrollable.getCurrentScrollPosition();
627
+ }
628
+
629
+ }
630
+
631
+ export class DomScrollableElement extends AbstractScrollableElement {
632
+
633
+ private _element: HTMLElement;
634
+
635
+ constructor(element: HTMLElement, options: ScrollableElementCreationOptions) {
636
+ options = options || {};
637
+ options.mouseWheelSmoothScroll = false;
638
+ const scrollable = new Scrollable({
639
+ forceIntegerValues: false, // See https://github.com/microsoft/vscode/issues/139877
640
+ smoothScrollDuration: 0,
641
+ scheduleAtNextAnimationFrame: (callback) => dom.scheduleAtNextAnimationFrame(dom.getWindow(element), callback)
642
+ });
643
+ super(element, options, scrollable);
644
+ this._register(scrollable);
645
+ this._element = element;
646
+ this._register(this.onScroll((e) => {
647
+ if (e.scrollTopChanged) {
648
+ this._element.scrollTop = e.scrollTop;
649
+ }
650
+ if (e.scrollLeftChanged) {
651
+ this._element.scrollLeft = e.scrollLeft;
652
+ }
653
+ }));
654
+ this.scanDomNode();
655
+ }
656
+
657
+ public setScrollPosition(update: INewScrollPosition): void {
658
+ this._scrollable.setScrollPositionNow(update);
659
+ }
660
+
661
+ public getScrollPosition(): IScrollPosition {
662
+ return this._scrollable.getCurrentScrollPosition();
663
+ }
664
+
665
+ public scanDomNode(): void {
666
+ // width, scrollLeft, scrollWidth, height, scrollTop, scrollHeight
667
+ this.setScrollDimensions({
668
+ width: this._element.clientWidth,
669
+ scrollWidth: this._element.scrollWidth,
670
+ height: this._element.clientHeight,
671
+ scrollHeight: this._element.scrollHeight
672
+ });
673
+ this.setScrollPosition({
674
+ scrollLeft: this._element.scrollLeft,
675
+ scrollTop: this._element.scrollTop,
676
+ });
677
+ }
678
+ }
679
+
680
+ function resolveOptions(opts: ScrollableElementCreationOptions): ScrollableElementResolvedOptions {
681
+ const result: ScrollableElementResolvedOptions = {
682
+ lazyRender: (typeof opts.lazyRender !== 'undefined' ? opts.lazyRender : false),
683
+ className: (typeof opts.className !== 'undefined' ? opts.className : ''),
684
+ useShadows: (typeof opts.useShadows !== 'undefined' ? opts.useShadows : true),
685
+ handleMouseWheel: (typeof opts.handleMouseWheel !== 'undefined' ? opts.handleMouseWheel : true),
686
+ flipAxes: (typeof opts.flipAxes !== 'undefined' ? opts.flipAxes : false),
687
+ consumeMouseWheelIfScrollbarIsNeeded: (typeof opts.consumeMouseWheelIfScrollbarIsNeeded !== 'undefined' ? opts.consumeMouseWheelIfScrollbarIsNeeded : false),
688
+ alwaysConsumeMouseWheel: (typeof opts.alwaysConsumeMouseWheel !== 'undefined' ? opts.alwaysConsumeMouseWheel : false),
689
+ scrollYToX: (typeof opts.scrollYToX !== 'undefined' ? opts.scrollYToX : false),
690
+ mouseWheelScrollSensitivity: (typeof opts.mouseWheelScrollSensitivity !== 'undefined' ? opts.mouseWheelScrollSensitivity : 1),
691
+ fastScrollSensitivity: (typeof opts.fastScrollSensitivity !== 'undefined' ? opts.fastScrollSensitivity : 5),
692
+ scrollPredominantAxis: (typeof opts.scrollPredominantAxis !== 'undefined' ? opts.scrollPredominantAxis : true),
693
+ mouseWheelSmoothScroll: (typeof opts.mouseWheelSmoothScroll !== 'undefined' ? opts.mouseWheelSmoothScroll : true),
694
+ arrowSize: (typeof opts.arrowSize !== 'undefined' ? opts.arrowSize : 11),
695
+
696
+ listenOnDomNode: (typeof opts.listenOnDomNode !== 'undefined' ? opts.listenOnDomNode : null),
697
+
698
+ horizontal: (typeof opts.horizontal !== 'undefined' ? opts.horizontal : ScrollbarVisibility.Auto),
699
+ horizontalScrollbarSize: (typeof opts.horizontalScrollbarSize !== 'undefined' ? opts.horizontalScrollbarSize : 10),
700
+ horizontalSliderSize: (typeof opts.horizontalSliderSize !== 'undefined' ? opts.horizontalSliderSize : 0),
701
+ horizontalHasArrows: (typeof opts.horizontalHasArrows !== 'undefined' ? opts.horizontalHasArrows : false),
702
+
703
+ vertical: (typeof opts.vertical !== 'undefined' ? opts.vertical : ScrollbarVisibility.Auto),
704
+ verticalScrollbarSize: (typeof opts.verticalScrollbarSize !== 'undefined' ? opts.verticalScrollbarSize : 10),
705
+ verticalHasArrows: (typeof opts.verticalHasArrows !== 'undefined' ? opts.verticalHasArrows : false),
706
+ verticalSliderSize: (typeof opts.verticalSliderSize !== 'undefined' ? opts.verticalSliderSize : 0),
707
+
708
+ scrollByPage: (typeof opts.scrollByPage !== 'undefined' ? opts.scrollByPage : false)
709
+ };
710
+
711
+ result.horizontalSliderSize = (typeof opts.horizontalSliderSize !== 'undefined' ? opts.horizontalSliderSize : result.horizontalScrollbarSize);
712
+ result.verticalSliderSize = (typeof opts.verticalSliderSize !== 'undefined' ? opts.verticalSliderSize : result.verticalScrollbarSize);
713
+
714
+ // Defaults are different on Macs
715
+ if (platform.isMacintosh) {
716
+ result.className += ' mac';
717
+ }
718
+
719
+ return result;
720
+ }