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

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 (163) 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/BufferReflow.ts +4 -1
  69. package/src/common/buffer/BufferSet.ts +11 -6
  70. package/src/common/buffer/CellData.ts +57 -0
  71. package/src/common/buffer/Marker.ts +2 -2
  72. package/src/common/buffer/Types.ts +6 -2
  73. package/src/common/data/EscapeSequences.ts +71 -70
  74. package/src/common/input/Keyboard.ts +14 -7
  75. package/src/common/input/KittyKeyboard.ts +526 -0
  76. package/src/common/input/Win32InputMode.ts +297 -0
  77. package/src/common/input/WriteBuffer.ts +69 -32
  78. package/src/common/input/XParseColor.ts +2 -2
  79. package/src/common/parser/ApcParser.ts +196 -0
  80. package/src/common/parser/Constants.ts +14 -4
  81. package/src/common/parser/DcsParser.ts +11 -12
  82. package/src/common/parser/EscapeSequenceParser.ts +205 -63
  83. package/src/common/parser/OscParser.ts +11 -12
  84. package/src/common/parser/Params.ts +27 -8
  85. package/src/common/parser/Types.ts +36 -2
  86. package/src/common/public/BufferLineApiView.ts +2 -2
  87. package/src/common/public/BufferNamespaceApi.ts +3 -3
  88. package/src/common/public/ParserApi.ts +3 -0
  89. package/src/common/services/BufferService.ts +14 -9
  90. package/src/common/services/CharsetService.ts +4 -0
  91. package/src/common/services/CoreService.ts +22 -9
  92. package/src/common/services/DecorationService.ts +258 -8
  93. package/src/common/services/LogService.ts +1 -31
  94. package/src/common/services/{CoreMouseService.ts → MouseStateService.ts} +21 -132
  95. package/src/common/services/OptionsService.ts +13 -4
  96. package/src/common/services/ServiceRegistry.ts +9 -7
  97. package/src/common/services/Services.ts +49 -40
  98. package/src/common/services/UnicodeService.ts +1 -1
  99. package/typings/xterm.d.ts +318 -34
  100. package/src/common/Clone.ts +0 -23
  101. package/src/common/TypedArrayUtils.ts +0 -17
  102. package/src/vs/base/browser/browser.ts +0 -141
  103. package/src/vs/base/browser/canIUse.ts +0 -49
  104. package/src/vs/base/browser/dom.ts +0 -2369
  105. package/src/vs/base/browser/fastDomNode.ts +0 -316
  106. package/src/vs/base/browser/globalPointerMoveMonitor.ts +0 -112
  107. package/src/vs/base/browser/iframe.ts +0 -135
  108. package/src/vs/base/browser/keyboardEvent.ts +0 -213
  109. package/src/vs/base/browser/mouseEvent.ts +0 -229
  110. package/src/vs/base/browser/touch.ts +0 -372
  111. package/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts +0 -303
  112. package/src/vs/base/browser/ui/scrollbar/horizontalScrollbar.ts +0 -114
  113. package/src/vs/base/browser/ui/scrollbar/scrollableElement.ts +0 -720
  114. package/src/vs/base/browser/ui/scrollbar/scrollableElementOptions.ts +0 -165
  115. package/src/vs/base/browser/ui/scrollbar/scrollbarArrow.ts +0 -114
  116. package/src/vs/base/browser/ui/scrollbar/scrollbarState.ts +0 -243
  117. package/src/vs/base/browser/ui/scrollbar/scrollbarVisibilityController.ts +0 -118
  118. package/src/vs/base/browser/ui/scrollbar/verticalScrollbar.ts +0 -116
  119. package/src/vs/base/browser/ui/widget.ts +0 -57
  120. package/src/vs/base/browser/window.ts +0 -14
  121. package/src/vs/base/common/arrays.ts +0 -887
  122. package/src/vs/base/common/arraysFind.ts +0 -202
  123. package/src/vs/base/common/assert.ts +0 -71
  124. package/src/vs/base/common/async.ts +0 -1992
  125. package/src/vs/base/common/cancellation.ts +0 -148
  126. package/src/vs/base/common/charCode.ts +0 -450
  127. package/src/vs/base/common/collections.ts +0 -140
  128. package/src/vs/base/common/decorators.ts +0 -130
  129. package/src/vs/base/common/equals.ts +0 -146
  130. package/src/vs/base/common/errors.ts +0 -303
  131. package/src/vs/base/common/event.ts +0 -1778
  132. package/src/vs/base/common/functional.ts +0 -32
  133. package/src/vs/base/common/hash.ts +0 -316
  134. package/src/vs/base/common/iterator.ts +0 -159
  135. package/src/vs/base/common/keyCodes.ts +0 -526
  136. package/src/vs/base/common/keybindings.ts +0 -284
  137. package/src/vs/base/common/lazy.ts +0 -47
  138. package/src/vs/base/common/lifecycle.ts +0 -801
  139. package/src/vs/base/common/linkedList.ts +0 -142
  140. package/src/vs/base/common/map.ts +0 -202
  141. package/src/vs/base/common/numbers.ts +0 -98
  142. package/src/vs/base/common/observable.ts +0 -76
  143. package/src/vs/base/common/observableInternal/api.ts +0 -31
  144. package/src/vs/base/common/observableInternal/autorun.ts +0 -281
  145. package/src/vs/base/common/observableInternal/base.ts +0 -489
  146. package/src/vs/base/common/observableInternal/debugName.ts +0 -145
  147. package/src/vs/base/common/observableInternal/derived.ts +0 -428
  148. package/src/vs/base/common/observableInternal/lazyObservableValue.ts +0 -146
  149. package/src/vs/base/common/observableInternal/logging.ts +0 -328
  150. package/src/vs/base/common/observableInternal/promise.ts +0 -209
  151. package/src/vs/base/common/observableInternal/utils.ts +0 -610
  152. package/src/vs/base/common/platform.ts +0 -281
  153. package/src/vs/base/common/scrollable.ts +0 -522
  154. package/src/vs/base/common/sequence.ts +0 -34
  155. package/src/vs/base/common/stopwatch.ts +0 -43
  156. package/src/vs/base/common/strings.ts +0 -557
  157. package/src/vs/base/common/symbols.ts +0 -9
  158. package/src/vs/base/common/uint.ts +0 -59
  159. package/src/vs/patches/nls.ts +0 -90
  160. package/src/vs/typings/base-common.d.ts +0 -20
  161. package/src/vs/typings/require.d.ts +0 -42
  162. package/src/vs/typings/vscode-globals-nls.d.ts +0 -36
  163. package/src/vs/typings/vscode-globals-product.d.ts +0 -33
@@ -8,48 +8,31 @@ import { IInputHandler, IAttributeData, IDisposable, IWindowOptions, IColorEvent
8
8
  import { C0, C1 } from 'common/data/EscapeSequences';
9
9
  import { CHARSETS, DEFAULT_CHARSET } from 'common/data/Charsets';
10
10
  import { EscapeSequenceParser } from 'common/parser/EscapeSequenceParser';
11
- import { Disposable } from 'vs/base/common/lifecycle';
11
+ import { Disposable } from 'common/Lifecycle';
12
12
  import { StringToUtf32, stringFromCodePoint, Utf8ToUtf32 } from 'common/input/TextDecoder';
13
13
  import { BufferLine, DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine';
14
14
  import { IParsingState, IEscapeSequenceParser, IParams, IFunctionIdentifier } from 'common/parser/Types';
15
15
  import { NULL_CELL_CODE, NULL_CELL_WIDTH, Attributes, FgFlags, BgFlags, Content, UnderlineStyle } from 'common/buffer/Constants';
16
16
  import { CellData } from 'common/buffer/CellData';
17
17
  import { AttributeData } from 'common/buffer/AttributeData';
18
- import { ICoreService, IBufferService, IOptionsService, ILogService, ICoreMouseService, ICharsetService, IUnicodeService, LogLevelEnum, IOscLinkService } from 'common/services/Services';
18
+ import { ICoreService, IBufferService, IOptionsService, ILogService, IMouseStateService, ICharsetService, IUnicodeService, LogLevelEnum, IOscLinkService } from 'common/services/Services';
19
19
  import { UnicodeService } from 'common/services/UnicodeService';
20
20
  import { OscHandler } from 'common/parser/OscParser';
21
21
  import { DcsHandler } from 'common/parser/DcsParser';
22
+ import { ApcHandler } from 'common/parser/ApcParser';
22
23
  import { IBuffer } from 'common/buffer/Types';
23
24
  import { parseColor } from 'common/input/XParseColor';
24
- import { Emitter } from 'vs/base/common/event';
25
+ import { Emitter } from 'common/Event';
26
+ import { XTERM_VERSION } from 'common/Version';
25
27
 
26
28
  /**
27
29
  * Map collect to glevel. Used in `selectCharset`.
28
30
  */
29
31
  const GLEVEL: { [key: string]: number } = { '(': 0, ')': 1, '*': 2, '+': 3, '-': 1, '.': 2 };
30
32
 
31
- /**
32
- * VT commands done by the parser - FIXME: move this to the parser?
33
- */
34
- // @vt: #Y ESC CSI "Control Sequence Introducer" "ESC [" "Start of a CSI sequence."
35
- // @vt: #Y ESC OSC "Operating System Command" "ESC ]" "Start of an OSC sequence."
36
- // @vt: #Y ESC DCS "Device Control String" "ESC P" "Start of a DCS sequence."
37
- // @vt: #Y ESC ST "String Terminator" "ESC \" "Terminator used for string type sequences."
38
- // @vt: #Y ESC PM "Privacy Message" "ESC ^" "Start of a privacy message."
39
- // @vt: #Y ESC APC "Application Program Command" "ESC _" "Start of an APC sequence."
40
- // @vt: #Y C1 CSI "Control Sequence Introducer" "\x9B" "Start of a CSI sequence."
41
- // @vt: #Y C1 OSC "Operating System Command" "\x9D" "Start of an OSC sequence."
42
- // @vt: #Y C1 DCS "Device Control String" "\x90" "Start of a DCS sequence."
43
- // @vt: #Y C1 ST "String Terminator" "\x9C" "Terminator used for string type sequences."
44
- // @vt: #Y C1 PM "Privacy Message" "\x9E" "Start of a privacy message."
45
- // @vt: #Y C1 APC "Application Program Command" "\x9F" "Start of an APC sequence."
46
- // @vt: #Y C0 NUL "Null" "\0, \x00" "NUL is ignored."
47
- // @vt: #Y C0 ESC "Escape" "\e, \x1B" "Start of a sequence. Cancels any other sequence."
48
-
49
33
  /**
50
34
  * Document xterm VT features here that are currently unsupported
51
35
  */
52
- // @vt: #E[Supported via @xterm/addon-image.] DCS SIXEL "SIXEL Graphics" "DCS Ps ; Ps ; Ps ; q Pt ST" "Draw SIXEL image."
53
36
  // @vt: #N DCS DECUDK "User Defined Keys" "DCS Ps ; Ps \| Pt ST" "Definitions for user-defined keys."
54
37
  // @vt: #N DCS XTGETTCAP "Request Terminfo String" "DCS + q Pt ST" "Request Terminfo String."
55
38
  // @vt: #N DCS XTSETTCAP "Set Terminfo Data" "DCS + p Pt ST" "Set Terminfo Data."
@@ -58,12 +41,13 @@ const GLEVEL: { [key: string]: number } = { '(': 0, ')': 1, '*': 2, '+': 3, '-':
58
41
  /**
59
42
  * Max length of the UTF32 input buffer. Real memory consumption is 4 times higher.
60
43
  */
61
- const MAX_PARSEBUFFER_LENGTH = 131072;
62
-
63
- /**
64
- * Limit length of title and icon name stacks.
65
- */
66
- const STACK_LIMIT = 10;
44
+ const enum Constants {
45
+ MAX_PARSEBUFFER_LENGTH = 131072,
46
+ /** Limit length of title and icon name stacks. */
47
+ STACK_LIMIT = 10,
48
+ // create a warning log if an async handler takes longer than the limit (in ms)
49
+ SLOW_ASYNC_LIMIT = 5000
50
+ }
67
51
 
68
52
  // map params to window option
69
53
  function paramToWindowOption(n: number, opts: IWindowOptions): boolean {
@@ -102,9 +86,6 @@ export enum WindowsOptionsReportType {
102
86
  GET_CELL_SIZE_PIXELS = 1
103
87
  }
104
88
 
105
- // create a warning log if an async handler takes longer than the limit (in ms)
106
- const SLOW_ASYNC_LIMIT = 5000;
107
-
108
89
  // Work variables to avoid garbage collection
109
90
  let $temp = 0;
110
91
 
@@ -158,6 +139,8 @@ export class InputHandler extends Disposable implements IInputHandler {
158
139
  public readonly onTitleChange = this._onTitleChange.event;
159
140
  private readonly _onColor = this._register(new Emitter<IColorEvent>());
160
141
  public readonly onColor = this._onColor.event;
142
+ private readonly _onRequestColorSchemeQuery = this._register(new Emitter<void>());
143
+ public readonly onRequestColorSchemeQuery = this._onRequestColorSchemeQuery.event;
161
144
 
162
145
  private _parseStack: IParseStack = {
163
146
  paused: false,
@@ -174,7 +157,7 @@ export class InputHandler extends Disposable implements IInputHandler {
174
157
  private readonly _logService: ILogService,
175
158
  private readonly _optionsService: IOptionsService,
176
159
  private readonly _oscLinkService: IOscLinkService,
177
- private readonly _coreMouseService: ICoreMouseService,
160
+ private readonly _mouseStateService: IMouseStateService,
178
161
  private readonly _unicodeService: IUnicodeService,
179
162
  private readonly _parser: IEscapeSequenceParser = new EscapeSequenceParser()
180
163
  ) {
@@ -207,6 +190,9 @@ export class InputHandler extends Disposable implements IInputHandler {
207
190
  }
208
191
  this._logService.debug('Unknown DCS code: ', { identifier: this._parser.identToString(ident), action, payload });
209
192
  });
193
+ this._parser.setApcHandlerFallback((ident, action, payload) => {
194
+ this._logService.debug('Unknown APC code: ', { identifier: this._parser.identToString(ident), action, payload });
195
+ });
210
196
 
211
197
  /**
212
198
  * print handler
@@ -239,6 +225,7 @@ export class InputHandler extends Disposable implements IInputHandler {
239
225
  this._parser.registerCsiHandler({ final: 'T' }, params => this.scrollDown(params));
240
226
  this._parser.registerCsiHandler({ final: 'X' }, params => this.eraseChars(params));
241
227
  this._parser.registerCsiHandler({ final: 'Z' }, params => this.cursorBackwardTab(params));
228
+ this._parser.registerCsiHandler({ final: '^' }, params => this.scrollDown(params));
242
229
  this._parser.registerCsiHandler({ final: '`' }, params => this.charPosAbsolute(params));
243
230
  this._parser.registerCsiHandler({ final: 'a' }, params => this.hPositionRelative(params));
244
231
  this._parser.registerCsiHandler({ final: 'b' }, params => this.repeatPrecedingCharacter(params));
@@ -256,6 +243,7 @@ export class InputHandler extends Disposable implements IInputHandler {
256
243
  this._parser.registerCsiHandler({ final: 'n' }, params => this.deviceStatus(params));
257
244
  this._parser.registerCsiHandler({ prefix: '?', final: 'n' }, params => this.deviceStatusPrivate(params));
258
245
  this._parser.registerCsiHandler({ intermediates: '!', final: 'p' }, params => this.softReset(params));
246
+ this._parser.registerCsiHandler({ prefix: '>', final: 'q' }, params => this.sendXtVersion(params));
259
247
  this._parser.registerCsiHandler({ intermediates: ' ', final: 'q' }, params => this.setCursorStyle(params));
260
248
  this._parser.registerCsiHandler({ final: 'r' }, params => this.setScrollRegion(params));
261
249
  this._parser.registerCsiHandler({ final: 's' }, params => this.saveCursor(params));
@@ -267,6 +255,12 @@ export class InputHandler extends Disposable implements IInputHandler {
267
255
  this._parser.registerCsiHandler({ intermediates: '$', final: 'p' }, params => this.requestMode(params, true));
268
256
  this._parser.registerCsiHandler({ prefix: '?', intermediates: '$', final: 'p' }, params => this.requestMode(params, false));
269
257
 
258
+ // Kitty keyboard protocol handlers
259
+ this._parser.registerCsiHandler({ prefix: '=', final: 'u' }, params => this.kittyKeyboardSet(params));
260
+ this._parser.registerCsiHandler({ prefix: '?', final: 'u' }, params => this.kittyKeyboardQuery(params));
261
+ this._parser.registerCsiHandler({ prefix: '>', final: 'u' }, params => this.kittyKeyboardPush(params));
262
+ this._parser.registerCsiHandler({ prefix: '<', final: 'u' }, params => this.kittyKeyboardPop(params));
263
+
270
264
  /**
271
265
  * execute handler
272
266
  */
@@ -395,12 +389,23 @@ export class InputHandler extends Disposable implements IInputHandler {
395
389
  private _logSlowResolvingAsync(p: Promise<boolean>): void {
396
390
  // log a limited warning about an async handler taking too long
397
391
  if (this._logService.logLevel <= LogLevelEnum.WARN) {
398
- Promise.race([p, new Promise((res, rej) => setTimeout(() => rej('#SLOW_TIMEOUT'), SLOW_ASYNC_LIMIT))])
399
- .catch(err => {
392
+ let slowTimeout: ReturnType<typeof setTimeout> | undefined;
393
+ const slowPromise = new Promise<never>((_res, rej) => {
394
+ slowTimeout = setTimeout(() => rej('#SLOW_TIMEOUT'), Constants.SLOW_ASYNC_LIMIT);
395
+ });
396
+ Promise.race([p, slowPromise])
397
+ .then(() => {
398
+ if (slowTimeout !== undefined) {
399
+ clearTimeout(slowTimeout);
400
+ }
401
+ }, err => {
402
+ if (slowTimeout !== undefined) {
403
+ clearTimeout(slowTimeout);
404
+ }
400
405
  if (err !== '#SLOW_TIMEOUT') {
401
406
  throw err;
402
407
  }
403
- console.warn(`async parser handler taking longer than ${SLOW_ASYNC_LIMIT} ms`);
408
+ console.warn(`async parser handler taking longer than ${Constants.SLOW_ASYNC_LIMIT} ms`);
404
409
  });
405
410
  }
406
411
  }
@@ -438,8 +443,8 @@ export class InputHandler extends Disposable implements IInputHandler {
438
443
  cursorStartX = this._parseStack.cursorStartX;
439
444
  cursorStartY = this._parseStack.cursorStartY;
440
445
  this._parseStack.paused = false;
441
- if (data.length > MAX_PARSEBUFFER_LENGTH) {
442
- start = this._parseStack.position + MAX_PARSEBUFFER_LENGTH;
446
+ if (data.length > Constants.MAX_PARSEBUFFER_LENGTH) {
447
+ start = this._parseStack.position + Constants.MAX_PARSEBUFFER_LENGTH;
443
448
  }
444
449
  }
445
450
 
@@ -456,8 +461,8 @@ export class InputHandler extends Disposable implements IInputHandler {
456
461
 
457
462
  // resize input buffer if needed
458
463
  if (this._parseBuffer.length < data.length) {
459
- if (this._parseBuffer.length < MAX_PARSEBUFFER_LENGTH) {
460
- this._parseBuffer = new Uint32Array(Math.min(data.length, MAX_PARSEBUFFER_LENGTH));
464
+ if (this._parseBuffer.length < Constants.MAX_PARSEBUFFER_LENGTH) {
465
+ this._parseBuffer = new Uint32Array(Math.min(data.length, Constants.MAX_PARSEBUFFER_LENGTH));
461
466
  }
462
467
  }
463
468
 
@@ -468,9 +473,9 @@ export class InputHandler extends Disposable implements IInputHandler {
468
473
  }
469
474
 
470
475
  // process big data in smaller chunks
471
- if (data.length > MAX_PARSEBUFFER_LENGTH) {
472
- for (let i = start; i < data.length; i += MAX_PARSEBUFFER_LENGTH) {
473
- const end = i + MAX_PARSEBUFFER_LENGTH < data.length ? i + MAX_PARSEBUFFER_LENGTH : data.length;
476
+ if (data.length > Constants.MAX_PARSEBUFFER_LENGTH) {
477
+ for (let i = start; i < data.length; i += Constants.MAX_PARSEBUFFER_LENGTH) {
478
+ const end = i + Constants.MAX_PARSEBUFFER_LENGTH < data.length ? i + Constants.MAX_PARSEBUFFER_LENGTH : data.length;
474
479
  const len = (typeof data === 'string')
475
480
  ? this._stringDecoder.decode(data.substring(i, end), this._parseBuffer)
476
481
  : this._utf8Decoder.decode(data.subarray(i, end), this._parseBuffer);
@@ -518,7 +523,13 @@ export class InputHandler extends Disposable implements IInputHandler {
518
523
  const wraparoundMode = this._coreService.decPrivateModes.wraparound;
519
524
  const insertMode = this._coreService.modes.insertMode;
520
525
  const curAttr = this._curAttrData;
521
- let bufferRow = this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y)!;
526
+ let bufferRow = this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y);
527
+
528
+ // Defensive check: bufferRow can be undefined if a resize occurred mid-write due to async
529
+ // scheduling gaps in WriteBuffer. See https://github.com/xtermjs/xterm.js/issues/5597
530
+ if (!bufferRow) {
531
+ return;
532
+ }
522
533
 
523
534
  this._dirtyRowTracker.markDirty(this._activeBuffer.y);
524
535
 
@@ -531,6 +542,12 @@ export class InputHandler extends Disposable implements IInputHandler {
531
542
  for (let pos = start; pos < end; ++pos) {
532
543
  code = data[pos];
533
544
 
545
+ // Soft hyphen's (U+00AD) behavior is ambiguous and differs across terminals. We opt to treat
546
+ // it as a zero-width hint to text layout engines and simply ignore it.
547
+ if (code === 0xAD) {
548
+ continue;
549
+ }
550
+
534
551
  // get charset replacement character
535
552
  // charset is only defined for ASCII, therefore we only
536
553
  // search for an replacement char if code < 127
@@ -577,7 +594,10 @@ export class InputHandler extends Disposable implements IInputHandler {
577
594
  this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y)!.isWrapped = true;
578
595
  }
579
596
  // row changed, get it again
580
- bufferRow = this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y)!;
597
+ bufferRow = this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y);
598
+ if (!bufferRow) {
599
+ return;
600
+ }
581
601
  if (oldWidth > 0 && bufferRow instanceof BufferLine) {
582
602
  // Combining character widens 1 column to 2.
583
603
  // Move old character to next line.
@@ -688,6 +708,13 @@ export class InputHandler extends Disposable implements IInputHandler {
688
708
  return this._parser.registerOscHandler(ident, new OscHandler(callback));
689
709
  }
690
710
 
711
+ /**
712
+ * Forward registerApcHandler from parser.
713
+ */
714
+ public registerApcHandler(id: IFunctionIdentifier, callback: (data: string) => boolean | Promise<boolean>): IDisposable {
715
+ return this._parser.registerApcHandler(id, new ApcHandler(callback));
716
+ }
717
+
691
718
  /**
692
719
  * BEL
693
720
  * Bell (Ctrl-G).
@@ -1145,7 +1172,10 @@ export class InputHandler extends Disposable implements IInputHandler {
1145
1172
  * @param respectProtect Whether to respect the protection attribute (DECSCA).
1146
1173
  */
1147
1174
  private _eraseInBufferLine(y: number, start: number, end: number, clearWrap: boolean = false, respectProtect: boolean = false): void {
1148
- const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + y)!;
1175
+ const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + y);
1176
+ if (!line) {
1177
+ return;
1178
+ }
1149
1179
  line.replaceCells(
1150
1180
  start,
1151
1181
  end,
@@ -1215,7 +1245,10 @@ export class InputHandler extends Disposable implements IInputHandler {
1215
1245
  this._eraseInBufferLine(j, 0, this._activeBuffer.x + 1, true, respectProtect);
1216
1246
  if (this._activeBuffer.x + 1 >= this._bufferService.cols) {
1217
1247
  // Deleted entire previous line. This next line can no longer be wrapped.
1218
- this._activeBuffer.lines.get(j + 1)!.isWrapped = false;
1248
+ const nextLine = this._activeBuffer.lines.get(j + 1);
1249
+ if (nextLine) {
1250
+ nextLine.isWrapped = false;
1251
+ }
1219
1252
  }
1220
1253
  while (j--) {
1221
1254
  this._resetBufferLine(j, respectProtect);
@@ -1721,12 +1754,28 @@ export class InputHandler extends Disposable implements IInputHandler {
1721
1754
  return true;
1722
1755
  }
1723
1756
 
1757
+ /**
1758
+ * CSI > Ps q
1759
+ * Ps = 0 => Report xterm name and version (XTVERSION).
1760
+ *
1761
+ * The response is a DCS sequence identifying the version: DCS > | text ST
1762
+ *
1763
+ * @vt: #Y CSI XTVERSION "Report Xterm Version" "CSI > q" "Report the terminal name and version."
1764
+ */
1765
+ public sendXtVersion(params: IParams): boolean {
1766
+ if (params.params[0] > 0) {
1767
+ return true;
1768
+ }
1769
+ this._coreService.triggerDataEvent(`${C0.ESC}P>|xterm.js(${XTERM_VERSION})${C0.ESC}\\`);
1770
+ return true;
1771
+ }
1772
+
1724
1773
  /**
1725
1774
  * Evaluate if the current terminal is the given argument.
1726
1775
  * @param term The terminal name to evaluate
1727
1776
  */
1728
1777
  private _is(term: string): boolean {
1729
- return (this._optionsService.rawOptions.termName + '').indexOf(term) === 0;
1778
+ return (this._optionsService.rawOptions.termName + '').startsWith(term);
1730
1779
  }
1731
1780
 
1732
1781
  /**
@@ -1853,7 +1902,7 @@ export class InputHandler extends Disposable implements IInputHandler {
1853
1902
  * | 7 | Auto-wrap Mode (DECAWM). | #Y |
1854
1903
  * | 8 | Auto-repeat Keys (DECARM). Always on. | #N |
1855
1904
  * | 9 | X10 xterm mouse protocol. | #Y |
1856
- * | 12 | Start Blinking Cursor. | #Y |
1905
+ * | 12 | Start Blinking Cursor. | #P[Requires the allowSetCursorBlink quirk option enabled.] |
1857
1906
  * | 25 | Show Cursor (DECTCEM). | #Y |
1858
1907
  * | 45 | Reverse wrap-around. | #Y |
1859
1908
  * | 47 | Use Alternate Screen Buffer. | #Y |
@@ -1906,7 +1955,9 @@ export class InputHandler extends Disposable implements IInputHandler {
1906
1955
  this._coreService.decPrivateModes.wraparound = true;
1907
1956
  break;
1908
1957
  case 12:
1909
- this._optionsService.options.cursorBlink = true;
1958
+ if (this._optionsService.rawOptions.quirks?.allowSetCursorBlink) {
1959
+ this._optionsService.options.cursorBlink = true;
1960
+ }
1910
1961
  break;
1911
1962
  case 45:
1912
1963
  this._coreService.decPrivateModes.reverseWraparound = true;
@@ -1918,19 +1969,19 @@ export class InputHandler extends Disposable implements IInputHandler {
1918
1969
  break;
1919
1970
  case 9: // X10 Mouse
1920
1971
  // no release, no motion, no wheel, no modifiers.
1921
- this._coreMouseService.activeProtocol = 'X10';
1972
+ this._mouseStateService.activeProtocol = 'X10';
1922
1973
  break;
1923
1974
  case 1000: // vt200 mouse
1924
1975
  // no motion.
1925
- this._coreMouseService.activeProtocol = 'VT200';
1976
+ this._mouseStateService.activeProtocol = 'VT200';
1926
1977
  break;
1927
1978
  case 1002: // button event mouse
1928
- this._coreMouseService.activeProtocol = 'DRAG';
1979
+ this._mouseStateService.activeProtocol = 'DRAG';
1929
1980
  break;
1930
1981
  case 1003: // any event mouse
1931
1982
  // any event - sends motion events,
1932
1983
  // even if there is no button held down.
1933
- this._coreMouseService.activeProtocol = 'ANY';
1984
+ this._mouseStateService.activeProtocol = 'ANY';
1934
1985
  break;
1935
1986
  case 1004: // send focusin/focusout events
1936
1987
  // focusin: ^[[I
@@ -1942,13 +1993,13 @@ export class InputHandler extends Disposable implements IInputHandler {
1942
1993
  this._logService.debug('DECSET 1005 not supported (see #2507)');
1943
1994
  break;
1944
1995
  case 1006: // sgr ext mode mouse
1945
- this._coreMouseService.activeEncoding = 'SGR';
1996
+ this._mouseStateService.activeEncoding = 'SGR';
1946
1997
  break;
1947
1998
  case 1015: // urxvt ext mode mouse - removed in #2507
1948
1999
  this._logService.debug('DECSET 1015 not supported (see #2507)');
1949
2000
  break;
1950
2001
  case 1016: // sgr pixels mode mouse
1951
- this._coreMouseService.activeEncoding = 'SGR_PIXELS';
2002
+ this._mouseStateService.activeEncoding = 'SGR_PIXELS';
1952
2003
  break;
1953
2004
  case 25: // show cursor
1954
2005
  this._coreService.isCursorHidden = false;
@@ -1961,6 +2012,12 @@ export class InputHandler extends Disposable implements IInputHandler {
1961
2012
  // FALL-THROUGH
1962
2013
  case 47: // alt screen buffer
1963
2014
  case 1047: // alt screen buffer
2015
+ // Swap kitty keyboard flags: save main, restore alt
2016
+ if (this._optionsService.rawOptions.vtExtensions?.kittyKeyboard) {
2017
+ const state = this._coreService.kittyKeyboard;
2018
+ state.mainFlags = state.flags;
2019
+ state.flags = state.altFlags;
2020
+ }
1964
2021
  this._bufferService.buffers.activateAltBuffer(this._eraseAttrData());
1965
2022
  this._coreService.isCursorInitialized = true;
1966
2023
  this._onRequestRefreshRows.fire(undefined);
@@ -1972,6 +2029,16 @@ export class InputHandler extends Disposable implements IInputHandler {
1972
2029
  case 2026: // synchronized output (https://github.com/contour-terminal/vt-extensions/blob/master/synchronized-output.md)
1973
2030
  this._coreService.decPrivateModes.synchronizedOutput = true;
1974
2031
  break;
2032
+ case 2031: // color scheme updates (https://contour-terminal.org/vt-extensions/color-palette-update-notifications/)
2033
+ if (this._optionsService.rawOptions.vtExtensions?.colorSchemeQuery ?? true) {
2034
+ this._coreService.decPrivateModes.colorSchemeUpdates = true;
2035
+ }
2036
+ break;
2037
+ case 9001: // win32-input-mode (https://github.com/microsoft/terminal/blob/main/doc/specs/%234999%20-%20Improved%20keyboard%20handling%20in%20Conpty.md)
2038
+ if (this._optionsService.rawOptions.vtExtensions?.win32InputMode) {
2039
+ this._coreService.decPrivateModes.win32InputMode = true;
2040
+ }
2041
+ break;
1975
2042
  }
1976
2043
  }
1977
2044
  return true;
@@ -2101,7 +2168,7 @@ export class InputHandler extends Disposable implements IInputHandler {
2101
2168
  * | 7 | No Wraparound Mode (DECAWM). | #Y |
2102
2169
  * | 8 | No Auto-repeat Keys (DECARM). | #N |
2103
2170
  * | 9 | Don't send Mouse X & Y on button press. | #Y |
2104
- * | 12 | Stop Blinking Cursor. | #Y |
2171
+ * | 12 | Stop Blinking Cursor. | #P[Requires the allowSetCursorBlink quirk option enabled.] |
2105
2172
  * | 25 | Hide Cursor (DECTCEM). | #Y |
2106
2173
  * | 45 | No reverse wrap-around. | #Y |
2107
2174
  * | 47 | Use Normal Screen Buffer. | #Y |
@@ -2147,7 +2214,9 @@ export class InputHandler extends Disposable implements IInputHandler {
2147
2214
  this._coreService.decPrivateModes.wraparound = false;
2148
2215
  break;
2149
2216
  case 12:
2150
- this._optionsService.options.cursorBlink = false;
2217
+ if (this._optionsService.rawOptions.quirks?.allowSetCursorBlink) {
2218
+ this._optionsService.options.cursorBlink = false;
2219
+ }
2151
2220
  break;
2152
2221
  case 45:
2153
2222
  this._coreService.decPrivateModes.reverseWraparound = false;
@@ -2161,7 +2230,7 @@ export class InputHandler extends Disposable implements IInputHandler {
2161
2230
  case 1000: // vt200 mouse
2162
2231
  case 1002: // button event mouse
2163
2232
  case 1003: // any event mouse
2164
- this._coreMouseService.activeProtocol = 'NONE';
2233
+ this._mouseStateService.activeProtocol = 'NONE';
2165
2234
  break;
2166
2235
  case 1004: // send focusin/focusout events
2167
2236
  this._coreService.decPrivateModes.sendFocus = false;
@@ -2170,13 +2239,13 @@ export class InputHandler extends Disposable implements IInputHandler {
2170
2239
  this._logService.debug('DECRST 1005 not supported (see #2507)');
2171
2240
  break;
2172
2241
  case 1006: // sgr ext mode mouse
2173
- this._coreMouseService.activeEncoding = 'DEFAULT';
2242
+ this._mouseStateService.activeEncoding = 'DEFAULT';
2174
2243
  break;
2175
2244
  case 1015: // urxvt ext mode mouse - removed in #2507
2176
2245
  this._logService.debug('DECRST 1015 not supported (see #2507)');
2177
2246
  break;
2178
2247
  case 1016: // sgr pixels mode mouse
2179
- this._coreMouseService.activeEncoding = 'DEFAULT';
2248
+ this._mouseStateService.activeEncoding = 'DEFAULT';
2180
2249
  break;
2181
2250
  case 25: // hide cursor
2182
2251
  this._coreService.isCursorHidden = true;
@@ -2188,6 +2257,12 @@ export class InputHandler extends Disposable implements IInputHandler {
2188
2257
  // FALL-THROUGH
2189
2258
  case 47: // normal screen buffer
2190
2259
  case 1047: // normal screen buffer - clearing it first
2260
+ // Swap kitty keyboard flags: save alt, restore main
2261
+ if (this._optionsService.rawOptions.vtExtensions?.kittyKeyboard) {
2262
+ const state = this._coreService.kittyKeyboard;
2263
+ state.altFlags = state.flags;
2264
+ state.flags = state.mainFlags;
2265
+ }
2191
2266
  // Ensure the selection manager has the correct buffer
2192
2267
  this._bufferService.buffers.activateNormalBuffer();
2193
2268
  if (params.params[i] === 1049) {
@@ -2204,6 +2279,16 @@ export class InputHandler extends Disposable implements IInputHandler {
2204
2279
  this._coreService.decPrivateModes.synchronizedOutput = false;
2205
2280
  this._onRequestRefreshRows.fire(undefined);
2206
2281
  break;
2282
+ case 2031: // color scheme updates (https://contour-terminal.org/vt-extensions/color-palette-update-notifications/)
2283
+ if (this._optionsService.rawOptions.vtExtensions?.colorSchemeQuery ?? true) {
2284
+ this._coreService.decPrivateModes.colorSchemeUpdates = false;
2285
+ }
2286
+ break;
2287
+ case 9001: // win32-input-mode
2288
+ if (this._optionsService.rawOptions.vtExtensions?.win32InputMode) {
2289
+ this._coreService.decPrivateModes.win32InputMode = false;
2290
+ }
2291
+ break;
2207
2292
  }
2208
2293
  }
2209
2294
  return true;
@@ -2254,7 +2339,7 @@ export class InputHandler extends Disposable implements IInputHandler {
2254
2339
 
2255
2340
  // access helpers
2256
2341
  const dm = this._coreService.decPrivateModes;
2257
- const { activeProtocol: mouseProtocol, activeEncoding: mouseEncoding } = this._coreMouseService;
2342
+ const { activeProtocol: mouseProtocol, activeEncoding: mouseEncoding } = this._mouseStateService;
2258
2343
  const cs = this._coreService;
2259
2344
  const { buffers, cols } = this._bufferService;
2260
2345
  const { active, alt } = buffers;
@@ -2299,6 +2384,7 @@ export class InputHandler extends Disposable implements IInputHandler {
2299
2384
  if (p === 47 || p === 1047 || p === 1049) return f(p, b2v(active === alt));
2300
2385
  if (p === 2004) return f(p, b2v(dm.bracketedPasteMode));
2301
2386
  if (p === 2026) return f(p, b2v(dm.synchronizedOutput));
2387
+ if (p === 9001) return this._optionsService.rawOptions.vtExtensions?.win32InputMode ? f(p, b2v(dm.win32InputMode)) : f(p, V.NOT_RECOGNIZED);
2302
2388
  return f(p, V.NOT_RECOGNIZED);
2303
2389
  }
2304
2390
 
@@ -2311,7 +2397,7 @@ export class InputHandler extends Disposable implements IInputHandler {
2311
2397
  color &= ~Attributes.RGB_MASK;
2312
2398
  color |= AttributeData.fromColorRGB([c1, c2, c3]);
2313
2399
  } else if (mode === 5) {
2314
- color &= ~(Attributes.CM_MASK | Attributes.PCOLOR_MASK);
2400
+ color &= ~(Attributes.CM_MASK | Attributes.RGB_MASK);
2315
2401
  color |= Attributes.CM_P256 | (c1 & 0xff);
2316
2402
  }
2317
2403
  return color;
@@ -2476,6 +2562,8 @@ export class InputHandler extends Disposable implements IInputHandler {
2476
2562
  * | 53 | Overlined. | #Y |
2477
2563
  * | 55 | Not Overlined. | #Y |
2478
2564
  * | 58 | Underline color: Extended color. | #P[Support for RGB and indexed colors, see below.] |
2565
+ * | 221 | Not bold (kitty extension). | #Y |
2566
+ * | 222 | Not faint (kitty extension). | #Y |
2479
2567
  * | 90 - 97 | Bright foreground color (analogous to 30 - 37). | #Y |
2480
2568
  * | 100 - 107 | Bright background color (analogous to 40 - 47). | #Y |
2481
2569
  *
@@ -2502,10 +2590,6 @@ export class InputHandler extends Disposable implements IInputHandler {
2502
2590
  * | 3 | CMY color. | #N |
2503
2591
  * | 4 | CMYK color. | #N |
2504
2592
  * | 5 | Indexed (256 colors) as `Ps ; 5 ; INDEX` or `Ps : 5 : INDEX`. | #Y |
2505
- *
2506
- *
2507
- * FIXME: blinking is implemented in attrs, but not working in renderers?
2508
- * FIXME: remove dead branch for p=100
2509
2593
  */
2510
2594
  public charAttributes(params: IParams): boolean {
2511
2595
  // Optimize a single SGR0.
@@ -2522,19 +2606,19 @@ export class InputHandler extends Disposable implements IInputHandler {
2522
2606
  p = params.params[i];
2523
2607
  if (p >= 30 && p <= 37) {
2524
2608
  // fg color 8
2525
- attr.fg &= ~(Attributes.CM_MASK | Attributes.PCOLOR_MASK);
2609
+ attr.fg &= ~(Attributes.CM_MASK | Attributes.RGB_MASK);
2526
2610
  attr.fg |= Attributes.CM_P16 | (p - 30);
2527
2611
  } else if (p >= 40 && p <= 47) {
2528
2612
  // bg color 8
2529
- attr.bg &= ~(Attributes.CM_MASK | Attributes.PCOLOR_MASK);
2613
+ attr.bg &= ~(Attributes.CM_MASK | Attributes.RGB_MASK);
2530
2614
  attr.bg |= Attributes.CM_P16 | (p - 40);
2531
2615
  } else if (p >= 90 && p <= 97) {
2532
2616
  // fg color 16
2533
- attr.fg &= ~(Attributes.CM_MASK | Attributes.PCOLOR_MASK);
2617
+ attr.fg &= ~(Attributes.CM_MASK | Attributes.RGB_MASK);
2534
2618
  attr.fg |= Attributes.CM_P16 | (p - 90) | 8;
2535
2619
  } else if (p >= 100 && p <= 107) {
2536
2620
  // bg color 16
2537
- attr.bg &= ~(Attributes.CM_MASK | Attributes.PCOLOR_MASK);
2621
+ attr.bg &= ~(Attributes.CM_MASK | Attributes.RGB_MASK);
2538
2622
  attr.bg |= Attributes.CM_P16 | (p - 100) | 8;
2539
2623
  } else if (p === 0) {
2540
2624
  // default
@@ -2594,11 +2678,11 @@ export class InputHandler extends Disposable implements IInputHandler {
2594
2678
  } else if (p === 39) {
2595
2679
  // reset fg
2596
2680
  attr.fg &= ~(Attributes.CM_MASK | Attributes.RGB_MASK);
2597
- attr.fg |= DEFAULT_ATTR_DATA.fg & (Attributes.PCOLOR_MASK | Attributes.RGB_MASK);
2681
+ attr.fg |= DEFAULT_ATTR_DATA.fg & Attributes.RGB_MASK;
2598
2682
  } else if (p === 49) {
2599
2683
  // reset bg
2600
2684
  attr.bg &= ~(Attributes.CM_MASK | Attributes.RGB_MASK);
2601
- attr.bg |= DEFAULT_ATTR_DATA.bg & (Attributes.PCOLOR_MASK | Attributes.RGB_MASK);
2685
+ attr.bg |= DEFAULT_ATTR_DATA.bg & Attributes.RGB_MASK;
2602
2686
  } else if (p === 38 || p === 48 || p === 58) {
2603
2687
  // fg color 256 and RGB
2604
2688
  i += this._extractColor(params, i, attr);
@@ -2608,16 +2692,16 @@ export class InputHandler extends Disposable implements IInputHandler {
2608
2692
  } else if (p === 55) {
2609
2693
  // not overline
2610
2694
  attr.bg &= ~BgFlags.OVERLINE;
2695
+ } else if (p === 221 && (this._optionsService.rawOptions.vtExtensions?.kittySgrBoldFaintControl ?? true)) {
2696
+ // not bold (kitty extension)
2697
+ attr.fg &= ~FgFlags.BOLD;
2698
+ } else if (p === 222 && (this._optionsService.rawOptions.vtExtensions?.kittySgrBoldFaintControl ?? true)) {
2699
+ // not faint (kitty extension)
2700
+ attr.bg &= ~BgFlags.DIM;
2611
2701
  } else if (p === 59) {
2612
2702
  attr.extended = attr.extended.clone();
2613
2703
  attr.extended.underlineColor = -1;
2614
2704
  attr.updateExtended();
2615
- } else if (p === 100) { // FIXME: dead branch, p=100 already handled above!
2616
- // reset fg/bg
2617
- attr.fg &= ~(Attributes.CM_MASK | Attributes.RGB_MASK);
2618
- attr.fg |= DEFAULT_ATTR_DATA.fg & (Attributes.PCOLOR_MASK | Attributes.RGB_MASK);
2619
- attr.bg &= ~(Attributes.CM_MASK | Attributes.RGB_MASK);
2620
- attr.bg |= DEFAULT_ATTR_DATA.bg & (Attributes.PCOLOR_MASK | Attributes.RGB_MASK);
2621
2705
  } else {
2622
2706
  this._logService.debug('Unknown SGR attribute: %d.', p);
2623
2707
  }
@@ -2693,6 +2777,12 @@ export class InputHandler extends Disposable implements IInputHandler {
2693
2777
  // no dec locator/mouse
2694
2778
  // this.handler(C0.ESC + '[?50n');
2695
2779
  break;
2780
+ case 996:
2781
+ // color scheme query (https://contour-terminal.org/vt-extensions/color-palette-update-notifications/)
2782
+ if (this._optionsService.rawOptions.vtExtensions?.colorSchemeQuery ?? true) {
2783
+ this._onRequestColorSchemeQuery.fire();
2784
+ }
2785
+ break;
2696
2786
  }
2697
2787
  return true;
2698
2788
  }
@@ -2859,13 +2949,13 @@ export class InputHandler extends Disposable implements IInputHandler {
2859
2949
  case 22: // PushTitle
2860
2950
  if (second === 0 || second === 2) {
2861
2951
  this._windowTitleStack.push(this._windowTitle);
2862
- if (this._windowTitleStack.length > STACK_LIMIT) {
2952
+ if (this._windowTitleStack.length > Constants.STACK_LIMIT) {
2863
2953
  this._windowTitleStack.shift();
2864
2954
  }
2865
2955
  }
2866
2956
  if (second === 0 || second === 1) {
2867
2957
  this._iconNameStack.push(this._iconName);
2868
- if (this._iconNameStack.length > STACK_LIMIT) {
2958
+ if (this._iconNameStack.length > Constants.STACK_LIMIT) {
2869
2959
  this._iconNameStack.shift();
2870
2960
  }
2871
2961
  }
@@ -2901,6 +2991,10 @@ export class InputHandler extends Disposable implements IInputHandler {
2901
2991
  this._activeBuffer.savedCurAttrData.fg = this._curAttrData.fg;
2902
2992
  this._activeBuffer.savedCurAttrData.bg = this._curAttrData.bg;
2903
2993
  this._activeBuffer.savedCharset = this._charsetService.charset;
2994
+ this._activeBuffer.savedCharsets = this._charsetService.charsets.slice();
2995
+ this._activeBuffer.savedGlevel = this._charsetService.glevel;
2996
+ this._activeBuffer.savedOriginMode = this._coreService.decPrivateModes.origin;
2997
+ this._activeBuffer.savedWraparoundMode = this._coreService.decPrivateModes.wraparound;
2904
2998
  return true;
2905
2999
  }
2906
3000
 
@@ -2918,15 +3012,16 @@ export class InputHandler extends Disposable implements IInputHandler {
2918
3012
  this._activeBuffer.y = Math.max(this._activeBuffer.savedY - this._activeBuffer.ybase, 0);
2919
3013
  this._curAttrData.fg = this._activeBuffer.savedCurAttrData.fg;
2920
3014
  this._curAttrData.bg = this._activeBuffer.savedCurAttrData.bg;
2921
- this._charsetService.charset = (this as any)._savedCharset;
2922
- if (this._activeBuffer.savedCharset) {
2923
- this._charsetService.charset = this._activeBuffer.savedCharset;
3015
+ for (let i = 0; i < this._activeBuffer.savedCharsets.length; i++) {
3016
+ this._charsetService.setgCharset(i, this._activeBuffer.savedCharsets[i]);
2924
3017
  }
3018
+ this._charsetService.setgLevel(this._activeBuffer.savedGlevel);
3019
+ this._coreService.decPrivateModes.origin = this._activeBuffer.savedOriginMode;
3020
+ this._coreService.decPrivateModes.wraparound = this._activeBuffer.savedWraparoundMode;
2925
3021
  this._restrictCursor();
2926
3022
  return true;
2927
3023
  }
2928
3024
 
2929
-
2930
3025
  /**
2931
3026
  * OSC 2; <data> ST (set window title)
2932
3027
  * Proxy to set window title.
@@ -3249,7 +3344,7 @@ export class InputHandler extends Disposable implements IInputHandler {
3249
3344
  if (collectAndFlag[0] === '/') {
3250
3345
  return true; // TODO: Is this supported?
3251
3346
  }
3252
- this._charsetService.setgCharset(GLEVEL[collectAndFlag[0]], CHARSETS[collectAndFlag[1]] || DEFAULT_CHARSET);
3347
+ this._charsetService.setgCharset(GLEVEL[collectAndFlag[0]], CHARSETS[collectAndFlag[1]] ?? DEFAULT_CHARSET);
3253
3348
  return true;
3254
3349
  }
3255
3350
 
@@ -3320,6 +3415,8 @@ export class InputHandler extends Disposable implements IInputHandler {
3320
3415
  * ESC c
3321
3416
  * DEC mnemonic: RIS (https://vt100.net/docs/vt510-rm/RIS.html)
3322
3417
  * Reset to initial state.
3418
+ *
3419
+ * @vt: #Y ESC RIS "Full Reset" "ESC c" "Reset to initial state."
3323
3420
  */
3324
3421
  public fullReset(): boolean {
3325
3422
  this._parser.reset();
@@ -3436,6 +3533,107 @@ export class InputHandler extends Disposable implements IInputHandler {
3436
3533
  public markRangeDirty(y1: number, y2: number): void {
3437
3534
  this._dirtyRowTracker.markRangeDirty(y1, y2);
3438
3535
  }
3536
+
3537
+ // #region Kitty keyboard
3538
+
3539
+ /**
3540
+ * CSI = flags ; mode u
3541
+ * Set Kitty keyboard protocol flags.
3542
+ * mode: 1=set, 2=set-only-specified, 3=reset-only-specified
3543
+ *
3544
+ * @vt: #Y CSI KKBDSET "Kitty Keyboard Set" "CSI = Ps ; Pm u" "Set Kitty keyboard protocol flags."
3545
+ */
3546
+ public kittyKeyboardSet(params: IParams): boolean {
3547
+ if (!this._optionsService.rawOptions.vtExtensions?.kittyKeyboard) {
3548
+ return true;
3549
+ }
3550
+ const flags = params.params[0] || 0;
3551
+ const mode = params.length > 1 ? (params.params[1] || 1) : 1;
3552
+ const state = this._coreService.kittyKeyboard;
3553
+
3554
+ switch (mode) {
3555
+ case 1: // Set all flags
3556
+ state.flags = flags;
3557
+ break;
3558
+ case 2: // Set only specified flags (OR)
3559
+ state.flags |= flags;
3560
+ break;
3561
+ case 3: // Reset only specified flags (AND NOT)
3562
+ state.flags &= ~flags;
3563
+ break;
3564
+ }
3565
+ return true;
3566
+ }
3567
+
3568
+ /**
3569
+ * CSI ? u
3570
+ * Query Kitty keyboard protocol flags.
3571
+ * Terminal responds with CSI ? flags u
3572
+ *
3573
+ * @vt: #Y CSI KKBDQUERY "Kitty Keyboard Query" "CSI ? u" "Query Kitty keyboard protocol flags."
3574
+ */
3575
+ public kittyKeyboardQuery(params: IParams): boolean {
3576
+ if (!this._optionsService.rawOptions.vtExtensions?.kittyKeyboard) {
3577
+ return true;
3578
+ }
3579
+ const flags = this._coreService.kittyKeyboard.flags;
3580
+ this._coreService.triggerDataEvent(`${C0.ESC}[?${flags}u`);
3581
+ return true;
3582
+ }
3583
+
3584
+ /**
3585
+ * CSI > flags u
3586
+ * Push Kitty keyboard flags onto stack and set new flags.
3587
+ *
3588
+ * @vt: #Y CSI KKBDPUSH "Kitty Keyboard Push" "CSI > Ps u" "Push keyboard flags to stack and set new flags."
3589
+ */
3590
+ public kittyKeyboardPush(params: IParams): boolean {
3591
+ if (!this._optionsService.rawOptions.vtExtensions?.kittyKeyboard) {
3592
+ return true;
3593
+ }
3594
+ const flags = params.params[0] || 0;
3595
+ const state = this._coreService.kittyKeyboard;
3596
+ const isAlt = this._bufferService.buffer === this._bufferService.buffers.alt;
3597
+ const stack = isAlt ? state.altStack : state.mainStack;
3598
+
3599
+ // Evict oldest entry if stack is full (DoS protection, limit of 16)
3600
+ if (stack.length >= 16) {
3601
+ stack.shift();
3602
+ }
3603
+
3604
+ // Push current flags onto stack and set new flags
3605
+ stack.push(state.flags);
3606
+ state.flags = flags;
3607
+ return true;
3608
+ }
3609
+
3610
+ /**
3611
+ * CSI < count u
3612
+ * Pop Kitty keyboard flags from stack.
3613
+ *
3614
+ * @vt: #Y CSI KKBDPOP "Kitty Keyboard Pop" "CSI < Ps u" "Pop keyboard flags from stack."
3615
+ */
3616
+ public kittyKeyboardPop(params: IParams): boolean {
3617
+ if (!this._optionsService.rawOptions.vtExtensions?.kittyKeyboard) {
3618
+ return true;
3619
+ }
3620
+ const count = Math.max(1, params.params[0] || 1);
3621
+ const state = this._coreService.kittyKeyboard;
3622
+ const isAlt = this._bufferService.buffer === this._bufferService.buffers.alt;
3623
+ const stack = isAlt ? state.altStack : state.mainStack;
3624
+
3625
+ // Pop specified number of entries from stack
3626
+ for (let i = 0; i < count && stack.length > 0; i++) {
3627
+ state.flags = stack.pop()!;
3628
+ }
3629
+ // If stack is empty after popping, reset to 0
3630
+ if (stack.length === 0 && count > 0) {
3631
+ state.flags = 0;
3632
+ }
3633
+ return true;
3634
+ }
3635
+
3636
+ // #endregion
3439
3637
  }
3440
3638
 
3441
3639
  export interface IDirtyRowTracker {