@xterm/xterm 5.6.0-beta.99 → 6.0.0

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.
@@ -117,12 +117,6 @@ export function evaluateKeyboardEvent(
117
117
  }
118
118
  if (modifiers) {
119
119
  result.key = C0.ESC + '[1;' + (modifiers + 1) + 'D';
120
- // HACK: Make Alt + left-arrow behave like Ctrl + left-arrow: move one word backwards
121
- // http://unix.stackexchange.com/a/108106
122
- // macOS uses different escape sequences than linux
123
- if (result.key === C0.ESC + '[1;3D') {
124
- result.key = C0.ESC + (isMac ? 'b' : '[1;5D');
125
- }
126
120
  } else if (applicationCursorMode) {
127
121
  result.key = C0.ESC + 'OD';
128
122
  } else {
@@ -136,12 +130,6 @@ export function evaluateKeyboardEvent(
136
130
  }
137
131
  if (modifiers) {
138
132
  result.key = C0.ESC + '[1;' + (modifiers + 1) + 'C';
139
- // HACK: Make Alt + right-arrow behave like Ctrl + right-arrow: move one word forward
140
- // http://unix.stackexchange.com/a/108106
141
- // macOS uses different escape sequences than linux
142
- if (result.key === C0.ESC + '[1;3C') {
143
- result.key = C0.ESC + (isMac ? 'f' : '[1;5C');
144
- }
145
133
  } else if (applicationCursorMode) {
146
134
  result.key = C0.ESC + 'OC';
147
135
  } else {
@@ -155,12 +143,6 @@ export function evaluateKeyboardEvent(
155
143
  }
156
144
  if (modifiers) {
157
145
  result.key = C0.ESC + '[1;' + (modifiers + 1) + 'A';
158
- // HACK: Make Alt + up-arrow behave like Ctrl + up-arrow
159
- // http://unix.stackexchange.com/a/108106
160
- // macOS uses different escape sequences than linux
161
- if (!isMac && result.key === C0.ESC + '[1;3A') {
162
- result.key = C0.ESC + '[1;5A';
163
- }
164
146
  } else if (applicationCursorMode) {
165
147
  result.key = C0.ESC + 'OA';
166
148
  } else {
@@ -174,12 +156,6 @@ export function evaluateKeyboardEvent(
174
156
  }
175
157
  if (modifiers) {
176
158
  result.key = C0.ESC + '[1;' + (modifiers + 1) + 'B';
177
- // HACK: Make Alt + down-arrow behave like Ctrl + down-arrow
178
- // http://unix.stackexchange.com/a/108106
179
- // macOS uses different escape sequences than linux
180
- if (!isMac && result.key === C0.ESC + '[1;3B') {
181
- result.key = C0.ESC + '[1;5B';
182
- }
183
159
  } else if (applicationCursorMode) {
184
160
  result.key = C0.ESC + 'OB';
185
161
  } else {
@@ -137,7 +137,7 @@ export class WriteBuffer extends Disposable {
137
137
  * effectively lowering the redrawing needs, schematically:
138
138
  *
139
139
  * macroTask _innerWrite:
140
- * if (Date.now() - (lastTime | 0) < WRITE_TIMEOUT_MS):
140
+ * if (performance.now() - (lastTime | 0) < WRITE_TIMEOUT_MS):
141
141
  * schedule microTask _innerWrite(lastTime)
142
142
  * else:
143
143
  * schedule macroTask _innerWrite(0)
@@ -158,7 +158,7 @@ export class WriteBuffer extends Disposable {
158
158
  * Note, for pure sync code `lastTime` and `promiseResult` have no meaning.
159
159
  */
160
160
  protected _innerWrite(lastTime: number = 0, promiseResult: boolean = true): void {
161
- const startTime = lastTime || Date.now();
161
+ const startTime = lastTime || performance.now();
162
162
  while (this._writeBuffer.length > this._bufferOffset) {
163
163
  const data = this._writeBuffer[this._bufferOffset];
164
164
  const result = this._action(data, promiseResult);
@@ -186,7 +186,7 @@ export class WriteBuffer extends Disposable {
186
186
  * responsibility to slice hard work), but we can at least schedule a screen update as we
187
187
  * gain control.
188
188
  */
189
- const continuation: (r: boolean) => void = (r: boolean) => Date.now() - startTime >= WRITE_TIMEOUT_MS
189
+ const continuation: (r: boolean) => void = (r: boolean) => performance.now() - startTime >= WRITE_TIMEOUT_MS
190
190
  ? setTimeout(() => this._innerWrite(0, r))
191
191
  : this._innerWrite(startTime, r);
192
192
 
@@ -202,7 +202,8 @@ export class WriteBuffer extends Disposable {
202
202
  * throughput by eval'ing `startTime` upfront pulling at least one more chunk into the
203
203
  * current microtask queue (executed before setTimeout).
204
204
  */
205
- // const continuation: (r: boolean) => void = Date.now() - startTime >= WRITE_TIMEOUT_MS
205
+ // const continuation: (r: boolean) => void = performance.now() - startTime >=
206
+ // WRITE_TIMEOUT_MS
206
207
  // ? r => setTimeout(() => this._innerWrite(0, r))
207
208
  // : r => this._innerWrite(startTime, r);
208
209
 
@@ -222,7 +223,7 @@ export class WriteBuffer extends Disposable {
222
223
  this._bufferOffset++;
223
224
  this._pendingData -= data.length;
224
225
 
225
- if (Date.now() - startTime >= WRITE_TIMEOUT_MS) {
226
+ if (performance.now() - startTime >= WRITE_TIMEOUT_MS) {
226
227
  break;
227
228
  }
228
229
  }
@@ -7,7 +7,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
7
7
  import { IAttributeData, IBufferLine } from 'common/Types';
8
8
  import { BufferSet } from 'common/buffer/BufferSet';
9
9
  import { IBuffer, IBufferSet } from 'common/buffer/Types';
10
- import { IBufferService, IOptionsService } from 'common/services/Services';
10
+ import { IBufferService, IOptionsService, type IBufferResizeEvent } from 'common/services/Services';
11
11
  import { Emitter } from 'vs/base/common/event';
12
12
 
13
13
  export const MINIMUM_COLS = 2; // Less than 2 can mess with wide chars
@@ -22,7 +22,7 @@ export class BufferService extends Disposable implements IBufferService {
22
22
  /** Whether the user is scrolling (locks the scroll position) */
23
23
  public isUserScrolling: boolean = false;
24
24
 
25
- private readonly _onResize = this._register(new Emitter<{ cols: number, rows: number }>());
25
+ private readonly _onResize = this._register(new Emitter<IBufferResizeEvent>());
26
26
  public readonly onResize = this._onResize.event;
27
27
  private readonly _onScroll = this._register(new Emitter<number>());
28
28
  public readonly onScroll = this._onScroll.event;
@@ -37,15 +37,18 @@ export class BufferService extends Disposable implements IBufferService {
37
37
  this.cols = Math.max(optionsService.rawOptions.cols || 0, MINIMUM_COLS);
38
38
  this.rows = Math.max(optionsService.rawOptions.rows || 0, MINIMUM_ROWS);
39
39
  this.buffers = this._register(new BufferSet(optionsService, this));
40
+ this._register(this.buffers.onBufferActivate(e => {
41
+ this._onScroll.fire(e.activeBuffer.ydisp);
42
+ }));
40
43
  }
41
44
 
42
45
  public resize(cols: number, rows: number): void {
46
+ const colsChanged = this.cols !== cols;
47
+ const rowsChanged = this.rows !== rows;
43
48
  this.cols = cols;
44
49
  this.rows = rows;
45
50
  this.buffers.resize(cols, rows);
46
- // TODO: This doesn't fire when scrollback changes - add a resize event to BufferSet and forward
47
- // event
48
- this._onResize.fire({ cols, rows });
51
+ this._onResize.fire({ cols, rows, colsChanged, rowsChanged });
49
52
  }
50
53
 
51
54
  public reset(): void {
@@ -2,7 +2,7 @@
2
2
  * Copyright (c) 2019 The xterm.js authors. All rights reserved.
3
3
  * @license MIT
4
4
  */
5
- import { IBufferService, ICoreService, ICoreMouseService } from 'common/services/Services';
5
+ import { IBufferService, ICoreService, ICoreMouseService, IOptionsService } from 'common/services/Services';
6
6
  import { ICoreMouseProtocol, ICoreMouseEvent, CoreMouseEncoding, CoreMouseEventType, CoreMouseButton, CoreMouseAction } from 'common/Types';
7
7
  import { Disposable } from 'vs/base/common/lifecycle';
8
8
  import { Emitter } from 'vs/base/common/event';
@@ -174,13 +174,15 @@ export class CoreMouseService extends Disposable implements ICoreMouseService {
174
174
  private _activeProtocol: string = '';
175
175
  private _activeEncoding: string = '';
176
176
  private _lastEvent: ICoreMouseEvent | null = null;
177
+ private _wheelPartialScroll: number = 0;
177
178
 
178
179
  private readonly _onProtocolChange = this._register(new Emitter<CoreMouseEventType>());
179
- public readonly onProtocolChange = this._onProtocolChange.event;
180
+ public readonly onProtocolChange = this._onProtocolChange.event;
180
181
 
181
182
  constructor(
182
183
  @IBufferService private readonly _bufferService: IBufferService,
183
- @ICoreService private readonly _coreService: ICoreService
184
+ @ICoreService private readonly _coreService: ICoreService,
185
+ @IOptionsService private readonly _optionsService: IOptionsService
184
186
  ) {
185
187
  super();
186
188
  // register default protocols and encodings
@@ -229,6 +231,49 @@ export class CoreMouseService extends Disposable implements ICoreMouseService {
229
231
  this.activeProtocol = 'NONE';
230
232
  this.activeEncoding = 'DEFAULT';
231
233
  this._lastEvent = null;
234
+ this._wheelPartialScroll = 0;
235
+ }
236
+
237
+ /**
238
+ * Processes a wheel event, accounting for partial scrolls for trackpad, mouse scrolls.
239
+ * This prevents hyper-sensitive scrolling in alt buffer.
240
+ */
241
+ public consumeWheelEvent(ev: WheelEvent, cellHeight?: number, dpr?: number): number {
242
+ // Do nothing if it's not a vertical scroll event
243
+ if (ev.deltaY === 0 || ev.shiftKey) {
244
+ return 0;
245
+ }
246
+
247
+ if (cellHeight === undefined || dpr === undefined) {
248
+ return 0;
249
+ }
250
+
251
+ const targetWheelEventPixels = cellHeight / dpr;
252
+ let amount = this._applyScrollModifier(ev.deltaY, ev);
253
+
254
+ if (ev.deltaMode === WheelEvent.DOM_DELTA_PIXEL) {
255
+ amount /= (targetWheelEventPixels + 0.0); // Prevent integer division
256
+
257
+ const isLikelyTrackpad = Math.abs(ev.deltaY) < 50;
258
+ if (isLikelyTrackpad) {
259
+ amount *= 0.3;
260
+ }
261
+
262
+ this._wheelPartialScroll += amount;
263
+ amount = Math.floor(Math.abs(this._wheelPartialScroll)) * (this._wheelPartialScroll > 0 ? 1 : -1);
264
+ this._wheelPartialScroll %= 1;
265
+ } else if (ev.deltaMode === WheelEvent.DOM_DELTA_PAGE) {
266
+ amount *= this._bufferService.rows;
267
+ }
268
+ return amount;
269
+ }
270
+
271
+ private _applyScrollModifier(amount: number, ev: WheelEvent): number {
272
+ // Multiply the scroll speed when the modifier key is pressed
273
+ if (ev.altKey || ev.ctrlKey || ev.shiftKey) {
274
+ return amount * this._optionsService.rawOptions.fastScrollSensitivity * this._optionsService.rawOptions.scrollSensitivity;
275
+ }
276
+ return amount * this._optionsService.rawOptions.scrollSensitivity;
232
277
  }
233
278
 
234
279
  /**
@@ -22,6 +22,7 @@ const DEFAULT_DEC_PRIVATE_MODES: IDecPrivateModes = Object.freeze({
22
22
  origin: false,
23
23
  reverseWraparound: false,
24
24
  sendFocus: false,
25
+ synchronizedOutput: false,
25
26
  wraparound: true // defaults: xterm - true, vt100 - false
26
27
  });
27
28
 
@@ -75,7 +76,8 @@ export class CoreService extends Disposable implements ICoreService {
75
76
  }
76
77
 
77
78
  // Fire onData API
78
- this._logService.debug(`sending data "${data}"`, () => data.split('').map(e => e.charCodeAt(0)));
79
+ this._logService.debug(`sending data "${data}"`);
80
+ this._logService.trace(`sending data (codes)`, () => data.split('').map(e => e.charCodeAt(0)));
79
81
  this._onData.fire(data);
80
82
  }
81
83
 
@@ -83,7 +85,8 @@ export class CoreService extends Disposable implements ICoreService {
83
85
  if (this._optionsService.rawOptions.disableStdin) {
84
86
  return;
85
87
  }
86
- this._logService.debug(`sending binary "${data}"`, () => data.split('').map(e => e.charCodeAt(0)));
88
+ this._logService.debug(`sending binary "${data}"`);
89
+ this._logService.trace(`sending binary (codes)`, () => data.split('').map(e => e.charCodeAt(0)));
87
90
  this._onBinary.fire(data);
88
91
  }
89
92
  }
@@ -32,6 +32,7 @@ export const DEFAULT_OPTIONS: Readonly<Required<ITerminalOptions>> = {
32
32
  logLevel: 'info',
33
33
  logger: null,
34
34
  scrollback: 1000,
35
+ scrollOnEraseInDisplay: false,
35
36
  scrollOnUserInput: true,
36
37
  scrollSensitivity: 1,
37
38
  screenReaderMode: false,
@@ -18,7 +18,7 @@ export interface IBufferService {
18
18
  readonly buffer: IBuffer;
19
19
  readonly buffers: IBufferSet;
20
20
  isUserScrolling: boolean;
21
- onResize: Event<{ cols: number, rows: number }>;
21
+ onResize: Event<IBufferResizeEvent>;
22
22
  onScroll: Event<number>;
23
23
  scroll(eraseAttr: IAttributeData, isWrapped?: boolean): void;
24
24
  scrollLines(disp: number, suppressScrollEvent?: boolean): void;
@@ -26,6 +26,13 @@ export interface IBufferService {
26
26
  reset(): void;
27
27
  }
28
28
 
29
+ export interface IBufferResizeEvent {
30
+ cols: number;
31
+ rows: number;
32
+ colsChanged: boolean;
33
+ rowsChanged: boolean;
34
+ }
35
+
29
36
  export const ICoreMouseService = createDecorator<ICoreMouseService>('CoreMouseService');
30
37
  export interface ICoreMouseService {
31
38
  serviceBrand: undefined;
@@ -58,6 +65,11 @@ export interface ICoreMouseService {
58
65
  * Human readable version of mouse events.
59
66
  */
60
67
  explainEvents(events: CoreMouseEventType): { [event: string]: boolean };
68
+
69
+ /**
70
+ * Process wheel event taking partial scroll into account.
71
+ */
72
+ consumeWheelEvent(ev: WheelEvent, cellHeight?: number, dpr?: number): number;
61
73
  }
62
74
 
63
75
  export const ICoreService = createDecorator<ICoreService>('CoreService');
@@ -254,6 +266,7 @@ export interface ITerminalOptions {
254
266
  windowOptions?: IWindowOptions;
255
267
  wordSeparator?: string;
256
268
  overviewRuler?: IOverviewRulerOptions;
269
+ scrollOnEraseInDisplay?: boolean;
257
270
 
258
271
  [key: string]: any;
259
272
  cancelEvents: boolean;
@@ -124,7 +124,7 @@ export function raceTimeout<T>(promise: Promise<T>, timeout: number, onTimeout?:
124
124
  ]);
125
125
  }
126
126
 
127
- export function asPromise<T>(callback: () => T | Thenable<T>): Promise<T> {
127
+ export function asPromise<T>(callback: () => T | PromiseLike<T>): Promise<T> {
128
128
  return new Promise<T>((resolve, reject) => {
129
129
  const item = callback();
130
130
  if (isThenable<T>(item)) {
@@ -107,13 +107,6 @@ declare module '@xterm/xterm' {
107
107
  */
108
108
  drawBoldTextInBrightColors?: boolean;
109
109
 
110
- /**
111
- * The modifier key hold to multiply scroll speed.
112
- * @deprecated This option is no longer available and will always use alt.
113
- * Setting this will be ignored.
114
- */
115
- fastScrollModifier?: 'none' | 'alt' | 'ctrl' | 'shift';
116
-
117
110
  /**
118
111
  * The scroll speed multiplier used for fast scrolling when `Alt` is held.
119
112
  */
@@ -257,6 +250,13 @@ declare module '@xterm/xterm' {
257
250
  */
258
251
  scrollback?: number;
259
252
 
253
+ /**
254
+ * If enabled the Erase in Display All (ED2) escape sequence will push
255
+ * erased text to scrollback, instead of clearing only the viewport portion.
256
+ * This emulates PuTTY's default clear screen behavior.
257
+ */
258
+ scrollOnEraseInDisplay?: boolean;
259
+
260
260
  /**
261
261
  * Whether to scroll to the bottom whenever there is some user input. The
262
262
  * default is true.
@@ -284,25 +284,6 @@ declare module '@xterm/xterm' {
284
284
  */
285
285
  theme?: ITheme;
286
286
 
287
- /**
288
- * Whether "Windows mode" is enabled. Because Windows backends winpty and
289
- * conpty operate by doing line wrapping on their side, xterm.js does not
290
- * have access to wrapped lines. When Windows mode is enabled the following
291
- * changes will be in effect:
292
- *
293
- * - Reflow is disabled.
294
- * - Lines are assumed to be wrapped if the last character of the line is
295
- * not whitespace.
296
- *
297
- * When using conpty on Windows 11 version >= 21376, it is recommended to
298
- * disable this because native text wrapping sequences are output correctly
299
- * thanks to https://github.com/microsoft/terminal/issues/405
300
- *
301
- * @deprecated Use {@link windowsPty}. This value will be ignored if
302
- * windowsPty is set.
303
- */
304
- windowsMode?: boolean;
305
-
306
287
  /**
307
288
  * Compatibility information when the pty is known to be hosted on Windows.
308
289
  * Setting this will turn on certain heuristics/workarounds depending on the
@@ -1258,21 +1239,31 @@ declare module '@xterm/xterm' {
1258
1239
 
1259
1240
  /**
1260
1241
  * Write data to the terminal.
1242
+ *
1243
+ * Note that the change will not be reflected in the {@link buffer}
1244
+ * immediately as the data is processed asynchronously. Provide a
1245
+ * {@link callback} to know when the data was processed.
1261
1246
  * @param data The data to write to the terminal. This can either be raw
1262
1247
  * bytes given as Uint8Array from the pty or a string. Raw bytes will always
1263
1248
  * be treated as UTF-8 encoded, string data as UTF-16.
1264
1249
  * @param callback Optional callback that fires when the data was processed
1265
- * by the parser.
1250
+ * by the parser. This callback must be provided and awaited in order for
1251
+ * {@link buffer} to reflect the change in the write.
1266
1252
  */
1267
1253
  write(data: string | Uint8Array, callback?: () => void): void;
1268
1254
 
1269
1255
  /**
1270
1256
  * Writes data to the terminal, followed by a break line character (\n).
1257
+ *
1258
+ * Note that the change will not be reflected in the {@link buffer}
1259
+ * immediately as the data is processed asynchronously. Provide a
1260
+ * {@link callback} to know when the data was processed.
1271
1261
  * @param data The data to write to the terminal. This can either be raw
1272
1262
  * bytes given as Uint8Array from the pty or a string. Raw bytes will always
1273
1263
  * be treated as UTF-8 encoded, string data as UTF-16.
1274
1264
  * @param callback Optional callback that fires when the data was processed
1275
- * by the parser.
1265
+ * by the parser. This callback must be provided and awaited in order for
1266
+ * {@link buffer} to reflect the change in the write.
1276
1267
  */
1277
1268
  writeln(data: string | Uint8Array, callback?: () => void): void;
1278
1269
 
@@ -1951,6 +1942,13 @@ declare module '@xterm/xterm' {
1951
1942
  * Send FocusIn/FocusOut events: `CSI ? 1 0 0 4 h`
1952
1943
  */
1953
1944
  readonly sendFocusMode: boolean;
1945
+ /**
1946
+ * Synchronized Output Mode: `CSI ? 2 0 2 6 h`
1947
+ *
1948
+ * When enabled, output is buffered and only rendered when the mode is
1949
+ * disabled, allowing for atomic screen updates without tearing.
1950
+ */
1951
+ readonly synchronizedOutputMode: boolean;
1954
1952
  /**
1955
1953
  * Auto-Wrap Mode (DECAWM): `CSI ? 7 h`
1956
1954
  */
@@ -1,12 +0,0 @@
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
- /**
7
- * Thenable is a common denominator between ES6 promises, Q, jquery.Deferred, WinJS.Promise,
8
- * and others. This API makes no assumption about what promise library is being used which
9
- * enables reusing existing code without migrating to a specific promise implementation. Still,
10
- * we recommend the use of native promises which are available in VS Code.
11
- */
12
- interface Thenable<T> extends PromiseLike<T> { }