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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/README.md +62 -38
  2. package/css/xterm.css +29 -22
  3. package/lib/xterm.js +1 -1
  4. package/lib/xterm.js.map +1 -1
  5. package/lib/xterm.mjs +8 -34
  6. package/lib/xterm.mjs.map +4 -4
  7. package/package.json +25 -22
  8. package/src/browser/AccessibilityManager.ts +11 -6
  9. package/src/browser/Clipboard.ts +6 -3
  10. package/src/browser/CoreBrowserTerminal.ts +149 -319
  11. package/src/browser/Dom.ts +178 -0
  12. package/src/browser/Linkifier.ts +11 -11
  13. package/src/browser/OscLinkProvider.ts +82 -14
  14. package/src/browser/RenderDebouncer.ts +2 -2
  15. package/src/browser/TimeBasedDebouncer.ts +2 -2
  16. package/src/browser/Types.ts +12 -11
  17. package/src/browser/Viewport.ts +55 -20
  18. package/src/browser/decorations/BufferDecorationRenderer.ts +1 -1
  19. package/src/browser/decorations/OverviewRulerRenderer.ts +33 -17
  20. package/src/browser/input/CompositionHelper.ts +44 -8
  21. package/src/browser/public/Terminal.ts +25 -28
  22. package/src/browser/renderer/dom/DomRenderer.ts +242 -76
  23. package/src/browser/renderer/dom/DomRendererRowFactory.ts +19 -13
  24. package/src/browser/renderer/dom/WidthCache.ts +54 -52
  25. package/src/browser/renderer/shared/Constants.ts +7 -0
  26. package/src/browser/renderer/shared/TextBlinkStateManager.ts +97 -0
  27. package/src/browser/renderer/shared/Types.ts +8 -2
  28. package/src/browser/scrollable/abstractScrollbar.ts +300 -0
  29. package/src/browser/scrollable/fastDomNode.ts +126 -0
  30. package/src/browser/scrollable/globalPointerMoveMonitor.ts +90 -0
  31. package/src/browser/scrollable/horizontalScrollbar.ts +85 -0
  32. package/src/browser/scrollable/mouseEvent.ts +292 -0
  33. package/src/browser/scrollable/scrollable.ts +486 -0
  34. package/src/browser/scrollable/scrollableElement.ts +581 -0
  35. package/src/browser/scrollable/scrollableElementOptions.ts +161 -0
  36. package/src/browser/scrollable/scrollbarArrow.ts +110 -0
  37. package/src/browser/scrollable/scrollbarState.ts +246 -0
  38. package/src/browser/scrollable/scrollbarVisibilityController.ts +113 -0
  39. package/src/browser/scrollable/touch.ts +485 -0
  40. package/src/browser/scrollable/verticalScrollbar.ts +143 -0
  41. package/src/browser/scrollable/widget.ts +23 -0
  42. package/src/browser/services/CharSizeService.ts +2 -2
  43. package/src/browser/services/CoreBrowserService.ts +7 -5
  44. package/src/browser/services/KeyboardService.ts +67 -0
  45. package/src/browser/services/LinkProviderService.ts +1 -1
  46. package/src/browser/services/MouseCoordsService.ts +47 -0
  47. package/src/browser/services/MouseService.ts +518 -25
  48. package/src/browser/services/RenderService.ts +28 -16
  49. package/src/browser/services/SelectionService.ts +45 -39
  50. package/src/browser/services/Services.ts +40 -17
  51. package/src/browser/services/ThemeService.ts +2 -2
  52. package/src/common/Async.ts +141 -0
  53. package/src/common/CircularList.ts +2 -2
  54. package/src/common/Color.ts +8 -0
  55. package/src/common/CoreTerminal.ts +31 -21
  56. package/src/common/Event.ts +118 -0
  57. package/src/common/InputHandler.ts +283 -85
  58. package/src/common/Lifecycle.ts +113 -0
  59. package/src/common/Platform.ts +13 -3
  60. package/src/common/SortedList.ts +7 -3
  61. package/src/common/StringBuilder.ts +67 -0
  62. package/src/common/TaskQueue.ts +14 -5
  63. package/src/common/Types.ts +51 -31
  64. package/src/common/Version.ts +9 -0
  65. package/src/common/buffer/Buffer.ts +34 -19
  66. package/src/common/buffer/BufferLine.ts +133 -65
  67. package/src/common/buffer/BufferLineStringCache.ts +69 -0
  68. package/src/common/buffer/BufferSet.ts +11 -6
  69. package/src/common/buffer/CellData.ts +57 -0
  70. package/src/common/buffer/Marker.ts +2 -2
  71. package/src/common/buffer/Types.ts +6 -2
  72. package/src/common/data/EscapeSequences.ts +71 -70
  73. package/src/common/input/Keyboard.ts +14 -7
  74. package/src/common/input/KittyKeyboard.ts +526 -0
  75. package/src/common/input/Win32InputMode.ts +297 -0
  76. package/src/common/input/WriteBuffer.ts +69 -32
  77. package/src/common/input/XParseColor.ts +2 -2
  78. package/src/common/parser/ApcParser.ts +196 -0
  79. package/src/common/parser/Constants.ts +14 -4
  80. package/src/common/parser/DcsParser.ts +11 -12
  81. package/src/common/parser/EscapeSequenceParser.ts +205 -63
  82. package/src/common/parser/OscParser.ts +11 -12
  83. package/src/common/parser/Params.ts +27 -8
  84. package/src/common/parser/Types.ts +36 -2
  85. package/src/common/public/BufferLineApiView.ts +2 -2
  86. package/src/common/public/BufferNamespaceApi.ts +3 -3
  87. package/src/common/public/ParserApi.ts +3 -0
  88. package/src/common/services/BufferService.ts +14 -9
  89. package/src/common/services/CharsetService.ts +4 -0
  90. package/src/common/services/CoreService.ts +22 -9
  91. package/src/common/services/DecorationService.ts +258 -8
  92. package/src/common/services/LogService.ts +1 -31
  93. package/src/common/services/{CoreMouseService.ts → MouseStateService.ts} +21 -132
  94. package/src/common/services/OptionsService.ts +13 -4
  95. package/src/common/services/ServiceRegistry.ts +9 -7
  96. package/src/common/services/Services.ts +49 -40
  97. package/src/common/services/UnicodeService.ts +1 -1
  98. package/typings/xterm.d.ts +318 -34
  99. package/src/common/Clone.ts +0 -23
  100. package/src/common/TypedArrayUtils.ts +0 -17
  101. package/src/vs/base/browser/browser.ts +0 -141
  102. package/src/vs/base/browser/canIUse.ts +0 -49
  103. package/src/vs/base/browser/dom.ts +0 -2369
  104. package/src/vs/base/browser/fastDomNode.ts +0 -316
  105. package/src/vs/base/browser/globalPointerMoveMonitor.ts +0 -112
  106. package/src/vs/base/browser/iframe.ts +0 -135
  107. package/src/vs/base/browser/keyboardEvent.ts +0 -213
  108. package/src/vs/base/browser/mouseEvent.ts +0 -229
  109. package/src/vs/base/browser/touch.ts +0 -372
  110. package/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts +0 -303
  111. package/src/vs/base/browser/ui/scrollbar/horizontalScrollbar.ts +0 -114
  112. package/src/vs/base/browser/ui/scrollbar/scrollableElement.ts +0 -720
  113. package/src/vs/base/browser/ui/scrollbar/scrollableElementOptions.ts +0 -165
  114. package/src/vs/base/browser/ui/scrollbar/scrollbarArrow.ts +0 -114
  115. package/src/vs/base/browser/ui/scrollbar/scrollbarState.ts +0 -243
  116. package/src/vs/base/browser/ui/scrollbar/scrollbarVisibilityController.ts +0 -118
  117. package/src/vs/base/browser/ui/scrollbar/verticalScrollbar.ts +0 -116
  118. package/src/vs/base/browser/ui/widget.ts +0 -57
  119. package/src/vs/base/browser/window.ts +0 -14
  120. package/src/vs/base/common/arrays.ts +0 -887
  121. package/src/vs/base/common/arraysFind.ts +0 -202
  122. package/src/vs/base/common/assert.ts +0 -71
  123. package/src/vs/base/common/async.ts +0 -1992
  124. package/src/vs/base/common/cancellation.ts +0 -148
  125. package/src/vs/base/common/charCode.ts +0 -450
  126. package/src/vs/base/common/collections.ts +0 -140
  127. package/src/vs/base/common/decorators.ts +0 -130
  128. package/src/vs/base/common/equals.ts +0 -146
  129. package/src/vs/base/common/errors.ts +0 -303
  130. package/src/vs/base/common/event.ts +0 -1778
  131. package/src/vs/base/common/functional.ts +0 -32
  132. package/src/vs/base/common/hash.ts +0 -316
  133. package/src/vs/base/common/iterator.ts +0 -159
  134. package/src/vs/base/common/keyCodes.ts +0 -526
  135. package/src/vs/base/common/keybindings.ts +0 -284
  136. package/src/vs/base/common/lazy.ts +0 -47
  137. package/src/vs/base/common/lifecycle.ts +0 -801
  138. package/src/vs/base/common/linkedList.ts +0 -142
  139. package/src/vs/base/common/map.ts +0 -202
  140. package/src/vs/base/common/numbers.ts +0 -98
  141. package/src/vs/base/common/observable.ts +0 -76
  142. package/src/vs/base/common/observableInternal/api.ts +0 -31
  143. package/src/vs/base/common/observableInternal/autorun.ts +0 -281
  144. package/src/vs/base/common/observableInternal/base.ts +0 -489
  145. package/src/vs/base/common/observableInternal/debugName.ts +0 -145
  146. package/src/vs/base/common/observableInternal/derived.ts +0 -428
  147. package/src/vs/base/common/observableInternal/lazyObservableValue.ts +0 -146
  148. package/src/vs/base/common/observableInternal/logging.ts +0 -328
  149. package/src/vs/base/common/observableInternal/promise.ts +0 -209
  150. package/src/vs/base/common/observableInternal/utils.ts +0 -610
  151. package/src/vs/base/common/platform.ts +0 -281
  152. package/src/vs/base/common/scrollable.ts +0 -522
  153. package/src/vs/base/common/sequence.ts +0 -34
  154. package/src/vs/base/common/stopwatch.ts +0 -43
  155. package/src/vs/base/common/strings.ts +0 -557
  156. package/src/vs/base/common/symbols.ts +0 -9
  157. package/src/vs/base/common/uint.ts +0 -59
  158. package/src/vs/patches/nls.ts +0 -90
  159. package/src/vs/typings/base-common.d.ts +0 -20
  160. package/src/vs/typings/require.d.ts +0 -42
  161. package/src/vs/typings/vscode-globals-nls.d.ts +0 -36
  162. package/src/vs/typings/vscode-globals-product.d.ts +0 -33
@@ -14,13 +14,18 @@ export const enum ParserState {
14
14
  CSI_PARAM = 4,
15
15
  CSI_INTERMEDIATE = 5,
16
16
  CSI_IGNORE = 6,
17
- SOS_PM_APC_STRING = 7,
17
+ SOS_PM_STRING = 7,
18
18
  OSC_STRING = 8,
19
19
  DCS_ENTRY = 9,
20
20
  DCS_PARAM = 10,
21
21
  DCS_IGNORE = 11,
22
22
  DCS_INTERMEDIATE = 12,
23
- DCS_PASSTHROUGH = 13
23
+ DCS_PASSTHROUGH = 13,
24
+ APC_ENTRY = 14,
25
+ APC_INTERMEDIATE = 15,
26
+ APC_PASSTHROUGH = 16,
27
+ // Number of states, meaning LAST_STATE + 1.
28
+ STATE_LENGTH = 17
24
29
  }
25
30
 
26
31
  /**
@@ -41,7 +46,10 @@ export const enum ParserAction {
41
46
  CLEAR = 11,
42
47
  DCS_HOOK = 12,
43
48
  DCS_PUT = 13,
44
- DCS_UNHOOK = 14
49
+ DCS_UNHOOK = 14,
50
+ APC_START = 15,
51
+ APC_PUT = 16,
52
+ APC_END = 17
45
53
  }
46
54
 
47
55
  /**
@@ -55,4 +63,6 @@ export const enum OscState {
55
63
  }
56
64
 
57
65
  // payload limit for OSC and DCS
58
- export const PAYLOAD_LIMIT = 10000000;
66
+ export const enum ParserConstants {
67
+ PAYLOAD_LIMIT = 10000000
68
+ }
@@ -7,7 +7,8 @@ import { IDisposable } from 'common/Types';
7
7
  import { IDcsHandler, IParams, IHandlerCollection, IDcsParser, DcsFallbackHandlerType, ISubParserStackState } from 'common/parser/Types';
8
8
  import { utf32ToString } from 'common/input/TextDecoder';
9
9
  import { Params } from 'common/parser/Params';
10
- import { PAYLOAD_LIMIT } from 'common/parser/Constants';
10
+ import { ParserConstants } from 'common/parser/Constants';
11
+ import { LimitedStringBuilder } from 'common/StringBuilder';
11
12
 
12
13
  const EMPTY_HANDLERS: IDcsHandler[] = [];
13
14
 
@@ -29,9 +30,7 @@ export class DcsParser implements IDcsParser {
29
30
  }
30
31
 
31
32
  public registerHandler(ident: number, handler: IDcsHandler): IDisposable {
32
- if (this._handlers[ident] === undefined) {
33
- this._handlers[ident] = [];
34
- }
33
+ this._handlers[ident] ??= [];
35
34
  const handlerList = this._handlers[ident];
36
35
  handlerList.push(handler);
37
36
  return {
@@ -140,7 +139,9 @@ EMPTY_PARAMS.addParam(0);
140
139
  * Note: The payload is currently limited to 50 MB (hardcoded).
141
140
  */
142
141
  export class DcsHandler implements IDcsHandler {
143
- private _data = '';
142
+ private static _payloadLimit = ParserConstants.PAYLOAD_LIMIT;
143
+
144
+ private _data = new LimitedStringBuilder(DcsHandler._payloadLimit);
144
145
  private _params: IParams = EMPTY_PARAMS;
145
146
  private _hitLimit: boolean = false;
146
147
 
@@ -152,7 +153,7 @@ export class DcsHandler implements IDcsHandler {
152
153
  // perf optimization:
153
154
  // clone only, if we have non empty params, otherwise stick with default
154
155
  this._params = (params.length > 1 || params.params[0]) ? params.clone() : EMPTY_PARAMS;
155
- this._data = '';
156
+ this._data.reset();
156
157
  this._hitLimit = false;
157
158
  }
158
159
 
@@ -160,9 +161,7 @@ export class DcsHandler implements IDcsHandler {
160
161
  if (this._hitLimit) {
161
162
  return;
162
163
  }
163
- this._data += utf32ToString(data, start, end);
164
- if (this._data.length > PAYLOAD_LIMIT) {
165
- this._data = '';
164
+ if (this._data.append(utf32ToString(data, start, end))) {
166
165
  this._hitLimit = true;
167
166
  }
168
167
  }
@@ -172,20 +171,20 @@ export class DcsHandler implements IDcsHandler {
172
171
  if (this._hitLimit) {
173
172
  ret = false;
174
173
  } else if (success) {
175
- ret = this._handler(this._data, this._params);
174
+ ret = this._handler(this._data.toString(), this._params);
176
175
  if (ret instanceof Promise) {
177
176
  // need to hold data and params until `ret` got resolved
178
177
  // dont care for errors, data will be freed anyway on next start
179
178
  return ret.then(res => {
180
179
  this._params = EMPTY_PARAMS;
181
- this._data = '';
180
+ this._data.reset();
182
181
  this._hitLimit = false;
183
182
  return res;
184
183
  });
185
184
  }
186
185
  }
187
186
  this._params = EMPTY_PARAMS;
188
- this._data = '';
187
+ this._data.reset();
189
188
  this._hitLimit = false;
190
189
  return ret;
191
190
  }
@@ -3,13 +3,32 @@
3
3
  * @license MIT
4
4
  */
5
5
 
6
- import { IParsingState, IDcsHandler, IEscapeSequenceParser, IParams, IOscHandler, IHandlerCollection, CsiHandlerType, OscFallbackHandlerType, IOscParser, EscHandlerType, IDcsParser, DcsFallbackHandlerType, IFunctionIdentifier, ExecuteFallbackHandlerType, CsiFallbackHandlerType, EscFallbackHandlerType, PrintHandlerType, PrintFallbackHandlerType, ExecuteHandlerType, IParserStackState, ParserStackType, ResumableHandlersType } from 'common/parser/Types';
6
+ import { IParsingState, IDcsHandler, IEscapeSequenceParser, IParams, IOscHandler, IHandlerCollection, CsiHandlerType, OscFallbackHandlerType, IOscParser, EscHandlerType, IDcsParser, DcsFallbackHandlerType, IFunctionIdentifier, ExecuteFallbackHandlerType, CsiFallbackHandlerType, EscFallbackHandlerType, PrintHandlerType, PrintFallbackHandlerType, ExecuteHandlerType, IParserStackState, ParserStackType, ResumableHandlersType, IApcHandler, IApcParser, ApcFallbackHandlerType } from 'common/parser/Types';
7
7
  import { ParserState, ParserAction } from 'common/parser/Constants';
8
- import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
8
+ import { Disposable, toDisposable } from 'common/Lifecycle';
9
9
  import { IDisposable } from 'common/Types';
10
10
  import { Params } from 'common/parser/Params';
11
11
  import { OscParser } from 'common/parser/OscParser';
12
12
  import { DcsParser } from 'common/parser/DcsParser';
13
+ import { ApcParser } from 'common/parser/ApcParser';
14
+
15
+ /**
16
+ * VT commands done by the parser
17
+ */
18
+ // @vt: #Y ESC CSI "Control Sequence Introducer" "ESC [" "Start of a CSI sequence."
19
+ // @vt: #Y ESC OSC "Operating System Command" "ESC ]" "Start of an OSC sequence."
20
+ // @vt: #Y ESC DCS "Device Control String" "ESC P" "Start of a DCS sequence."
21
+ // @vt: #Y ESC ST "String Terminator" "ESC \" "Terminator used for string type sequences."
22
+ // @vt: #Y ESC PM "Privacy Message" "ESC ^" "Start of a privacy message."
23
+ // @vt: #Y ESC APC "Application Program Command" "ESC _" "Start of an APC sequence."
24
+ // @vt: #Y C1 CSI "Control Sequence Introducer" "\x9B" "Start of a CSI sequence."
25
+ // @vt: #Y C1 OSC "Operating System Command" "\x9D" "Start of an OSC sequence."
26
+ // @vt: #Y C1 DCS "Device Control String" "\x90" "Start of a DCS sequence."
27
+ // @vt: #Y C1 ST "String Terminator" "\x9C" "Terminator used for string type sequences."
28
+ // @vt: #Y C1 PM "Privacy Message" "\x9E" "Start of a privacy message."
29
+ // @vt: #Y C1 APC "Application Program Command" "\x9F" "Start of an APC sequence."
30
+ // @vt: #Y C0 NUL "Null" "\0, \x00" "NUL is ignored."
31
+ // @vt: #Y C0 ESC "Escape" "\e, \x1B" "Start of a sequence. Cancels any other sequence."
13
32
 
14
33
  /**
15
34
  * Table values are generated like this:
@@ -17,8 +36,8 @@ import { DcsParser } from 'common/parser/DcsParser';
17
36
  * value: action << TableValue.TRANSITION_ACTION_SHIFT | nextState
18
37
  */
19
38
  const enum TableAccess {
20
- TRANSITION_ACTION_SHIFT = 4,
21
- TRANSITION_STATE_MASK = 15,
39
+ TRANSITION_ACTION_SHIFT = 8,
40
+ TRANSITION_STATE_MASK = 255,
22
41
  INDEX_STATE_SHIFT = 8
23
42
  }
24
43
 
@@ -26,10 +45,10 @@ const enum TableAccess {
26
45
  * Transition table for EscapeSequenceParser.
27
46
  */
28
47
  export class TransitionTable {
29
- public table: Uint8Array;
48
+ public table: Uint16Array;
30
49
 
31
50
  constructor(length: number) {
32
- this.table = new Uint8Array(length);
51
+ this.table = new Uint16Array(length);
33
52
  }
34
53
 
35
54
  /**
@@ -76,7 +95,9 @@ const NON_ASCII_PRINTABLE = 0xA0;
76
95
  * Taken from https://vt100.net/emu/dec_ansi_parser.
77
96
  */
78
97
  export const VT500_TRANSITION_TABLE = (function (): TransitionTable {
79
- const table: TransitionTable = new TransitionTable(4095);
98
+ // table size:
99
+ // (ParserState.STATE_LENGTH - 1) << TableAccess.INDEX_STATE_SHIFT | NON_ASCII_PRINTABLE + 1
100
+ const table: TransitionTable = new TransitionTable(4257);
80
101
 
81
102
  // range macro for byte
82
103
  const BYTE_VALUES = 256;
@@ -89,22 +110,22 @@ export const VT500_TRANSITION_TABLE = (function (): TransitionTable {
89
110
  EXECUTABLES.push(0x19);
90
111
  EXECUTABLES.push.apply(EXECUTABLES, r(0x1c, 0x20));
91
112
 
92
- const states: number[] = r(ParserState.GROUND, ParserState.DCS_PASSTHROUGH + 1);
93
- let state: any;
113
+ const states: number[] = r(ParserState.GROUND, ParserState.STATE_LENGTH);
94
114
 
95
115
  // set default transition
96
116
  table.setDefault(ParserAction.ERROR, ParserState.GROUND);
97
117
  // printables
98
118
  table.addMany(PRINTABLES, ParserState.GROUND, ParserAction.PRINT, ParserState.GROUND);
99
119
  // global anywhere rules
100
- for (state in states) {
120
+ for (const state of states) {
101
121
  table.addMany([0x18, 0x1a, 0x99, 0x9a], state, ParserAction.EXECUTE, ParserState.GROUND);
102
122
  table.addMany(r(0x80, 0x90), state, ParserAction.EXECUTE, ParserState.GROUND);
103
123
  table.addMany(r(0x90, 0x98), state, ParserAction.EXECUTE, ParserState.GROUND);
104
124
  table.add(0x9c, state, ParserAction.IGNORE, ParserState.GROUND); // ST as terminator
105
125
  table.add(0x1b, state, ParserAction.CLEAR, ParserState.ESCAPE); // ESC
106
126
  table.add(0x9d, state, ParserAction.OSC_START, ParserState.OSC_STRING); // OSC
107
- table.addMany([0x98, 0x9e, 0x9f], state, ParserAction.IGNORE, ParserState.SOS_PM_APC_STRING);
127
+ table.addMany([0x98, 0x9e], state, ParserAction.IGNORE, ParserState.SOS_PM_STRING); // SOS, PM
128
+ table.add(0x9f, state, ParserAction.CLEAR, ParserState.APC_ENTRY); // APC
108
129
  table.add(0x9b, state, ParserAction.CLEAR, ParserState.CSI_ENTRY); // CSI
109
130
  table.add(0x90, state, ParserAction.CLEAR, ParserState.DCS_ENTRY); // DCS
110
131
  }
@@ -128,12 +149,27 @@ export const VT500_TRANSITION_TABLE = (function (): TransitionTable {
128
149
  table.add(0x7f, ParserState.OSC_STRING, ParserAction.OSC_PUT, ParserState.OSC_STRING);
129
150
  table.addMany([0x9c, 0x1b, 0x18, 0x1a, 0x07], ParserState.OSC_STRING, ParserAction.OSC_END, ParserState.GROUND);
130
151
  table.addMany(r(0x1c, 0x20), ParserState.OSC_STRING, ParserAction.IGNORE, ParserState.OSC_STRING);
131
- // sos/pm/apc does nothing
132
- table.addMany([0x58, 0x5e, 0x5f], ParserState.ESCAPE, ParserAction.IGNORE, ParserState.SOS_PM_APC_STRING);
133
- table.addMany(PRINTABLES, ParserState.SOS_PM_APC_STRING, ParserAction.IGNORE, ParserState.SOS_PM_APC_STRING);
134
- table.addMany(EXECUTABLES, ParserState.SOS_PM_APC_STRING, ParserAction.IGNORE, ParserState.SOS_PM_APC_STRING);
135
- table.add(0x9c, ParserState.SOS_PM_APC_STRING, ParserAction.IGNORE, ParserState.GROUND);
136
- table.add(0x7f, ParserState.SOS_PM_APC_STRING, ParserAction.IGNORE, ParserState.SOS_PM_APC_STRING);
152
+ // sos/pm
153
+ table.addMany([0x58, 0x5e], ParserState.ESCAPE, ParserAction.IGNORE, ParserState.SOS_PM_STRING);
154
+ table.addMany(PRINTABLES, ParserState.SOS_PM_STRING, ParserAction.IGNORE, ParserState.SOS_PM_STRING);
155
+ table.addMany(EXECUTABLES, ParserState.SOS_PM_STRING, ParserAction.IGNORE, ParserState.SOS_PM_STRING);
156
+ table.add(0x9c, ParserState.SOS_PM_STRING, ParserAction.IGNORE, ParserState.GROUND);
157
+ table.add(0x7f, ParserState.SOS_PM_STRING, ParserAction.IGNORE, ParserState.SOS_PM_STRING);
158
+ // apc
159
+ table.add(0x5f, ParserState.ESCAPE, ParserAction.CLEAR, ParserState.APC_ENTRY);
160
+ table.addMany(EXECUTABLES, ParserState.APC_ENTRY, ParserAction.IGNORE, ParserState.APC_ENTRY);
161
+ table.add(0x7f, ParserState.APC_ENTRY, ParserAction.IGNORE, ParserState.APC_ENTRY);
162
+ table.addMany(r(0x20, 0x30), ParserState.APC_ENTRY, ParserAction.COLLECT, ParserState.APC_INTERMEDIATE);
163
+ table.addMany(r(0x30, 0x7f), ParserState.APC_ENTRY, ParserAction.APC_START, ParserState.APC_PASSTHROUGH);
164
+ table.addMany(r(0x30, 0x7f), ParserState.APC_INTERMEDIATE, ParserAction.APC_START, ParserState.APC_PASSTHROUGH);
165
+ table.addMany(EXECUTABLES, ParserState.APC_INTERMEDIATE, ParserAction.IGNORE, ParserState.APC_INTERMEDIATE);
166
+ table.addMany(r(0x20, 0x30), ParserState.APC_INTERMEDIATE, ParserAction.COLLECT, ParserState.APC_INTERMEDIATE);
167
+ table.add(0x7f, ParserState.APC_INTERMEDIATE, ParserAction.IGNORE, ParserState.APC_INTERMEDIATE);
168
+ table.addMany(PRINTABLES, ParserState.APC_PASSTHROUGH, ParserAction.APC_PUT, ParserState.APC_PASSTHROUGH);
169
+ table.addMany(EXECUTABLES, ParserState.APC_PASSTHROUGH, ParserAction.IGNORE, ParserState.APC_PASSTHROUGH);
170
+ table.addMany(r(0x08, 0x0e), ParserState.APC_PASSTHROUGH, ParserAction.APC_PUT, ParserState.APC_PASSTHROUGH);
171
+ table.add(0x7f, ParserState.APC_PASSTHROUGH, ParserAction.IGNORE, ParserState.APC_PASSTHROUGH);
172
+ table.addMany([0x1b, 0x9c, 0x18, 0x1a], ParserState.APC_PASSTHROUGH, ParserAction.APC_END, ParserState.GROUND);
137
173
  // csi entries
138
174
  table.add(0x5b, ParserState.ESCAPE, ParserAction.CLEAR, ParserState.CSI_ENTRY);
139
175
  table.addMany(r(0x40, 0x7f), ParserState.CSI_ENTRY, ParserAction.CSI_DISPATCH, ParserState.GROUND);
@@ -162,22 +198,18 @@ export const VT500_TRANSITION_TABLE = (function (): TransitionTable {
162
198
  table.add(0x50, ParserState.ESCAPE, ParserAction.CLEAR, ParserState.DCS_ENTRY);
163
199
  table.addMany(EXECUTABLES, ParserState.DCS_ENTRY, ParserAction.IGNORE, ParserState.DCS_ENTRY);
164
200
  table.add(0x7f, ParserState.DCS_ENTRY, ParserAction.IGNORE, ParserState.DCS_ENTRY);
165
- table.addMany(r(0x1c, 0x20), ParserState.DCS_ENTRY, ParserAction.IGNORE, ParserState.DCS_ENTRY);
166
201
  table.addMany(r(0x20, 0x30), ParserState.DCS_ENTRY, ParserAction.COLLECT, ParserState.DCS_INTERMEDIATE);
167
202
  table.addMany(r(0x30, 0x3c), ParserState.DCS_ENTRY, ParserAction.PARAM, ParserState.DCS_PARAM);
168
203
  table.addMany([0x3c, 0x3d, 0x3e, 0x3f], ParserState.DCS_ENTRY, ParserAction.COLLECT, ParserState.DCS_PARAM);
169
204
  table.addMany(EXECUTABLES, ParserState.DCS_IGNORE, ParserAction.IGNORE, ParserState.DCS_IGNORE);
170
205
  table.addMany(r(0x20, 0x80), ParserState.DCS_IGNORE, ParserAction.IGNORE, ParserState.DCS_IGNORE);
171
- table.addMany(r(0x1c, 0x20), ParserState.DCS_IGNORE, ParserAction.IGNORE, ParserState.DCS_IGNORE);
172
206
  table.addMany(EXECUTABLES, ParserState.DCS_PARAM, ParserAction.IGNORE, ParserState.DCS_PARAM);
173
207
  table.add(0x7f, ParserState.DCS_PARAM, ParserAction.IGNORE, ParserState.DCS_PARAM);
174
- table.addMany(r(0x1c, 0x20), ParserState.DCS_PARAM, ParserAction.IGNORE, ParserState.DCS_PARAM);
175
208
  table.addMany(r(0x30, 0x3c), ParserState.DCS_PARAM, ParserAction.PARAM, ParserState.DCS_PARAM);
176
209
  table.addMany([0x3c, 0x3d, 0x3e, 0x3f], ParserState.DCS_PARAM, ParserAction.IGNORE, ParserState.DCS_IGNORE);
177
210
  table.addMany(r(0x20, 0x30), ParserState.DCS_PARAM, ParserAction.COLLECT, ParserState.DCS_INTERMEDIATE);
178
211
  table.addMany(EXECUTABLES, ParserState.DCS_INTERMEDIATE, ParserAction.IGNORE, ParserState.DCS_INTERMEDIATE);
179
212
  table.add(0x7f, ParserState.DCS_INTERMEDIATE, ParserAction.IGNORE, ParserState.DCS_INTERMEDIATE);
180
- table.addMany(r(0x1c, 0x20), ParserState.DCS_INTERMEDIATE, ParserAction.IGNORE, ParserState.DCS_INTERMEDIATE);
181
213
  table.addMany(r(0x20, 0x30), ParserState.DCS_INTERMEDIATE, ParserAction.COLLECT, ParserState.DCS_INTERMEDIATE);
182
214
  table.addMany(r(0x30, 0x40), ParserState.DCS_INTERMEDIATE, ParserAction.IGNORE, ParserState.DCS_IGNORE);
183
215
  table.addMany(r(0x40, 0x7f), ParserState.DCS_INTERMEDIATE, ParserAction.DCS_HOOK, ParserState.DCS_PASSTHROUGH);
@@ -193,6 +225,7 @@ export const VT500_TRANSITION_TABLE = (function (): TransitionTable {
193
225
  table.add(NON_ASCII_PRINTABLE, ParserState.CSI_IGNORE, ParserAction.IGNORE, ParserState.CSI_IGNORE);
194
226
  table.add(NON_ASCII_PRINTABLE, ParserState.DCS_IGNORE, ParserAction.IGNORE, ParserState.DCS_IGNORE);
195
227
  table.add(NON_ASCII_PRINTABLE, ParserState.DCS_PASSTHROUGH, ParserAction.DCS_PUT, ParserState.DCS_PASSTHROUGH);
228
+ table.add(NON_ASCII_PRINTABLE, ParserState.APC_PASSTHROUGH, ParserAction.APC_PUT, ParserState.APC_PASSTHROUGH);
196
229
  return table;
197
230
  })();
198
231
 
@@ -239,10 +272,13 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
239
272
  // handler lookup containers
240
273
  protected _printHandler: PrintHandlerType;
241
274
  protected _executeHandlers: { [flag: number]: ExecuteHandlerType };
275
+ // fast path for EXE bytes < 0x18
276
+ protected _executeHandlersArr: (ExecuteHandlerType | undefined)[];
242
277
  protected _csiHandlers: IHandlerCollection<CsiHandlerType>;
243
278
  protected _escHandlers: IHandlerCollection<EscHandlerType>;
244
279
  protected readonly _oscParser: IOscParser;
245
280
  protected readonly _dcsParser: IDcsParser;
281
+ protected readonly _apcParser: IApcParser;
246
282
  protected _errorHandler: (state: IParsingState) => IParsingState;
247
283
 
248
284
  // fallback handlers
@@ -281,15 +317,18 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
281
317
  this._errorHandlerFb = (state: IParsingState): IParsingState => state;
282
318
  this._printHandler = this._printHandlerFb;
283
319
  this._executeHandlers = Object.create(null);
320
+ this._executeHandlersArr = new Array(0x18).fill(undefined);
284
321
  this._csiHandlers = Object.create(null);
285
322
  this._escHandlers = Object.create(null);
286
323
  this._register(toDisposable(() => {
287
324
  this._csiHandlers = Object.create(null);
288
325
  this._executeHandlers = Object.create(null);
326
+ this._executeHandlersArr = new Array(0x18).fill(undefined);
289
327
  this._escHandlers = Object.create(null);
290
328
  }));
291
329
  this._oscParser = this._register(new OscParser());
292
330
  this._dcsParser = this._register(new DcsParser());
331
+ this._apcParser = this._register(new ApcParser());
293
332
  this._errorHandler = this._errorHandlerFb;
294
333
 
295
334
  // swallow 7bit ST (ESC+\)
@@ -351,9 +390,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
351
390
 
352
391
  public registerEscHandler(id: IFunctionIdentifier, handler: EscHandlerType): IDisposable {
353
392
  const ident = this._identifier(id, [0x30, 0x7e]);
354
- if (this._escHandlers[ident] === undefined) {
355
- this._escHandlers[ident] = [];
356
- }
393
+ this._escHandlers[ident] ??= [];
357
394
  const handlerList = this._escHandlers[ident];
358
395
  handlerList.push(handler);
359
396
  return {
@@ -373,10 +410,14 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
373
410
  }
374
411
 
375
412
  public setExecuteHandler(flag: string, handler: ExecuteHandlerType): void {
376
- this._executeHandlers[flag.charCodeAt(0)] = handler;
413
+ const code = flag.charCodeAt(0);
414
+ this._executeHandlers[code] = handler;
415
+ if (code < 0x18) this._executeHandlersArr[code] = handler;
377
416
  }
378
417
  public clearExecuteHandler(flag: string): void {
379
- if (this._executeHandlers[flag.charCodeAt(0)]) delete this._executeHandlers[flag.charCodeAt(0)];
418
+ const code = flag.charCodeAt(0);
419
+ if (this._executeHandlers[code]) delete this._executeHandlers[code];
420
+ if (code < 0x18) this._executeHandlersArr[code] = undefined;
380
421
  }
381
422
  public setExecuteHandlerFallback(handler: ExecuteFallbackHandlerType): void {
382
423
  this._executeHandlerFb = handler;
@@ -384,9 +425,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
384
425
 
385
426
  public registerCsiHandler(id: IFunctionIdentifier, handler: CsiHandlerType): IDisposable {
386
427
  const ident = this._identifier(id);
387
- if (this._csiHandlers[ident] === undefined) {
388
- this._csiHandlers[ident] = [];
389
- }
428
+ this._csiHandlers[ident] ??= [];
390
429
  const handlerList = this._csiHandlers[ident];
391
430
  handlerList.push(handler);
392
431
  return {
@@ -425,6 +464,18 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
425
464
  this._oscParser.setHandlerFallback(handler);
426
465
  }
427
466
 
467
+ public registerApcHandler(id: IFunctionIdentifier, handler: IApcHandler): IDisposable {
468
+ id.prefix = undefined; // APC does not support prefix byte
469
+ return this._apcParser.registerHandler(this._identifier(id, [0x30, 0x7e]), handler);
470
+ }
471
+ public clearApcHandler(id: IFunctionIdentifier): void {
472
+ id.prefix = undefined; // APC does not support prefix byte
473
+ this._apcParser.clearHandler(this._identifier(id, [0x30, 0x7e]));
474
+ }
475
+ public setApcHandlerFallback(handler: ApcFallbackHandlerType): void {
476
+ this._apcParser.setHandlerFallback(handler);
477
+ }
478
+
428
479
  public setErrorHandler(callback: (state: IParsingState) => IParsingState): void {
429
480
  this._errorHandler = callback;
430
481
  }
@@ -445,8 +496,8 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
445
496
  this.currentState = this.initialState;
446
497
  this._oscParser.reset();
447
498
  this._dcsParser.reset();
448
- this._params.reset();
449
- this._params.addParam(0); // ZDM
499
+ this._apcParser.reset();
500
+ this._params.resetZdm();
450
501
  this._collect = 0;
451
502
  this.precedingJoinState = 0;
452
503
  // abort pending continuation from async handler
@@ -489,6 +540,10 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
489
540
  * - OSC_STRING:OSC_PUT
490
541
  * - DCS_PASSTHROUGH:DCS_PUT
491
542
  *
543
+ * Additionally the following fast paths exist before the table lookup:
544
+ * - EXE bytes < 0x18 in non-payload states (avoids table lookup entirely)
545
+ * - 7-bit CSI sequences without intermediates (ESC [ params final)
546
+ *
492
547
  * Note on asynchronous handler support:
493
548
  * Any handler returning a promise will be treated as asynchronous.
494
549
  * To keep the in-band blocking working for async handlers, `parse` pauses execution,
@@ -591,8 +646,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
591
646
  return handlerResult;
592
647
  }
593
648
  if (code === 0x1b) this._parseStack.transition |= ParserState.ESCAPE;
594
- this._params.reset();
595
- this._params.addParam(0); // ZDM
649
+ this._params.resetZdm();
596
650
  this._collect = 0;
597
651
  break;
598
652
  case ParserStackType.OSC:
@@ -602,8 +656,17 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
602
656
  return handlerResult;
603
657
  }
604
658
  if (code === 0x1b) this._parseStack.transition |= ParserState.ESCAPE;
605
- this._params.reset();
606
- this._params.addParam(0); // ZDM
659
+ this._params.resetZdm();
660
+ this._collect = 0;
661
+ break;
662
+ case ParserStackType.APC:
663
+ code = data[this._parseStack.chunkPos];
664
+ handlerResult = this._apcParser.end(code !== 0x18 && code !== 0x1a, promiseResult);
665
+ if (handlerResult) {
666
+ return handlerResult;
667
+ }
668
+ if (code === 0x1b) this._parseStack.transition |= ParserState.ESCAPE;
669
+ this._params.resetZdm();
607
670
  this._collect = 0;
608
671
  break;
609
672
  }
@@ -621,34 +684,90 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
621
684
  for (let i = start; i < length; ++i) {
622
685
  code = data[i];
623
686
 
687
+ // EXE fast-path: common control bytes (0x00-0x17) in non-payload states
688
+ if (code < 0x18 && this.currentState <= ParserState.CSI_IGNORE) {
689
+ (this._executeHandlersArr[code] ?? this._executeHandlerFb)(code);
690
+ this.precedingJoinState = 0;
691
+ continue;
692
+ }
693
+
694
+ // CSI fast-path: collapse ESC [ into a single entry, parse params+final in a tight loop
695
+ if (code === 0x1b
696
+ && this.currentState < ParserState.OSC_STRING
697
+ && i + 2 < length && data[i + 1] === 0x5b
698
+ ) {
699
+ this._params.resetZdm();
700
+ this._collect = 0;
701
+ let k = i + 2;
702
+ let ch = data[k];
703
+ if (ch >= 0x3c && ch <= 0x3f) {
704
+ this._collect = ch;
705
+ k++;
706
+ }
707
+ let csiDone = false;
708
+ for (; k < length; k++) {
709
+ ch = data[k];
710
+ if (ch >= 0x30 && ch <= 0x39) {
711
+ this._params.addDigit(ch - 48);
712
+ } else if (ch === 0x3b) {
713
+ this._params.addParam(0);
714
+ } else if (ch === 0x3a) {
715
+ this._params.addSubParam(-1);
716
+ } else if (ch >= 0x40 && ch <= 0x7e) {
717
+ const handlers = this._csiHandlers[this._collect << 8 | ch];
718
+ let j = handlers ? handlers.length - 1 : -1;
719
+ for (; j >= 0; j--) {
720
+ handlerResult = handlers[j](this._params);
721
+ if (handlerResult === true) {
722
+ break;
723
+ } else if (handlerResult instanceof Promise) {
724
+ transition = ParserAction.CSI_DISPATCH << TableAccess.TRANSITION_ACTION_SHIFT | ParserState.GROUND;
725
+ this._preserveStack(ParserStackType.CSI, handlers, j, transition, k);
726
+ return handlerResult;
727
+ }
728
+ }
729
+ if (j < 0) {
730
+ this._csiHandlerFb(this._collect << 8 | ch, this._params);
731
+ }
732
+ this.precedingJoinState = 0;
733
+ i = k;
734
+ this.currentState = ParserState.GROUND;
735
+ csiDone = true;
736
+ break;
737
+ } else {
738
+ break;
739
+ }
740
+ }
741
+ if (!csiDone) {
742
+ i = k - 1;
743
+ this.currentState = ParserState.CSI_PARAM;
744
+ }
745
+ continue;
746
+ }
747
+
624
748
  // normal transition & action lookup
625
- transition = this._transitions.table[this.currentState << TableAccess.INDEX_STATE_SHIFT | (code < 0xa0 ? code : NON_ASCII_PRINTABLE)];
749
+ transition = this._transitions.table[
750
+ this.currentState << TableAccess.INDEX_STATE_SHIFT |
751
+ (code < NON_ASCII_PRINTABLE ? code : NON_ASCII_PRINTABLE)
752
+ ];
626
753
  switch (transition >> TableAccess.TRANSITION_ACTION_SHIFT) {
627
754
  case ParserAction.PRINT:
628
- // read ahead with loop unrolling
629
755
  // Note: 0x20 (SP) is included, 0x7F (DEL) is excluded
630
- for (let j = i + 1; ; ++j) {
631
- if (j >= length || (code = data[j]) < 0x20 || (code > 0x7e && code < NON_ASCII_PRINTABLE)) {
632
- this._printHandler(data, i, j);
633
- i = j - 1;
634
- break;
635
- }
636
- if (++j >= length || (code = data[j]) < 0x20 || (code > 0x7e && code < NON_ASCII_PRINTABLE)) {
637
- this._printHandler(data, i, j);
638
- i = j - 1;
639
- break;
640
- }
641
- if (++j >= length || (code = data[j]) < 0x20 || (code > 0x7e && code < NON_ASCII_PRINTABLE)) {
642
- this._printHandler(data, i, j);
643
- i = j - 1;
644
- break;
645
- }
646
- if (++j >= length || (code = data[j]) < 0x20 || (code > 0x7e && code < NON_ASCII_PRINTABLE)) {
647
- this._printHandler(data, i, j);
648
- i = j - 1;
649
- break;
756
+ let c = i;
757
+ const l4 = length - 4;
758
+ while (c < l4
759
+ && data[++c] >= 0x20 && (data[c] <= 0x7e || data[c] >= NON_ASCII_PRINTABLE)
760
+ && data[++c] >= 0x20 && (data[c] <= 0x7e || data[c] >= NON_ASCII_PRINTABLE)
761
+ && data[++c] >= 0x20 && (data[c] <= 0x7e || data[c] >= NON_ASCII_PRINTABLE)
762
+ && data[++c] >= 0x20 && (data[c] <= 0x7e || data[c] >= NON_ASCII_PRINTABLE)
763
+ ) {}
764
+ if (c >= l4) {
765
+ while (c < length && data[c] >= 0x20 && (data[c] <= 0x7e || data[c] >= NON_ASCII_PRINTABLE)) {
766
+ c++;
650
767
  }
651
768
  }
769
+ this._printHandler(data, i, c);
770
+ i = c - 1;
652
771
  break;
653
772
  case ParserAction.EXECUTE:
654
773
  if (this._executeHandlers[code]) this._executeHandlers[code]();
@@ -730,8 +849,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
730
849
  this.precedingJoinState = 0;
731
850
  break;
732
851
  case ParserAction.CLEAR:
733
- this._params.reset();
734
- this._params.addParam(0); // ZDM
852
+ this._params.resetZdm();
735
853
  this._collect = 0;
736
854
  break;
737
855
  case ParserAction.DCS_HOOK:
@@ -755,8 +873,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
755
873
  return handlerResult;
756
874
  }
757
875
  if (code === 0x1b) transition |= ParserState.ESCAPE;
758
- this._params.reset();
759
- this._params.addParam(0); // ZDM
876
+ this._params.resetZdm();
760
877
  this._collect = 0;
761
878
  this.precedingJoinState = 0;
762
879
  break;
@@ -780,8 +897,33 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
780
897
  return handlerResult;
781
898
  }
782
899
  if (code === 0x1b) transition |= ParserState.ESCAPE;
783
- this._params.reset();
784
- this._params.addParam(0); // ZDM
900
+ this._params.resetZdm();
901
+ this._collect = 0;
902
+ this.precedingJoinState = 0;
903
+ break;
904
+ case ParserAction.APC_START:
905
+ this._apcParser.start(this._collect << 8 | code);
906
+ break;
907
+ case ParserAction.APC_PUT:
908
+ // inner loop - exit APC_PUT: 0x18, 0x1a, 0x1b, 0x9c
909
+ // allowed: 00/08 .. 00/13, 02/00 .. 07/14 + NON_ASCII_PRINTABLE
910
+ for (let j = i + 1; ; ++j) {
911
+ if (j < length && (
912
+ (data[j] >= 0x20 && data[j] < 0x7f) || (data[j] >= 0x08 && data[j] < 0x0e) || data[j] >= NON_ASCII_PRINTABLE
913
+ )) continue;
914
+ this._apcParser.put(data, i, j);
915
+ i = j - 1;
916
+ break;
917
+ }
918
+ break;
919
+ case ParserAction.APC_END:
920
+ handlerResult = this._apcParser.end(code !== 0x18 && code !== 0x1a);
921
+ if (handlerResult) {
922
+ this._preserveStack(ParserStackType.APC, [], 0, transition, i);
923
+ return handlerResult;
924
+ }
925
+ if (code === 0x1b) transition |= ParserState.ESCAPE;
926
+ this._params.resetZdm();
785
927
  this._collect = 0;
786
928
  this.precedingJoinState = 0;
787
929
  break;
@@ -4,9 +4,10 @@
4
4
  */
5
5
 
6
6
  import { IOscHandler, IHandlerCollection, OscFallbackHandlerType, IOscParser, ISubParserStackState } from 'common/parser/Types';
7
- import { OscState, PAYLOAD_LIMIT } from 'common/parser/Constants';
7
+ import { OscState, ParserConstants } from 'common/parser/Constants';
8
8
  import { utf32ToString } from 'common/input/TextDecoder';
9
9
  import { IDisposable } from 'common/Types';
10
+ import { LimitedStringBuilder } from 'common/StringBuilder';
10
11
 
11
12
  const EMPTY_HANDLERS: IOscHandler[] = [];
12
13
 
@@ -23,9 +24,7 @@ export class OscParser implements IOscParser {
23
24
  };
24
25
 
25
26
  public registerHandler(ident: number, handler: IOscHandler): IDisposable {
26
- if (this._handlers[ident] === undefined) {
27
- this._handlers[ident] = [];
28
- }
27
+ this._handlers[ident] ??= [];
29
28
  const handlerList = this._handlers[ident];
30
29
  handlerList.push(handler);
31
30
  return {
@@ -194,13 +193,15 @@ export class OscParser implements IOscParser {
194
193
  * as OSC handlers.
195
194
  */
196
195
  export class OscHandler implements IOscHandler {
197
- private _data = '';
196
+ private static _payloadLimit = ParserConstants.PAYLOAD_LIMIT;
197
+
198
+ private _data = new LimitedStringBuilder(OscHandler._payloadLimit);
198
199
  private _hitLimit: boolean = false;
199
200
 
200
201
  constructor(private _handler: (data: string) => boolean | Promise<boolean>) { }
201
202
 
202
203
  public start(): void {
203
- this._data = '';
204
+ this._data.reset();
204
205
  this._hitLimit = false;
205
206
  }
206
207
 
@@ -208,9 +209,7 @@ export class OscHandler implements IOscHandler {
208
209
  if (this._hitLimit) {
209
210
  return;
210
211
  }
211
- this._data += utf32ToString(data, start, end);
212
- if (this._data.length > PAYLOAD_LIMIT) {
213
- this._data = '';
212
+ if (this._data.append(utf32ToString(data, start, end))) {
214
213
  this._hitLimit = true;
215
214
  }
216
215
  }
@@ -220,18 +219,18 @@ export class OscHandler implements IOscHandler {
220
219
  if (this._hitLimit) {
221
220
  ret = false;
222
221
  } else if (success) {
223
- ret = this._handler(this._data);
222
+ ret = this._handler(this._data.toString());
224
223
  if (ret instanceof Promise) {
225
224
  // need to hold data until `ret` got resolved
226
225
  // dont care for errors, data will be freed anyway on next start
227
226
  return ret.then(res => {
228
- this._data = '';
227
+ this._data.reset();
229
228
  this._hitLimit = false;
230
229
  return res;
231
230
  });
232
231
  }
233
232
  }
234
- this._data = '';
233
+ this._data.reset();
235
234
  this._hitLimit = false;
236
235
  return ret;
237
236
  }