@xterm/xterm 6.1.0-beta.28 → 6.1.0-beta.281
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/README.md +62 -38
- package/css/xterm.css +29 -22
- package/lib/xterm.js +1 -1
- package/lib/xterm.js.map +1 -1
- package/lib/xterm.mjs +8 -34
- package/lib/xterm.mjs.map +4 -4
- package/package.json +56 -45
- package/src/browser/AccessibilityManager.ts +18 -13
- package/src/browser/Clipboard.ts +8 -5
- package/src/browser/ColorContrastCache.ts +3 -3
- package/src/browser/CoreBrowserTerminal.ts +179 -348
- package/src/browser/Dom.ts +178 -0
- package/src/browser/Linkifier.ts +14 -14
- package/src/browser/OscLinkProvider.ts +86 -18
- package/src/browser/RenderDebouncer.ts +7 -9
- package/src/browser/TimeBasedDebouncer.ts +12 -5
- package/src/browser/Types.ts +16 -14
- package/src/browser/Viewport.ts +58 -23
- package/src/browser/decorations/BufferDecorationRenderer.ts +3 -3
- package/src/browser/decorations/ColorZoneStore.ts +1 -1
- package/src/browser/decorations/OverviewRulerRenderer.ts +36 -20
- package/src/browser/input/CompositionHelper.ts +47 -11
- package/src/browser/input/Mouse.ts +5 -9
- package/src/browser/input/MoveToCell.ts +3 -3
- package/src/browser/public/Terminal.ts +33 -36
- package/src/browser/renderer/dom/DomRenderer.ts +265 -89
- package/src/browser/renderer/dom/DomRendererRowFactory.ts +34 -27
- package/src/browser/renderer/dom/WidthCache.ts +57 -55
- package/src/browser/renderer/shared/Constants.ts +7 -0
- package/src/browser/renderer/shared/RendererUtils.ts +1 -1
- package/src/browser/renderer/shared/SelectionRenderModel.ts +2 -2
- package/src/browser/renderer/shared/TextBlinkStateManager.ts +97 -0
- package/src/browser/renderer/shared/Types.ts +10 -4
- package/src/browser/scrollable/abstractScrollbar.ts +300 -0
- package/src/browser/scrollable/fastDomNode.ts +126 -0
- package/src/browser/scrollable/globalPointerMoveMonitor.ts +90 -0
- package/src/browser/scrollable/horizontalScrollbar.ts +85 -0
- package/src/browser/scrollable/mouseEvent.ts +292 -0
- package/src/browser/scrollable/scrollable.ts +486 -0
- package/src/browser/scrollable/scrollableElement.ts +581 -0
- package/src/browser/scrollable/scrollableElementOptions.ts +161 -0
- package/src/browser/scrollable/scrollbarArrow.ts +110 -0
- package/src/browser/scrollable/scrollbarState.ts +246 -0
- package/src/browser/scrollable/scrollbarVisibilityController.ts +113 -0
- package/src/browser/scrollable/touch.ts +485 -0
- package/src/browser/scrollable/verticalScrollbar.ts +143 -0
- package/src/browser/scrollable/widget.ts +23 -0
- package/src/browser/selection/SelectionModel.ts +1 -1
- package/src/browser/services/CharSizeService.ts +4 -4
- package/src/browser/services/CharacterJoinerService.ts +13 -11
- package/src/browser/services/CoreBrowserService.ts +7 -5
- package/src/browser/services/KeyboardService.ts +67 -0
- package/src/browser/services/LinkProviderService.ts +3 -3
- package/src/browser/services/MouseCoordsService.ts +47 -0
- package/src/browser/services/MouseService.ts +619 -23
- package/src/browser/services/RenderService.ts +33 -21
- package/src/browser/services/SelectionService.ts +72 -54
- package/src/browser/services/Services.ts +44 -21
- package/src/browser/services/ThemeService.ts +9 -9
- package/src/common/Async.ts +141 -0
- package/src/common/CircularList.ts +24 -3
- package/src/common/Color.ts +13 -5
- package/src/common/CoreTerminal.ts +61 -35
- package/src/common/Event.ts +118 -0
- package/src/common/InputHandler.ts +286 -105
- package/src/common/Lifecycle.ts +113 -0
- package/src/common/Platform.ts +15 -5
- package/src/common/SortedList.ts +8 -4
- package/src/common/StringBuilder.ts +67 -0
- package/src/common/TaskQueue.ts +17 -8
- package/src/common/Types.ts +68 -206
- package/src/common/Version.ts +1 -1
- package/src/common/WindowsMode.ts +2 -2
- package/src/common/buffer/AttributeData.ts +3 -2
- package/src/common/buffer/Buffer.ts +47 -32
- package/src/common/buffer/BufferLine.ts +175 -100
- package/src/common/buffer/BufferLineStringCache.ts +69 -0
- package/src/common/buffer/BufferReflow.ts +7 -4
- package/src/common/buffer/BufferSet.ts +13 -9
- package/src/common/buffer/CellData.ts +61 -4
- package/src/common/buffer/Constants.ts +13 -13
- package/src/common/buffer/Marker.ts +4 -4
- package/src/common/buffer/Types.ts +153 -3
- package/src/common/data/Charsets.ts +4 -7
- package/src/common/data/EscapeSequences.ts +71 -70
- package/src/common/input/Keyboard.ts +17 -10
- package/src/common/input/KittyKeyboard.ts +526 -0
- package/src/common/input/TextDecoder.ts +3 -3
- package/src/common/input/UnicodeV6.ts +3 -2
- package/src/common/input/Win32InputMode.ts +297 -0
- package/src/common/input/WriteBuffer.ts +108 -39
- package/src/common/input/XParseColor.ts +2 -2
- package/src/common/parser/ApcParser.ts +196 -0
- package/src/common/parser/Constants.ts +14 -4
- package/src/common/parser/DcsParser.ts +15 -16
- package/src/common/parser/EscapeSequenceParser.ts +214 -72
- package/src/common/parser/OscParser.ts +14 -15
- package/src/common/parser/Params.ts +31 -12
- package/src/common/parser/Types.ts +40 -30
- package/src/common/public/BufferApiView.ts +3 -3
- package/src/common/public/BufferLineApiView.ts +4 -4
- package/src/common/public/BufferNamespaceApi.ts +5 -5
- package/src/common/public/ParserApi.ts +5 -2
- package/src/common/public/UnicodeApi.ts +1 -1
- package/src/common/services/BufferService.ts +17 -13
- package/src/common/services/CharsetService.ts +6 -2
- package/src/common/services/CoreService.ts +23 -10
- package/src/common/services/DecorationService.ts +260 -15
- package/src/common/services/InstantiationService.ts +2 -2
- package/src/common/services/LogService.ts +2 -32
- package/src/common/services/{CoreMouseService.ts → MouseStateService.ts} +22 -133
- package/src/common/services/OptionsService.ts +17 -7
- package/src/common/services/OscLinkService.ts +3 -2
- package/src/common/services/ServiceRegistry.ts +14 -8
- package/src/common/services/Services.ts +54 -50
- package/src/common/services/UnicodeService.ts +6 -11
- package/typings/xterm.d.ts +329 -34
- package/src/common/Clone.ts +0 -23
- package/src/common/TypedArrayUtils.ts +0 -17
- package/src/vs/base/browser/browser.ts +0 -141
- package/src/vs/base/browser/canIUse.ts +0 -49
- package/src/vs/base/browser/dom.ts +0 -2369
- package/src/vs/base/browser/fastDomNode.ts +0 -316
- package/src/vs/base/browser/globalPointerMoveMonitor.ts +0 -112
- package/src/vs/base/browser/iframe.ts +0 -135
- package/src/vs/base/browser/keyboardEvent.ts +0 -213
- package/src/vs/base/browser/mouseEvent.ts +0 -229
- package/src/vs/base/browser/touch.ts +0 -372
- package/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts +0 -303
- package/src/vs/base/browser/ui/scrollbar/horizontalScrollbar.ts +0 -114
- package/src/vs/base/browser/ui/scrollbar/scrollableElement.ts +0 -720
- package/src/vs/base/browser/ui/scrollbar/scrollableElementOptions.ts +0 -165
- package/src/vs/base/browser/ui/scrollbar/scrollbarArrow.ts +0 -114
- package/src/vs/base/browser/ui/scrollbar/scrollbarState.ts +0 -243
- package/src/vs/base/browser/ui/scrollbar/scrollbarVisibilityController.ts +0 -118
- package/src/vs/base/browser/ui/scrollbar/verticalScrollbar.ts +0 -116
- package/src/vs/base/browser/ui/widget.ts +0 -57
- package/src/vs/base/browser/window.ts +0 -14
- package/src/vs/base/common/arrays.ts +0 -887
- package/src/vs/base/common/arraysFind.ts +0 -202
- package/src/vs/base/common/assert.ts +0 -71
- package/src/vs/base/common/async.ts +0 -1992
- package/src/vs/base/common/cancellation.ts +0 -148
- package/src/vs/base/common/charCode.ts +0 -450
- package/src/vs/base/common/collections.ts +0 -140
- package/src/vs/base/common/decorators.ts +0 -130
- package/src/vs/base/common/equals.ts +0 -146
- package/src/vs/base/common/errors.ts +0 -303
- package/src/vs/base/common/event.ts +0 -1778
- package/src/vs/base/common/functional.ts +0 -32
- package/src/vs/base/common/hash.ts +0 -316
- package/src/vs/base/common/iterator.ts +0 -159
- package/src/vs/base/common/keyCodes.ts +0 -526
- package/src/vs/base/common/keybindings.ts +0 -284
- package/src/vs/base/common/lazy.ts +0 -47
- package/src/vs/base/common/lifecycle.ts +0 -801
- package/src/vs/base/common/linkedList.ts +0 -142
- package/src/vs/base/common/map.ts +0 -202
- package/src/vs/base/common/numbers.ts +0 -98
- package/src/vs/base/common/observable.ts +0 -76
- package/src/vs/base/common/observableInternal/api.ts +0 -31
- package/src/vs/base/common/observableInternal/autorun.ts +0 -281
- package/src/vs/base/common/observableInternal/base.ts +0 -489
- package/src/vs/base/common/observableInternal/debugName.ts +0 -145
- package/src/vs/base/common/observableInternal/derived.ts +0 -428
- package/src/vs/base/common/observableInternal/lazyObservableValue.ts +0 -146
- package/src/vs/base/common/observableInternal/logging.ts +0 -328
- package/src/vs/base/common/observableInternal/promise.ts +0 -209
- package/src/vs/base/common/observableInternal/utils.ts +0 -610
- package/src/vs/base/common/platform.ts +0 -281
- package/src/vs/base/common/scrollable.ts +0 -522
- package/src/vs/base/common/sequence.ts +0 -34
- package/src/vs/base/common/stopwatch.ts +0 -43
- package/src/vs/base/common/strings.ts +0 -557
- package/src/vs/base/common/symbols.ts +0 -9
- package/src/vs/base/common/uint.ts +0 -59
- package/src/vs/patches/nls.ts +0 -90
- package/src/vs/typings/base-common.d.ts +0 -20
- package/src/vs/typings/require.d.ts +0 -42
- package/src/vs/typings/vscode-globals-nls.d.ts +0 -36
- package/src/vs/typings/vscode-globals-product.d.ts +0 -33
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*
|
|
5
|
+
* Minimal DOM helpers for xterm.js browser code.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { IntervalTimer } from '../common/Async';
|
|
9
|
+
import { IDisposable } from '../common/Lifecycle';
|
|
10
|
+
|
|
11
|
+
export function getWindow(e: Node | UIEvent | undefined | null): Window {
|
|
12
|
+
const candidateNode = e as Node | undefined | null;
|
|
13
|
+
if (candidateNode?.ownerDocument?.defaultView) {
|
|
14
|
+
return candidateNode.ownerDocument.defaultView;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const candidateEvent = e as UIEvent | undefined | null;
|
|
18
|
+
if (candidateEvent?.view) {
|
|
19
|
+
return candidateEvent.view;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return window;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
class DomListener implements IDisposable {
|
|
26
|
+
private _handler: ((e: any) => void) | null;
|
|
27
|
+
private _node: EventTarget | null;
|
|
28
|
+
private readonly _type: string;
|
|
29
|
+
private readonly _options: boolean | AddEventListenerOptions | undefined;
|
|
30
|
+
|
|
31
|
+
constructor(node: EventTarget, type: string, handler: (e: any) => void, options?: boolean | AddEventListenerOptions) {
|
|
32
|
+
this._node = node;
|
|
33
|
+
this._type = type;
|
|
34
|
+
this._handler = handler;
|
|
35
|
+
this._options = options;
|
|
36
|
+
node.addEventListener(type, handler, options);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public dispose(): void {
|
|
40
|
+
if (!this._node || !this._handler) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
this._node.removeEventListener(this._type, this._handler, this._options);
|
|
44
|
+
this._node = null;
|
|
45
|
+
this._handler = null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function addDisposableListener<K extends keyof GlobalEventHandlersEventMap>(node: EventTarget, type: K, handler: (event: GlobalEventHandlersEventMap[K]) => void, useCapture?: boolean): IDisposable;
|
|
50
|
+
export function addDisposableListener(node: EventTarget, type: string, handler: (event: any) => void, useCapture?: boolean): IDisposable;
|
|
51
|
+
export function addDisposableListener(node: EventTarget, type: string, handler: (event: any) => void, options: AddEventListenerOptions): IDisposable;
|
|
52
|
+
export function addDisposableListener(node: EventTarget, type: string, handler: (event: any) => void, useCaptureOrOptions?: boolean | AddEventListenerOptions): IDisposable {
|
|
53
|
+
return new DomListener(node, type, handler, useCaptureOrOptions);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function addStandardDisposableListener(node: HTMLElement, type: string, handler: (event: any) => void, useCapture?: boolean): IDisposable {
|
|
57
|
+
return addDisposableListener(node, type, handler, useCapture);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export const eventType = {
|
|
61
|
+
CLICK: 'click',
|
|
62
|
+
MOUSE_DOWN: 'mousedown',
|
|
63
|
+
MOUSE_OVER: 'mouseover',
|
|
64
|
+
MOUSE_LEAVE: 'mouseleave',
|
|
65
|
+
KEY_DOWN: 'keydown',
|
|
66
|
+
KEY_UP: 'keyup',
|
|
67
|
+
INPUT: 'input',
|
|
68
|
+
BLUR: 'blur',
|
|
69
|
+
FOCUS: 'focus',
|
|
70
|
+
CHANGE: 'change',
|
|
71
|
+
POINTER_DOWN: 'pointerdown',
|
|
72
|
+
POINTER_MOVE: 'pointermove',
|
|
73
|
+
POINTER_UP: 'pointerup',
|
|
74
|
+
MOUSE_WHEEL: 'wheel',
|
|
75
|
+
WHEEL: 'wheel'
|
|
76
|
+
} as const;
|
|
77
|
+
|
|
78
|
+
export function getDomNodePagePosition(domNode: HTMLElement): { left: number, top: number, width: number, height: number } {
|
|
79
|
+
const bb = domNode.getBoundingClientRect();
|
|
80
|
+
const win = getWindow(domNode);
|
|
81
|
+
return {
|
|
82
|
+
left: bb.left + win.scrollX,
|
|
83
|
+
top: bb.top + win.scrollY,
|
|
84
|
+
width: bb.width,
|
|
85
|
+
height: bb.height
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
class AnimationFrameQueueItem implements IDisposable {
|
|
90
|
+
private _canceled = false;
|
|
91
|
+
|
|
92
|
+
constructor(private readonly _runner: () => void, public priority: number) {
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public dispose(): void {
|
|
96
|
+
this._canceled = true;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public execute(): void {
|
|
100
|
+
if (this._canceled) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
this._runner();
|
|
105
|
+
} catch (e) {
|
|
106
|
+
console.error(e);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
public static sort(a: AnimationFrameQueueItem, b: AnimationFrameQueueItem): number {
|
|
111
|
+
return b.priority - a.priority;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
interface IWindowAnimationFrameState {
|
|
116
|
+
next: AnimationFrameQueueItem[];
|
|
117
|
+
current: AnimationFrameQueueItem[];
|
|
118
|
+
animFrameRequested: boolean;
|
|
119
|
+
inAnimationFrameRunner: boolean;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const animationFrameState = new Map<Window, IWindowAnimationFrameState>();
|
|
123
|
+
|
|
124
|
+
function getAnimationFrameState(targetWindow: Window): IWindowAnimationFrameState {
|
|
125
|
+
let state = animationFrameState.get(targetWindow);
|
|
126
|
+
if (!state) {
|
|
127
|
+
state = {
|
|
128
|
+
next: [],
|
|
129
|
+
current: [],
|
|
130
|
+
animFrameRequested: false,
|
|
131
|
+
inAnimationFrameRunner: false
|
|
132
|
+
};
|
|
133
|
+
animationFrameState.set(targetWindow, state);
|
|
134
|
+
}
|
|
135
|
+
return state;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function animationFrameRunner(targetWindow: Window): void {
|
|
139
|
+
const state = getAnimationFrameState(targetWindow);
|
|
140
|
+
state.animFrameRequested = false;
|
|
141
|
+
|
|
142
|
+
state.current = state.next;
|
|
143
|
+
state.next = [];
|
|
144
|
+
|
|
145
|
+
state.inAnimationFrameRunner = true;
|
|
146
|
+
while (state.current.length > 0) {
|
|
147
|
+
state.current.sort(AnimationFrameQueueItem.sort);
|
|
148
|
+
const top = state.current.shift()!;
|
|
149
|
+
top.execute();
|
|
150
|
+
}
|
|
151
|
+
state.inAnimationFrameRunner = false;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function scheduleAtNextAnimationFrame(targetWindow: Window, runner: () => void, priority: number = 0): IDisposable {
|
|
155
|
+
const state = getAnimationFrameState(targetWindow);
|
|
156
|
+
const item = new AnimationFrameQueueItem(runner, priority);
|
|
157
|
+
state.next.push(item);
|
|
158
|
+
|
|
159
|
+
if (!state.animFrameRequested) {
|
|
160
|
+
state.animFrameRequested = true;
|
|
161
|
+
targetWindow.requestAnimationFrame(() => animationFrameRunner(targetWindow));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return item;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export class WindowIntervalTimer extends IntervalTimer {
|
|
168
|
+
private readonly _defaultTarget?: Window;
|
|
169
|
+
|
|
170
|
+
constructor(node?: Node) {
|
|
171
|
+
super();
|
|
172
|
+
this._defaultTarget = node ? getWindow(node) : undefined;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
public cancelAndSet(runner: () => void, interval: number, targetWindow?: Window): void {
|
|
176
|
+
super.cancelAndSet(runner, interval, targetWindow ?? this._defaultTarget ?? window);
|
|
177
|
+
}
|
|
178
|
+
}
|
package/src/browser/Linkifier.ts
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
* @license MIT
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { IBufferCellPosition, ILink, ILinkDecorations, ILinkWithState, ILinkifier2, ILinkifierEvent } from '
|
|
7
|
-
import { Disposable, dispose, toDisposable } from '
|
|
8
|
-
import { IDisposable } from 'common/Types';
|
|
9
|
-
import { IBufferService } from 'common/services/Services';
|
|
10
|
-
import { ILinkProviderService,
|
|
11
|
-
import { Emitter } from '
|
|
12
|
-
import { addDisposableListener } from '
|
|
6
|
+
import { IBufferCellPosition, ILink, ILinkDecorations, ILinkWithState, ILinkifier2, ILinkifierEvent } from './Types';
|
|
7
|
+
import { Disposable, dispose, toDisposable } from '../common/Lifecycle';
|
|
8
|
+
import { IDisposable } from '../common/Types';
|
|
9
|
+
import { IBufferService } from '../common/services/Services';
|
|
10
|
+
import { ILinkProviderService, IMouseCoordsService, IRenderService } from './services/Services';
|
|
11
|
+
import { Emitter } from '../common/Event';
|
|
12
|
+
import { addDisposableListener } from './Dom';
|
|
13
13
|
|
|
14
14
|
export class Linkifier extends Disposable implements ILinkifier2 {
|
|
15
15
|
public get currentLink(): ILinkWithState | undefined { return this._currentLink; }
|
|
@@ -30,7 +30,7 @@ export class Linkifier extends Disposable implements ILinkifier2 {
|
|
|
30
30
|
|
|
31
31
|
constructor(
|
|
32
32
|
private readonly _element: HTMLElement,
|
|
33
|
-
@
|
|
33
|
+
@IMouseCoordsService private readonly _mouseCoordsService: IMouseCoordsService,
|
|
34
34
|
@IRenderService private readonly _renderService: IRenderService,
|
|
35
35
|
@IBufferService private readonly _bufferService: IBufferService,
|
|
36
36
|
@ILinkProviderService private readonly _linkProviderService: ILinkProviderService
|
|
@@ -60,7 +60,7 @@ export class Linkifier extends Disposable implements ILinkifier2 {
|
|
|
60
60
|
private _handleMouseMove(event: MouseEvent): void {
|
|
61
61
|
this._lastMouseEvent = event;
|
|
62
62
|
|
|
63
|
-
const position = this._positionFromMouseEvent(event, this._element
|
|
63
|
+
const position = this._positionFromMouseEvent(event, this._element);
|
|
64
64
|
if (!position) {
|
|
65
65
|
return;
|
|
66
66
|
}
|
|
@@ -222,7 +222,7 @@ export class Linkifier extends Disposable implements ILinkifier2 {
|
|
|
222
222
|
return;
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
-
const position = this._positionFromMouseEvent(event, this._element
|
|
225
|
+
const position = this._positionFromMouseEvent(event, this._element);
|
|
226
226
|
if (!position) {
|
|
227
227
|
return;
|
|
228
228
|
}
|
|
@@ -251,7 +251,7 @@ export class Linkifier extends Disposable implements ILinkifier2 {
|
|
|
251
251
|
return;
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
-
const position = this._positionFromMouseEvent(this._lastMouseEvent, this._element
|
|
254
|
+
const position = this._positionFromMouseEvent(this._lastMouseEvent, this._element);
|
|
255
255
|
|
|
256
256
|
if (!position) {
|
|
257
257
|
return;
|
|
@@ -312,7 +312,7 @@ export class Linkifier extends Disposable implements ILinkifier2 {
|
|
|
312
312
|
this._clearCurrentLink(start, end);
|
|
313
313
|
if (this._lastMouseEvent) {
|
|
314
314
|
// re-eval previously active link after changes
|
|
315
|
-
const position = this._positionFromMouseEvent(this._lastMouseEvent, this._element
|
|
315
|
+
const position = this._positionFromMouseEvent(this._lastMouseEvent, this._element);
|
|
316
316
|
if (position) {
|
|
317
317
|
this._askForLink(position, false);
|
|
318
318
|
}
|
|
@@ -378,8 +378,8 @@ export class Linkifier extends Disposable implements ILinkifier2 {
|
|
|
378
378
|
* Get the buffer position from a mouse event
|
|
379
379
|
* @param event
|
|
380
380
|
*/
|
|
381
|
-
private _positionFromMouseEvent(event: MouseEvent, element: HTMLElement
|
|
382
|
-
const coords =
|
|
381
|
+
private _positionFromMouseEvent(event: MouseEvent, element: HTMLElement): IBufferCellPosition | undefined {
|
|
382
|
+
const coords = this._mouseCoordsService.getCoords(event, element, this._bufferService.cols, this._bufferService.rows);
|
|
383
383
|
if (!coords) {
|
|
384
384
|
return;
|
|
385
385
|
}
|
|
@@ -3,12 +3,15 @@
|
|
|
3
3
|
* @license MIT
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { IBufferRange, ILink } from '
|
|
7
|
-
import { ILinkProvider } from '
|
|
8
|
-
import { CellData } from 'common/buffer/CellData';
|
|
9
|
-
import {
|
|
6
|
+
import { IBufferRange, ILink } from './Types';
|
|
7
|
+
import { ILinkProvider } from './services/Services';
|
|
8
|
+
import { CellData } from '../common/buffer/CellData';
|
|
9
|
+
import { IBufferLine } from '../common/buffer/Types';
|
|
10
|
+
import { IBufferService, IOptionsService, IOscLinkService } from '../common/services/Services';
|
|
10
11
|
|
|
11
12
|
export class OscLinkProvider implements ILinkProvider {
|
|
13
|
+
private readonly _workCell = new CellData();
|
|
14
|
+
|
|
12
15
|
constructor(
|
|
13
16
|
@IBufferService private readonly _bufferService: IBufferService,
|
|
14
17
|
@IOptionsService private readonly _optionsService: IOptionsService,
|
|
@@ -25,7 +28,7 @@ export class OscLinkProvider implements ILinkProvider {
|
|
|
25
28
|
|
|
26
29
|
const result: ILink[] = [];
|
|
27
30
|
const linkHandler = this._optionsService.rawOptions.linkHandler;
|
|
28
|
-
const cell =
|
|
31
|
+
const cell = this._workCell;
|
|
29
32
|
const lineLength = line.getTrimmedLength();
|
|
30
33
|
let currentLinkId = -1;
|
|
31
34
|
let currentStart = -1;
|
|
@@ -55,19 +58,8 @@ export class OscLinkProvider implements ILinkProvider {
|
|
|
55
58
|
if (finishLink || (currentStart !== -1 && x === lineLength - 1)) {
|
|
56
59
|
const text = this._oscLinkService.getLinkData(currentLinkId)?.uri;
|
|
57
60
|
if (text) {
|
|
58
|
-
|
|
59
|
-
const range
|
|
60
|
-
start: {
|
|
61
|
-
x: currentStart + 1,
|
|
62
|
-
y
|
|
63
|
-
},
|
|
64
|
-
end: {
|
|
65
|
-
// Offset end x if it's a link that ends on the last cell in the line
|
|
66
|
-
x: x + (!finishLink && x === lineLength - 1 ? 1 : 0),
|
|
67
|
-
y
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
|
|
61
|
+
const endX = x + (!finishLink && x === lineLength - 1 ? 1 : 0);
|
|
62
|
+
const range = this._getRangeWithLineWrap(y, currentStart, endX, currentLinkId);
|
|
71
63
|
let ignoreLink = false;
|
|
72
64
|
if (!linkHandler?.allowNonHttpProtocols) {
|
|
73
65
|
try {
|
|
@@ -109,6 +101,82 @@ export class OscLinkProvider implements ILinkProvider {
|
|
|
109
101
|
// id
|
|
110
102
|
callback(result);
|
|
111
103
|
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Expand a single-line OSC 8 range to a contiguous wrapped range for the same link id.
|
|
107
|
+
*/
|
|
108
|
+
private _getRangeWithLineWrap(y: number, startX: number, endX: number, linkId: number): IBufferRange {
|
|
109
|
+
let startY = y;
|
|
110
|
+
let finalStartX = startX;
|
|
111
|
+
let endY = y;
|
|
112
|
+
let finalEndX = endX;
|
|
113
|
+
|
|
114
|
+
// Expand upward only when this segment starts at column 0 and the current line is wrapped.
|
|
115
|
+
while (finalStartX === 0) {
|
|
116
|
+
const currentLine = this._bufferService.buffer.lines.get(startY - 1);
|
|
117
|
+
if (!currentLine?.isWrapped) {
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
const previousLine = this._bufferService.buffer.lines.get(startY - 2);
|
|
121
|
+
if (!previousLine) {
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
const previousLineLength = previousLine.getTrimmedLength();
|
|
125
|
+
if (previousLineLength === 0 || !this._hasUrlId(previousLine, previousLineLength - 1, linkId)) {
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
let previousStartX = previousLineLength - 1;
|
|
129
|
+
while (previousStartX > 0 && this._hasUrlId(previousLine, previousStartX - 1, linkId)) {
|
|
130
|
+
previousStartX--;
|
|
131
|
+
}
|
|
132
|
+
startY--;
|
|
133
|
+
finalStartX = previousStartX;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Expand downward only when this segment reaches trimmed EOL and the next line is wrapped.
|
|
137
|
+
while (true) {
|
|
138
|
+
const currentLine = this._bufferService.buffer.lines.get(endY - 1);
|
|
139
|
+
if (!currentLine) {
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
const currentLineLength = currentLine.getTrimmedLength();
|
|
143
|
+
if (finalEndX !== currentLineLength) {
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
const nextLine = this._bufferService.buffer.lines.get(endY);
|
|
147
|
+
if (!nextLine?.isWrapped) {
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
const nextLineLength = nextLine.getTrimmedLength();
|
|
151
|
+
if (nextLineLength === 0 || !this._hasUrlId(nextLine, 0, linkId)) {
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
let nextEndX = 1;
|
|
155
|
+
while (nextEndX < nextLineLength && this._hasUrlId(nextLine, nextEndX, linkId)) {
|
|
156
|
+
nextEndX++;
|
|
157
|
+
}
|
|
158
|
+
endY++;
|
|
159
|
+
finalEndX = nextEndX;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// IBufferRange uses 1-based coordinates.
|
|
163
|
+
return {
|
|
164
|
+
start: {
|
|
165
|
+
x: finalStartX + 1,
|
|
166
|
+
y: startY
|
|
167
|
+
},
|
|
168
|
+
end: {
|
|
169
|
+
x: finalEndX,
|
|
170
|
+
y: endY
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
private _hasUrlId(line: IBufferLine, x: number, linkId: number): boolean {
|
|
176
|
+
const cell = this._workCell;
|
|
177
|
+
line.loadCell(x, cell);
|
|
178
|
+
return !!cell.hasExtendedAttrs() && cell.extended.urlId === linkId;
|
|
179
|
+
}
|
|
112
180
|
}
|
|
113
181
|
|
|
114
182
|
function defaultActivate(e: MouseEvent, uri: string): void {
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* @license MIT
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { IRenderDebouncerWithCallback } from '
|
|
7
|
-
import { ICoreBrowserService } from '
|
|
6
|
+
import { IRenderDebouncerWithCallback } from './Types';
|
|
7
|
+
import { ICoreBrowserService } from './services/Services';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Debounces calls to render terminal rows using animation frames.
|
|
@@ -23,7 +23,7 @@ export class RenderDebouncer implements IRenderDebouncerWithCallback {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
public dispose(): void {
|
|
26
|
-
if (this._animationFrame) {
|
|
26
|
+
if (this._animationFrame !== undefined) {
|
|
27
27
|
this._coreBrowserService.window.cancelAnimationFrame(this._animationFrame);
|
|
28
28
|
this._animationFrame = undefined;
|
|
29
29
|
}
|
|
@@ -31,22 +31,20 @@ export class RenderDebouncer implements IRenderDebouncerWithCallback {
|
|
|
31
31
|
|
|
32
32
|
public addRefreshCallback(callback: FrameRequestCallback): number {
|
|
33
33
|
this._refreshCallbacks.push(callback);
|
|
34
|
-
|
|
35
|
-
this._animationFrame = this._coreBrowserService.window.requestAnimationFrame(() => this._innerRefresh());
|
|
36
|
-
}
|
|
34
|
+
this._animationFrame ??= this._coreBrowserService.window.requestAnimationFrame(() => this._innerRefresh());
|
|
37
35
|
return this._animationFrame;
|
|
38
36
|
}
|
|
39
37
|
|
|
40
38
|
public refresh(rowStart: number | undefined, rowEnd: number | undefined, rowCount: number): void {
|
|
41
39
|
this._rowCount = rowCount;
|
|
42
40
|
// Get the min/max row start/end for the arg values
|
|
43
|
-
rowStart = rowStart
|
|
44
|
-
rowEnd = rowEnd
|
|
41
|
+
rowStart = rowStart ?? 0;
|
|
42
|
+
rowEnd = rowEnd ?? this._rowCount - 1;
|
|
45
43
|
// Set the properties to the updated values
|
|
46
44
|
this._rowStart = this._rowStart !== undefined ? Math.min(this._rowStart, rowStart) : rowStart;
|
|
47
45
|
this._rowEnd = this._rowEnd !== undefined ? Math.max(this._rowEnd, rowEnd) : rowEnd;
|
|
48
46
|
|
|
49
|
-
if (this._animationFrame) {
|
|
47
|
+
if (this._animationFrame !== undefined) {
|
|
50
48
|
return;
|
|
51
49
|
}
|
|
52
50
|
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* @license MIT
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
import { IRenderDebouncer } from './Types';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const RENDER_DEBOUNCE_THRESHOLD_MS = 1000; // 1 Second
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Debounces calls to update screen readers to update at most once configurable interval of time.
|
|
@@ -31,14 +31,16 @@ export class TimeBasedDebouncer implements IRenderDebouncer {
|
|
|
31
31
|
public dispose(): void {
|
|
32
32
|
if (this._refreshTimeoutID) {
|
|
33
33
|
clearTimeout(this._refreshTimeoutID);
|
|
34
|
+
this._refreshTimeoutID = undefined;
|
|
34
35
|
}
|
|
36
|
+
this._additionalRefreshRequested = false;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
public refresh(rowStart: number | undefined, rowEnd: number | undefined, rowCount: number): void {
|
|
38
40
|
this._rowCount = rowCount;
|
|
39
41
|
// Get the min/max row start/end for the arg values
|
|
40
|
-
rowStart = rowStart
|
|
41
|
-
rowEnd = rowEnd
|
|
42
|
+
rowStart = rowStart ?? 0;
|
|
43
|
+
rowEnd = rowEnd ?? this._rowCount - 1;
|
|
42
44
|
// Set the properties to the updated values
|
|
43
45
|
this._rowStart = this._rowStart !== undefined ? Math.min(this._rowStart, rowStart) : rowStart;
|
|
44
46
|
this._rowEnd = this._rowEnd !== undefined ? Math.max(this._rowEnd, rowEnd) : rowEnd;
|
|
@@ -47,7 +49,12 @@ export class TimeBasedDebouncer implements IRenderDebouncer {
|
|
|
47
49
|
// enough time to pass before refreshing again.
|
|
48
50
|
const refreshRequestTime: number = performance.now();
|
|
49
51
|
if (refreshRequestTime - this._lastRefreshMs >= this._debounceThresholdMS) {
|
|
50
|
-
// Enough time has
|
|
52
|
+
// Enough time has elapsed since the last refresh; refresh immediately
|
|
53
|
+
if (this._refreshTimeoutID !== undefined) {
|
|
54
|
+
clearTimeout(this._refreshTimeoutID);
|
|
55
|
+
this._refreshTimeoutID = undefined;
|
|
56
|
+
this._additionalRefreshRequested = false;
|
|
57
|
+
}
|
|
51
58
|
this._lastRefreshMs = refreshRequestTime;
|
|
52
59
|
this._innerRefresh();
|
|
53
60
|
} else if (!this._additionalRefreshRequested) {
|
package/src/browser/Types.ts
CHANGED
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
* @license MIT
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
import { IBuffer } from 'common/buffer/Types';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
6
|
+
import { IColor, ITerminalOptions } from '../common/Types';
|
|
7
|
+
import { CharData, IBuffer } from '../common/buffer/Types';
|
|
8
|
+
import { ICoreTerminal } from '../common/CoreTerminal';
|
|
9
|
+
import { IDisposable, IRenderDimensions as IRenderDimensionsApi, Terminal as ITerminalApi } from '@xterm/xterm';
|
|
10
|
+
import { channels, css } from '../common/Color';
|
|
11
|
+
import type { IEvent } from '../common/Event';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* A portion of the public API that are implemented identially internally and simply passed through.
|
|
@@ -21,13 +22,14 @@ export interface ITerminal extends InternalPassthroughApis, ICoreTerminal {
|
|
|
21
22
|
linkifier: ILinkifier2 | undefined;
|
|
22
23
|
options: Required<ITerminalOptions>;
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
onFocus: Event<void>;
|
|
26
|
-
onA11yChar: Event<string>;
|
|
27
|
-
onA11yTab: Event<number>;
|
|
28
|
-
onWillOpen: Event<HTMLElement>;
|
|
25
|
+
readonly dimensions: IRenderDimensionsApi | undefined;
|
|
29
26
|
|
|
30
|
-
|
|
27
|
+
onBlur: IEvent<void>;
|
|
28
|
+
onFocus: IEvent<void>;
|
|
29
|
+
onDimensionsChange: IEvent<IRenderDimensionsApi>;
|
|
30
|
+
onA11yChar: IEvent<string>;
|
|
31
|
+
onA11yTab: IEvent<number>;
|
|
32
|
+
onWillOpen: IEvent<HTMLElement>;
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
export type CustomKeyEventHandler = (event: KeyboardEvent) => boolean;
|
|
@@ -98,7 +100,7 @@ export interface IPartialColorSet {
|
|
|
98
100
|
|
|
99
101
|
export interface IViewport extends IDisposable {
|
|
100
102
|
scrollBarWidth: number;
|
|
101
|
-
readonly onRequestScrollLines:
|
|
103
|
+
readonly onRequestScrollLines: IEvent<{ amount: number, suppressScrollEvent: boolean }>;
|
|
102
104
|
syncScrollArea(immediate?: boolean, force?: boolean): void;
|
|
103
105
|
getLinesScrolled(ev: WheelEvent): number;
|
|
104
106
|
getBufferElements(startLine: number, endLine?: number): { bufferElements: HTMLElement[], cursorElement?: HTMLElement };
|
|
@@ -128,8 +130,8 @@ export interface ILinkWithState {
|
|
|
128
130
|
}
|
|
129
131
|
|
|
130
132
|
export interface ILinkifier2 extends IDisposable {
|
|
131
|
-
onShowLinkUnderline:
|
|
132
|
-
onHideLinkUnderline:
|
|
133
|
+
onShowLinkUnderline: IEvent<ILinkifierEvent>;
|
|
134
|
+
onHideLinkUnderline: IEvent<ILinkifierEvent>;
|
|
133
135
|
readonly currentLink: ILinkWithState | undefined;
|
|
134
136
|
}
|
|
135
137
|
|