@xterm/xterm 5.4.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +235 -0
- package/css/xterm.css +209 -0
- package/lib/xterm.js +2 -0
- package/lib/xterm.js.map +1 -0
- package/package.json +101 -0
- package/src/browser/AccessibilityManager.ts +278 -0
- package/src/browser/Clipboard.ts +93 -0
- package/src/browser/ColorContrastCache.ts +34 -0
- package/src/browser/Lifecycle.ts +33 -0
- package/src/browser/Linkifier2.ts +416 -0
- package/src/browser/LocalizableStrings.ts +12 -0
- package/src/browser/OscLinkProvider.ts +128 -0
- package/src/browser/RenderDebouncer.ts +83 -0
- package/src/browser/Terminal.ts +1317 -0
- package/src/browser/TimeBasedDebouncer.ts +86 -0
- package/src/browser/Types.d.ts +181 -0
- package/src/browser/Viewport.ts +401 -0
- package/src/browser/decorations/BufferDecorationRenderer.ts +134 -0
- package/src/browser/decorations/ColorZoneStore.ts +117 -0
- package/src/browser/decorations/OverviewRulerRenderer.ts +218 -0
- package/src/browser/input/CompositionHelper.ts +246 -0
- package/src/browser/input/Mouse.ts +54 -0
- package/src/browser/input/MoveToCell.ts +249 -0
- package/src/browser/public/Terminal.ts +260 -0
- package/src/browser/renderer/dom/DomRenderer.ts +509 -0
- package/src/browser/renderer/dom/DomRendererRowFactory.ts +526 -0
- package/src/browser/renderer/dom/WidthCache.ts +160 -0
- package/src/browser/renderer/shared/CellColorResolver.ts +137 -0
- package/src/browser/renderer/shared/CharAtlasCache.ts +96 -0
- package/src/browser/renderer/shared/CharAtlasUtils.ts +75 -0
- package/src/browser/renderer/shared/Constants.ts +14 -0
- package/src/browser/renderer/shared/CursorBlinkStateManager.ts +146 -0
- package/src/browser/renderer/shared/CustomGlyphs.ts +687 -0
- package/src/browser/renderer/shared/DevicePixelObserver.ts +41 -0
- package/src/browser/renderer/shared/README.md +1 -0
- package/src/browser/renderer/shared/RendererUtils.ts +58 -0
- package/src/browser/renderer/shared/SelectionRenderModel.ts +91 -0
- package/src/browser/renderer/shared/TextureAtlas.ts +1082 -0
- package/src/browser/renderer/shared/Types.d.ts +173 -0
- package/src/browser/selection/SelectionModel.ts +144 -0
- package/src/browser/selection/Types.d.ts +15 -0
- package/src/browser/services/CharSizeService.ts +102 -0
- package/src/browser/services/CharacterJoinerService.ts +339 -0
- package/src/browser/services/CoreBrowserService.ts +137 -0
- package/src/browser/services/MouseService.ts +46 -0
- package/src/browser/services/RenderService.ts +279 -0
- package/src/browser/services/SelectionService.ts +1031 -0
- package/src/browser/services/Services.ts +147 -0
- package/src/browser/services/ThemeService.ts +237 -0
- package/src/common/CircularList.ts +241 -0
- package/src/common/Clone.ts +23 -0
- package/src/common/Color.ts +357 -0
- package/src/common/CoreTerminal.ts +284 -0
- package/src/common/EventEmitter.ts +78 -0
- package/src/common/InputHandler.ts +3461 -0
- package/src/common/Lifecycle.ts +108 -0
- package/src/common/MultiKeyMap.ts +42 -0
- package/src/common/Platform.ts +44 -0
- package/src/common/SortedList.ts +118 -0
- package/src/common/TaskQueue.ts +166 -0
- package/src/common/TypedArrayUtils.ts +17 -0
- package/src/common/Types.d.ts +553 -0
- package/src/common/WindowsMode.ts +27 -0
- package/src/common/buffer/AttributeData.ts +196 -0
- package/src/common/buffer/Buffer.ts +654 -0
- package/src/common/buffer/BufferLine.ts +524 -0
- package/src/common/buffer/BufferRange.ts +13 -0
- package/src/common/buffer/BufferReflow.ts +223 -0
- package/src/common/buffer/BufferSet.ts +134 -0
- package/src/common/buffer/CellData.ts +94 -0
- package/src/common/buffer/Constants.ts +149 -0
- package/src/common/buffer/Marker.ts +43 -0
- package/src/common/buffer/Types.d.ts +52 -0
- package/src/common/data/Charsets.ts +256 -0
- package/src/common/data/EscapeSequences.ts +153 -0
- package/src/common/input/Keyboard.ts +398 -0
- package/src/common/input/TextDecoder.ts +346 -0
- package/src/common/input/UnicodeV6.ts +145 -0
- package/src/common/input/WriteBuffer.ts +246 -0
- package/src/common/input/XParseColor.ts +80 -0
- package/src/common/parser/Constants.ts +58 -0
- package/src/common/parser/DcsParser.ts +192 -0
- package/src/common/parser/EscapeSequenceParser.ts +792 -0
- package/src/common/parser/OscParser.ts +238 -0
- package/src/common/parser/Params.ts +229 -0
- package/src/common/parser/Types.d.ts +275 -0
- package/src/common/public/AddonManager.ts +53 -0
- package/src/common/public/BufferApiView.ts +35 -0
- package/src/common/public/BufferLineApiView.ts +29 -0
- package/src/common/public/BufferNamespaceApi.ts +36 -0
- package/src/common/public/ParserApi.ts +37 -0
- package/src/common/public/UnicodeApi.ts +27 -0
- package/src/common/services/BufferService.ts +151 -0
- package/src/common/services/CharsetService.ts +34 -0
- package/src/common/services/CoreMouseService.ts +318 -0
- package/src/common/services/CoreService.ts +87 -0
- package/src/common/services/DecorationService.ts +140 -0
- package/src/common/services/InstantiationService.ts +85 -0
- package/src/common/services/LogService.ts +124 -0
- package/src/common/services/OptionsService.ts +202 -0
- package/src/common/services/OscLinkService.ts +115 -0
- package/src/common/services/ServiceRegistry.ts +49 -0
- package/src/common/services/Services.ts +373 -0
- package/src/common/services/UnicodeService.ts +111 -0
- package/src/headless/Terminal.ts +136 -0
- package/src/headless/public/Terminal.ts +195 -0
- package/typings/xterm.d.ts +1857 -0
|
@@ -0,0 +1,792 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
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';
|
|
7
|
+
import { ParserState, ParserAction } from 'common/parser/Constants';
|
|
8
|
+
import { Disposable, toDisposable } from 'common/Lifecycle';
|
|
9
|
+
import { IDisposable } from 'common/Types';
|
|
10
|
+
import { Params } from 'common/parser/Params';
|
|
11
|
+
import { OscParser } from 'common/parser/OscParser';
|
|
12
|
+
import { DcsParser } from 'common/parser/DcsParser';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Table values are generated like this:
|
|
16
|
+
* index: currentState << TableValue.INDEX_STATE_SHIFT | charCode
|
|
17
|
+
* value: action << TableValue.TRANSITION_ACTION_SHIFT | nextState
|
|
18
|
+
*/
|
|
19
|
+
const enum TableAccess {
|
|
20
|
+
TRANSITION_ACTION_SHIFT = 4,
|
|
21
|
+
TRANSITION_STATE_MASK = 15,
|
|
22
|
+
INDEX_STATE_SHIFT = 8
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Transition table for EscapeSequenceParser.
|
|
27
|
+
*/
|
|
28
|
+
export class TransitionTable {
|
|
29
|
+
public table: Uint8Array;
|
|
30
|
+
|
|
31
|
+
constructor(length: number) {
|
|
32
|
+
this.table = new Uint8Array(length);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Set default transition.
|
|
37
|
+
* @param action default action
|
|
38
|
+
* @param next default next state
|
|
39
|
+
*/
|
|
40
|
+
public setDefault(action: ParserAction, next: ParserState): void {
|
|
41
|
+
this.table.fill(action << TableAccess.TRANSITION_ACTION_SHIFT | next);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Add a transition to the transition table.
|
|
46
|
+
* @param code input character code
|
|
47
|
+
* @param state current parser state
|
|
48
|
+
* @param action parser action to be done
|
|
49
|
+
* @param next next parser state
|
|
50
|
+
*/
|
|
51
|
+
public add(code: number, state: ParserState, action: ParserAction, next: ParserState): void {
|
|
52
|
+
this.table[state << TableAccess.INDEX_STATE_SHIFT | code] = action << TableAccess.TRANSITION_ACTION_SHIFT | next;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Add transitions for multiple input character codes.
|
|
57
|
+
* @param codes input character code array
|
|
58
|
+
* @param state current parser state
|
|
59
|
+
* @param action parser action to be done
|
|
60
|
+
* @param next next parser state
|
|
61
|
+
*/
|
|
62
|
+
public addMany(codes: number[], state: ParserState, action: ParserAction, next: ParserState): void {
|
|
63
|
+
for (let i = 0; i < codes.length; i++) {
|
|
64
|
+
this.table[state << TableAccess.INDEX_STATE_SHIFT | codes[i]] = action << TableAccess.TRANSITION_ACTION_SHIFT | next;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
// Pseudo-character placeholder for printable non-ascii characters (unicode).
|
|
71
|
+
const NON_ASCII_PRINTABLE = 0xA0;
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* VT500 compatible transition table.
|
|
76
|
+
* Taken from https://vt100.net/emu/dec_ansi_parser.
|
|
77
|
+
*/
|
|
78
|
+
export const VT500_TRANSITION_TABLE = (function (): TransitionTable {
|
|
79
|
+
const table: TransitionTable = new TransitionTable(4095);
|
|
80
|
+
|
|
81
|
+
// range macro for byte
|
|
82
|
+
const BYTE_VALUES = 256;
|
|
83
|
+
const blueprint = Array.apply(null, Array(BYTE_VALUES)).map((unused: any, i: number) => i);
|
|
84
|
+
const r = (start: number, end: number): number[] => blueprint.slice(start, end);
|
|
85
|
+
|
|
86
|
+
// Default definitions.
|
|
87
|
+
const PRINTABLES = r(0x20, 0x7f); // 0x20 (SP) included, 0x7F (DEL) excluded
|
|
88
|
+
const EXECUTABLES = r(0x00, 0x18);
|
|
89
|
+
EXECUTABLES.push(0x19);
|
|
90
|
+
EXECUTABLES.push.apply(EXECUTABLES, r(0x1c, 0x20));
|
|
91
|
+
|
|
92
|
+
const states: number[] = r(ParserState.GROUND, ParserState.DCS_PASSTHROUGH + 1);
|
|
93
|
+
let state: any;
|
|
94
|
+
|
|
95
|
+
// set default transition
|
|
96
|
+
table.setDefault(ParserAction.ERROR, ParserState.GROUND);
|
|
97
|
+
// printables
|
|
98
|
+
table.addMany(PRINTABLES, ParserState.GROUND, ParserAction.PRINT, ParserState.GROUND);
|
|
99
|
+
// global anywhere rules
|
|
100
|
+
for (state in states) {
|
|
101
|
+
table.addMany([0x18, 0x1a, 0x99, 0x9a], state, ParserAction.EXECUTE, ParserState.GROUND);
|
|
102
|
+
table.addMany(r(0x80, 0x90), state, ParserAction.EXECUTE, ParserState.GROUND);
|
|
103
|
+
table.addMany(r(0x90, 0x98), state, ParserAction.EXECUTE, ParserState.GROUND);
|
|
104
|
+
table.add(0x9c, state, ParserAction.IGNORE, ParserState.GROUND); // ST as terminator
|
|
105
|
+
table.add(0x1b, state, ParserAction.CLEAR, ParserState.ESCAPE); // ESC
|
|
106
|
+
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);
|
|
108
|
+
table.add(0x9b, state, ParserAction.CLEAR, ParserState.CSI_ENTRY); // CSI
|
|
109
|
+
table.add(0x90, state, ParserAction.CLEAR, ParserState.DCS_ENTRY); // DCS
|
|
110
|
+
}
|
|
111
|
+
// rules for executables and 7f
|
|
112
|
+
table.addMany(EXECUTABLES, ParserState.GROUND, ParserAction.EXECUTE, ParserState.GROUND);
|
|
113
|
+
table.addMany(EXECUTABLES, ParserState.ESCAPE, ParserAction.EXECUTE, ParserState.ESCAPE);
|
|
114
|
+
table.add(0x7f, ParserState.ESCAPE, ParserAction.IGNORE, ParserState.ESCAPE);
|
|
115
|
+
table.addMany(EXECUTABLES, ParserState.OSC_STRING, ParserAction.IGNORE, ParserState.OSC_STRING);
|
|
116
|
+
table.addMany(EXECUTABLES, ParserState.CSI_ENTRY, ParserAction.EXECUTE, ParserState.CSI_ENTRY);
|
|
117
|
+
table.add(0x7f, ParserState.CSI_ENTRY, ParserAction.IGNORE, ParserState.CSI_ENTRY);
|
|
118
|
+
table.addMany(EXECUTABLES, ParserState.CSI_PARAM, ParserAction.EXECUTE, ParserState.CSI_PARAM);
|
|
119
|
+
table.add(0x7f, ParserState.CSI_PARAM, ParserAction.IGNORE, ParserState.CSI_PARAM);
|
|
120
|
+
table.addMany(EXECUTABLES, ParserState.CSI_IGNORE, ParserAction.EXECUTE, ParserState.CSI_IGNORE);
|
|
121
|
+
table.addMany(EXECUTABLES, ParserState.CSI_INTERMEDIATE, ParserAction.EXECUTE, ParserState.CSI_INTERMEDIATE);
|
|
122
|
+
table.add(0x7f, ParserState.CSI_INTERMEDIATE, ParserAction.IGNORE, ParserState.CSI_INTERMEDIATE);
|
|
123
|
+
table.addMany(EXECUTABLES, ParserState.ESCAPE_INTERMEDIATE, ParserAction.EXECUTE, ParserState.ESCAPE_INTERMEDIATE);
|
|
124
|
+
table.add(0x7f, ParserState.ESCAPE_INTERMEDIATE, ParserAction.IGNORE, ParserState.ESCAPE_INTERMEDIATE);
|
|
125
|
+
// osc
|
|
126
|
+
table.add(0x5d, ParserState.ESCAPE, ParserAction.OSC_START, ParserState.OSC_STRING);
|
|
127
|
+
table.addMany(PRINTABLES, ParserState.OSC_STRING, ParserAction.OSC_PUT, ParserState.OSC_STRING);
|
|
128
|
+
table.add(0x7f, ParserState.OSC_STRING, ParserAction.OSC_PUT, ParserState.OSC_STRING);
|
|
129
|
+
table.addMany([0x9c, 0x1b, 0x18, 0x1a, 0x07], ParserState.OSC_STRING, ParserAction.OSC_END, ParserState.GROUND);
|
|
130
|
+
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);
|
|
137
|
+
// csi entries
|
|
138
|
+
table.add(0x5b, ParserState.ESCAPE, ParserAction.CLEAR, ParserState.CSI_ENTRY);
|
|
139
|
+
table.addMany(r(0x40, 0x7f), ParserState.CSI_ENTRY, ParserAction.CSI_DISPATCH, ParserState.GROUND);
|
|
140
|
+
table.addMany(r(0x30, 0x3c), ParserState.CSI_ENTRY, ParserAction.PARAM, ParserState.CSI_PARAM);
|
|
141
|
+
table.addMany([0x3c, 0x3d, 0x3e, 0x3f], ParserState.CSI_ENTRY, ParserAction.COLLECT, ParserState.CSI_PARAM);
|
|
142
|
+
table.addMany(r(0x30, 0x3c), ParserState.CSI_PARAM, ParserAction.PARAM, ParserState.CSI_PARAM);
|
|
143
|
+
table.addMany(r(0x40, 0x7f), ParserState.CSI_PARAM, ParserAction.CSI_DISPATCH, ParserState.GROUND);
|
|
144
|
+
table.addMany([0x3c, 0x3d, 0x3e, 0x3f], ParserState.CSI_PARAM, ParserAction.IGNORE, ParserState.CSI_IGNORE);
|
|
145
|
+
table.addMany(r(0x20, 0x40), ParserState.CSI_IGNORE, ParserAction.IGNORE, ParserState.CSI_IGNORE);
|
|
146
|
+
table.add(0x7f, ParserState.CSI_IGNORE, ParserAction.IGNORE, ParserState.CSI_IGNORE);
|
|
147
|
+
table.addMany(r(0x40, 0x7f), ParserState.CSI_IGNORE, ParserAction.IGNORE, ParserState.GROUND);
|
|
148
|
+
table.addMany(r(0x20, 0x30), ParserState.CSI_ENTRY, ParserAction.COLLECT, ParserState.CSI_INTERMEDIATE);
|
|
149
|
+
table.addMany(r(0x20, 0x30), ParserState.CSI_INTERMEDIATE, ParserAction.COLLECT, ParserState.CSI_INTERMEDIATE);
|
|
150
|
+
table.addMany(r(0x30, 0x40), ParserState.CSI_INTERMEDIATE, ParserAction.IGNORE, ParserState.CSI_IGNORE);
|
|
151
|
+
table.addMany(r(0x40, 0x7f), ParserState.CSI_INTERMEDIATE, ParserAction.CSI_DISPATCH, ParserState.GROUND);
|
|
152
|
+
table.addMany(r(0x20, 0x30), ParserState.CSI_PARAM, ParserAction.COLLECT, ParserState.CSI_INTERMEDIATE);
|
|
153
|
+
// esc_intermediate
|
|
154
|
+
table.addMany(r(0x20, 0x30), ParserState.ESCAPE, ParserAction.COLLECT, ParserState.ESCAPE_INTERMEDIATE);
|
|
155
|
+
table.addMany(r(0x20, 0x30), ParserState.ESCAPE_INTERMEDIATE, ParserAction.COLLECT, ParserState.ESCAPE_INTERMEDIATE);
|
|
156
|
+
table.addMany(r(0x30, 0x7f), ParserState.ESCAPE_INTERMEDIATE, ParserAction.ESC_DISPATCH, ParserState.GROUND);
|
|
157
|
+
table.addMany(r(0x30, 0x50), ParserState.ESCAPE, ParserAction.ESC_DISPATCH, ParserState.GROUND);
|
|
158
|
+
table.addMany(r(0x51, 0x58), ParserState.ESCAPE, ParserAction.ESC_DISPATCH, ParserState.GROUND);
|
|
159
|
+
table.addMany([0x59, 0x5a, 0x5c], ParserState.ESCAPE, ParserAction.ESC_DISPATCH, ParserState.GROUND);
|
|
160
|
+
table.addMany(r(0x60, 0x7f), ParserState.ESCAPE, ParserAction.ESC_DISPATCH, ParserState.GROUND);
|
|
161
|
+
// dcs entry
|
|
162
|
+
table.add(0x50, ParserState.ESCAPE, ParserAction.CLEAR, ParserState.DCS_ENTRY);
|
|
163
|
+
table.addMany(EXECUTABLES, ParserState.DCS_ENTRY, ParserAction.IGNORE, ParserState.DCS_ENTRY);
|
|
164
|
+
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
|
+
table.addMany(r(0x20, 0x30), ParserState.DCS_ENTRY, ParserAction.COLLECT, ParserState.DCS_INTERMEDIATE);
|
|
167
|
+
table.addMany(r(0x30, 0x3c), ParserState.DCS_ENTRY, ParserAction.PARAM, ParserState.DCS_PARAM);
|
|
168
|
+
table.addMany([0x3c, 0x3d, 0x3e, 0x3f], ParserState.DCS_ENTRY, ParserAction.COLLECT, ParserState.DCS_PARAM);
|
|
169
|
+
table.addMany(EXECUTABLES, ParserState.DCS_IGNORE, ParserAction.IGNORE, ParserState.DCS_IGNORE);
|
|
170
|
+
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
|
+
table.addMany(EXECUTABLES, ParserState.DCS_PARAM, ParserAction.IGNORE, ParserState.DCS_PARAM);
|
|
173
|
+
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
|
+
table.addMany(r(0x30, 0x3c), ParserState.DCS_PARAM, ParserAction.PARAM, ParserState.DCS_PARAM);
|
|
176
|
+
table.addMany([0x3c, 0x3d, 0x3e, 0x3f], ParserState.DCS_PARAM, ParserAction.IGNORE, ParserState.DCS_IGNORE);
|
|
177
|
+
table.addMany(r(0x20, 0x30), ParserState.DCS_PARAM, ParserAction.COLLECT, ParserState.DCS_INTERMEDIATE);
|
|
178
|
+
table.addMany(EXECUTABLES, ParserState.DCS_INTERMEDIATE, ParserAction.IGNORE, ParserState.DCS_INTERMEDIATE);
|
|
179
|
+
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
|
+
table.addMany(r(0x20, 0x30), ParserState.DCS_INTERMEDIATE, ParserAction.COLLECT, ParserState.DCS_INTERMEDIATE);
|
|
182
|
+
table.addMany(r(0x30, 0x40), ParserState.DCS_INTERMEDIATE, ParserAction.IGNORE, ParserState.DCS_IGNORE);
|
|
183
|
+
table.addMany(r(0x40, 0x7f), ParserState.DCS_INTERMEDIATE, ParserAction.DCS_HOOK, ParserState.DCS_PASSTHROUGH);
|
|
184
|
+
table.addMany(r(0x40, 0x7f), ParserState.DCS_PARAM, ParserAction.DCS_HOOK, ParserState.DCS_PASSTHROUGH);
|
|
185
|
+
table.addMany(r(0x40, 0x7f), ParserState.DCS_ENTRY, ParserAction.DCS_HOOK, ParserState.DCS_PASSTHROUGH);
|
|
186
|
+
table.addMany(EXECUTABLES, ParserState.DCS_PASSTHROUGH, ParserAction.DCS_PUT, ParserState.DCS_PASSTHROUGH);
|
|
187
|
+
table.addMany(PRINTABLES, ParserState.DCS_PASSTHROUGH, ParserAction.DCS_PUT, ParserState.DCS_PASSTHROUGH);
|
|
188
|
+
table.add(0x7f, ParserState.DCS_PASSTHROUGH, ParserAction.IGNORE, ParserState.DCS_PASSTHROUGH);
|
|
189
|
+
table.addMany([0x1b, 0x9c, 0x18, 0x1a], ParserState.DCS_PASSTHROUGH, ParserAction.DCS_UNHOOK, ParserState.GROUND);
|
|
190
|
+
// special handling of unicode chars
|
|
191
|
+
table.add(NON_ASCII_PRINTABLE, ParserState.GROUND, ParserAction.PRINT, ParserState.GROUND);
|
|
192
|
+
table.add(NON_ASCII_PRINTABLE, ParserState.OSC_STRING, ParserAction.OSC_PUT, ParserState.OSC_STRING);
|
|
193
|
+
table.add(NON_ASCII_PRINTABLE, ParserState.CSI_IGNORE, ParserAction.IGNORE, ParserState.CSI_IGNORE);
|
|
194
|
+
table.add(NON_ASCII_PRINTABLE, ParserState.DCS_IGNORE, ParserAction.IGNORE, ParserState.DCS_IGNORE);
|
|
195
|
+
table.add(NON_ASCII_PRINTABLE, ParserState.DCS_PASSTHROUGH, ParserAction.DCS_PUT, ParserState.DCS_PASSTHROUGH);
|
|
196
|
+
return table;
|
|
197
|
+
})();
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* EscapeSequenceParser.
|
|
202
|
+
* This class implements the ANSI/DEC compatible parser described by
|
|
203
|
+
* Paul Williams (https://vt100.net/emu/dec_ansi_parser).
|
|
204
|
+
*
|
|
205
|
+
* To implement custom ANSI compliant escape sequences it is not needed to
|
|
206
|
+
* alter this parser, instead consider registering a custom handler.
|
|
207
|
+
* For non ANSI compliant sequences change the transition table with
|
|
208
|
+
* the optional `transitions` constructor argument and
|
|
209
|
+
* reimplement the `parse` method.
|
|
210
|
+
*
|
|
211
|
+
* This parser is currently hardcoded to operate in ZDM (Zero Default Mode)
|
|
212
|
+
* as suggested by the original parser, thus empty parameters are set to 0.
|
|
213
|
+
* This this is not in line with the latest ECMA-48 specification
|
|
214
|
+
* (ZDM was part of the early specs and got completely removed later on).
|
|
215
|
+
*
|
|
216
|
+
* Other than the original parser from vt100.net this parser supports
|
|
217
|
+
* sub parameters in digital parameters separated by colons. Empty sub parameters
|
|
218
|
+
* are set to -1 (no ZDM for sub parameters).
|
|
219
|
+
*
|
|
220
|
+
* About prefix and intermediate bytes:
|
|
221
|
+
* This parser follows the assumptions of the vt100.net parser with these restrictions:
|
|
222
|
+
* - only one prefix byte is allowed as first parameter byte, byte range 0x3c .. 0x3f
|
|
223
|
+
* - max. two intermediates are respected, byte range 0x20 .. 0x2f
|
|
224
|
+
* Note that this is not in line with ECMA-48 which does not limit either of those.
|
|
225
|
+
* Furthermore ECMA-48 allows the prefix byte range at any param byte position. Currently
|
|
226
|
+
* there are no known sequences that follow the broader definition of the specification.
|
|
227
|
+
*
|
|
228
|
+
* TODO: implement error recovery hook via error handler return values
|
|
229
|
+
*/
|
|
230
|
+
export class EscapeSequenceParser extends Disposable implements IEscapeSequenceParser {
|
|
231
|
+
public initialState: number;
|
|
232
|
+
public currentState: number;
|
|
233
|
+
public precedingJoinState: number; // UnicodeJoinProperties
|
|
234
|
+
|
|
235
|
+
// buffers over several parse calls
|
|
236
|
+
protected _params: Params;
|
|
237
|
+
protected _collect: number;
|
|
238
|
+
|
|
239
|
+
// handler lookup containers
|
|
240
|
+
protected _printHandler: PrintHandlerType;
|
|
241
|
+
protected _executeHandlers: { [flag: number]: ExecuteHandlerType };
|
|
242
|
+
protected _csiHandlers: IHandlerCollection<CsiHandlerType>;
|
|
243
|
+
protected _escHandlers: IHandlerCollection<EscHandlerType>;
|
|
244
|
+
protected readonly _oscParser: IOscParser;
|
|
245
|
+
protected readonly _dcsParser: IDcsParser;
|
|
246
|
+
protected _errorHandler: (state: IParsingState) => IParsingState;
|
|
247
|
+
|
|
248
|
+
// fallback handlers
|
|
249
|
+
protected _printHandlerFb: PrintFallbackHandlerType;
|
|
250
|
+
protected _executeHandlerFb: ExecuteFallbackHandlerType;
|
|
251
|
+
protected _csiHandlerFb: CsiFallbackHandlerType;
|
|
252
|
+
protected _escHandlerFb: EscFallbackHandlerType;
|
|
253
|
+
protected _errorHandlerFb: (state: IParsingState) => IParsingState;
|
|
254
|
+
|
|
255
|
+
// parser stack save for async handler support
|
|
256
|
+
protected _parseStack: IParserStackState = {
|
|
257
|
+
state: ParserStackType.NONE,
|
|
258
|
+
handlers: [],
|
|
259
|
+
handlerPos: 0,
|
|
260
|
+
transition: 0,
|
|
261
|
+
chunkPos: 0
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
constructor(
|
|
265
|
+
protected readonly _transitions: TransitionTable = VT500_TRANSITION_TABLE
|
|
266
|
+
) {
|
|
267
|
+
super();
|
|
268
|
+
|
|
269
|
+
this.initialState = ParserState.GROUND;
|
|
270
|
+
this.currentState = this.initialState;
|
|
271
|
+
this._params = new Params(); // defaults to 32 storable params/subparams
|
|
272
|
+
this._params.addParam(0); // ZDM
|
|
273
|
+
this._collect = 0;
|
|
274
|
+
this.precedingJoinState = 0;
|
|
275
|
+
|
|
276
|
+
// set default fallback handlers and handler lookup containers
|
|
277
|
+
this._printHandlerFb = (data, start, end): void => { };
|
|
278
|
+
this._executeHandlerFb = (code: number): void => { };
|
|
279
|
+
this._csiHandlerFb = (ident: number, params: IParams): void => { };
|
|
280
|
+
this._escHandlerFb = (ident: number): void => { };
|
|
281
|
+
this._errorHandlerFb = (state: IParsingState): IParsingState => state;
|
|
282
|
+
this._printHandler = this._printHandlerFb;
|
|
283
|
+
this._executeHandlers = Object.create(null);
|
|
284
|
+
this._csiHandlers = Object.create(null);
|
|
285
|
+
this._escHandlers = Object.create(null);
|
|
286
|
+
this.register(toDisposable(() => {
|
|
287
|
+
this._csiHandlers = Object.create(null);
|
|
288
|
+
this._executeHandlers = Object.create(null);
|
|
289
|
+
this._escHandlers = Object.create(null);
|
|
290
|
+
}));
|
|
291
|
+
this._oscParser = this.register(new OscParser());
|
|
292
|
+
this._dcsParser = this.register(new DcsParser());
|
|
293
|
+
this._errorHandler = this._errorHandlerFb;
|
|
294
|
+
|
|
295
|
+
// swallow 7bit ST (ESC+\)
|
|
296
|
+
this.registerEscHandler({ final: '\\' }, () => true);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
protected _identifier(id: IFunctionIdentifier, finalRange: number[] = [0x40, 0x7e]): number {
|
|
300
|
+
let res = 0;
|
|
301
|
+
if (id.prefix) {
|
|
302
|
+
if (id.prefix.length > 1) {
|
|
303
|
+
throw new Error('only one byte as prefix supported');
|
|
304
|
+
}
|
|
305
|
+
res = id.prefix.charCodeAt(0);
|
|
306
|
+
if (res && 0x3c > res || res > 0x3f) {
|
|
307
|
+
throw new Error('prefix must be in range 0x3c .. 0x3f');
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
if (id.intermediates) {
|
|
311
|
+
if (id.intermediates.length > 2) {
|
|
312
|
+
throw new Error('only two bytes as intermediates are supported');
|
|
313
|
+
}
|
|
314
|
+
for (let i = 0; i < id.intermediates.length; ++i) {
|
|
315
|
+
const intermediate = id.intermediates.charCodeAt(i);
|
|
316
|
+
if (0x20 > intermediate || intermediate > 0x2f) {
|
|
317
|
+
throw new Error('intermediate must be in range 0x20 .. 0x2f');
|
|
318
|
+
}
|
|
319
|
+
res <<= 8;
|
|
320
|
+
res |= intermediate;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (id.final.length !== 1) {
|
|
324
|
+
throw new Error('final must be a single byte');
|
|
325
|
+
}
|
|
326
|
+
const finalCode = id.final.charCodeAt(0);
|
|
327
|
+
if (finalRange[0] > finalCode || finalCode > finalRange[1]) {
|
|
328
|
+
throw new Error(`final must be in range ${finalRange[0]} .. ${finalRange[1]}`);
|
|
329
|
+
}
|
|
330
|
+
res <<= 8;
|
|
331
|
+
res |= finalCode;
|
|
332
|
+
|
|
333
|
+
return res;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
public identToString(ident: number): string {
|
|
337
|
+
const res: string[] = [];
|
|
338
|
+
while (ident) {
|
|
339
|
+
res.push(String.fromCharCode(ident & 0xFF));
|
|
340
|
+
ident >>= 8;
|
|
341
|
+
}
|
|
342
|
+
return res.reverse().join('');
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
public setPrintHandler(handler: PrintHandlerType): void {
|
|
346
|
+
this._printHandler = handler;
|
|
347
|
+
}
|
|
348
|
+
public clearPrintHandler(): void {
|
|
349
|
+
this._printHandler = this._printHandlerFb;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
public registerEscHandler(id: IFunctionIdentifier, handler: EscHandlerType): IDisposable {
|
|
353
|
+
const ident = this._identifier(id, [0x30, 0x7e]);
|
|
354
|
+
if (this._escHandlers[ident] === undefined) {
|
|
355
|
+
this._escHandlers[ident] = [];
|
|
356
|
+
}
|
|
357
|
+
const handlerList = this._escHandlers[ident];
|
|
358
|
+
handlerList.push(handler);
|
|
359
|
+
return {
|
|
360
|
+
dispose: () => {
|
|
361
|
+
const handlerIndex = handlerList.indexOf(handler);
|
|
362
|
+
if (handlerIndex !== -1) {
|
|
363
|
+
handlerList.splice(handlerIndex, 1);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
public clearEscHandler(id: IFunctionIdentifier): void {
|
|
369
|
+
if (this._escHandlers[this._identifier(id, [0x30, 0x7e])]) delete this._escHandlers[this._identifier(id, [0x30, 0x7e])];
|
|
370
|
+
}
|
|
371
|
+
public setEscHandlerFallback(handler: EscFallbackHandlerType): void {
|
|
372
|
+
this._escHandlerFb = handler;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
public setExecuteHandler(flag: string, handler: ExecuteHandlerType): void {
|
|
376
|
+
this._executeHandlers[flag.charCodeAt(0)] = handler;
|
|
377
|
+
}
|
|
378
|
+
public clearExecuteHandler(flag: string): void {
|
|
379
|
+
if (this._executeHandlers[flag.charCodeAt(0)]) delete this._executeHandlers[flag.charCodeAt(0)];
|
|
380
|
+
}
|
|
381
|
+
public setExecuteHandlerFallback(handler: ExecuteFallbackHandlerType): void {
|
|
382
|
+
this._executeHandlerFb = handler;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
public registerCsiHandler(id: IFunctionIdentifier, handler: CsiHandlerType): IDisposable {
|
|
386
|
+
const ident = this._identifier(id);
|
|
387
|
+
if (this._csiHandlers[ident] === undefined) {
|
|
388
|
+
this._csiHandlers[ident] = [];
|
|
389
|
+
}
|
|
390
|
+
const handlerList = this._csiHandlers[ident];
|
|
391
|
+
handlerList.push(handler);
|
|
392
|
+
return {
|
|
393
|
+
dispose: () => {
|
|
394
|
+
const handlerIndex = handlerList.indexOf(handler);
|
|
395
|
+
if (handlerIndex !== -1) {
|
|
396
|
+
handlerList.splice(handlerIndex, 1);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
public clearCsiHandler(id: IFunctionIdentifier): void {
|
|
402
|
+
if (this._csiHandlers[this._identifier(id)]) delete this._csiHandlers[this._identifier(id)];
|
|
403
|
+
}
|
|
404
|
+
public setCsiHandlerFallback(callback: (ident: number, params: IParams) => void): void {
|
|
405
|
+
this._csiHandlerFb = callback;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
public registerDcsHandler(id: IFunctionIdentifier, handler: IDcsHandler): IDisposable {
|
|
409
|
+
return this._dcsParser.registerHandler(this._identifier(id), handler);
|
|
410
|
+
}
|
|
411
|
+
public clearDcsHandler(id: IFunctionIdentifier): void {
|
|
412
|
+
this._dcsParser.clearHandler(this._identifier(id));
|
|
413
|
+
}
|
|
414
|
+
public setDcsHandlerFallback(handler: DcsFallbackHandlerType): void {
|
|
415
|
+
this._dcsParser.setHandlerFallback(handler);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
public registerOscHandler(ident: number, handler: IOscHandler): IDisposable {
|
|
419
|
+
return this._oscParser.registerHandler(ident, handler);
|
|
420
|
+
}
|
|
421
|
+
public clearOscHandler(ident: number): void {
|
|
422
|
+
this._oscParser.clearHandler(ident);
|
|
423
|
+
}
|
|
424
|
+
public setOscHandlerFallback(handler: OscFallbackHandlerType): void {
|
|
425
|
+
this._oscParser.setHandlerFallback(handler);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
public setErrorHandler(callback: (state: IParsingState) => IParsingState): void {
|
|
429
|
+
this._errorHandler = callback;
|
|
430
|
+
}
|
|
431
|
+
public clearErrorHandler(): void {
|
|
432
|
+
this._errorHandler = this._errorHandlerFb;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Reset parser to initial values.
|
|
437
|
+
*
|
|
438
|
+
* This can also be used to lift the improper continuation error condition
|
|
439
|
+
* when dealing with async handlers. Use this only as a last resort to silence
|
|
440
|
+
* that error when the terminal has no pending data to be processed. Note that
|
|
441
|
+
* the interrupted async handler might continue its work in the future messing
|
|
442
|
+
* up the terminal state even further.
|
|
443
|
+
*/
|
|
444
|
+
public reset(): void {
|
|
445
|
+
this.currentState = this.initialState;
|
|
446
|
+
this._oscParser.reset();
|
|
447
|
+
this._dcsParser.reset();
|
|
448
|
+
this._params.reset();
|
|
449
|
+
this._params.addParam(0); // ZDM
|
|
450
|
+
this._collect = 0;
|
|
451
|
+
this.precedingJoinState = 0;
|
|
452
|
+
// abort pending continuation from async handler
|
|
453
|
+
// Here the RESET type indicates, that the next parse call will
|
|
454
|
+
// ignore any saved stack, instead continues sync with next codepoint from GROUND
|
|
455
|
+
if (this._parseStack.state !== ParserStackType.NONE) {
|
|
456
|
+
this._parseStack.state = ParserStackType.RESET;
|
|
457
|
+
this._parseStack.handlers = []; // also release handlers ref
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Async parse support.
|
|
463
|
+
*/
|
|
464
|
+
protected _preserveStack(
|
|
465
|
+
state: ParserStackType,
|
|
466
|
+
handlers: ResumableHandlersType,
|
|
467
|
+
handlerPos: number,
|
|
468
|
+
transition: number,
|
|
469
|
+
chunkPos: number
|
|
470
|
+
): void {
|
|
471
|
+
this._parseStack.state = state;
|
|
472
|
+
this._parseStack.handlers = handlers;
|
|
473
|
+
this._parseStack.handlerPos = handlerPos;
|
|
474
|
+
this._parseStack.transition = transition;
|
|
475
|
+
this._parseStack.chunkPos = chunkPos;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Parse UTF32 codepoints in `data` up to `length`.
|
|
480
|
+
*
|
|
481
|
+
* Note: For several actions with high data load the parsing is optimized
|
|
482
|
+
* by using local read ahead loops with hardcoded conditions to
|
|
483
|
+
* avoid costly table lookups. Make sure that any change of table values
|
|
484
|
+
* will be reflected in the loop conditions as well and vice versa.
|
|
485
|
+
* Affected states/actions:
|
|
486
|
+
* - GROUND:PRINT
|
|
487
|
+
* - CSI_PARAM:PARAM
|
|
488
|
+
* - DCS_PARAM:PARAM
|
|
489
|
+
* - OSC_STRING:OSC_PUT
|
|
490
|
+
* - DCS_PASSTHROUGH:DCS_PUT
|
|
491
|
+
*
|
|
492
|
+
* Note on asynchronous handler support:
|
|
493
|
+
* Any handler returning a promise will be treated as asynchronous.
|
|
494
|
+
* To keep the in-band blocking working for async handlers, `parse` pauses execution,
|
|
495
|
+
* creates a stack save and returns the promise to the caller.
|
|
496
|
+
* For proper continuation of the paused state it is important
|
|
497
|
+
* to await the promise resolving. On resolve the parse must be repeated
|
|
498
|
+
* with the same chunk of data and the resolved value in `promiseResult`
|
|
499
|
+
* until no promise is returned.
|
|
500
|
+
*
|
|
501
|
+
* Important: With only sync handlers defined, parsing is completely synchronous as well.
|
|
502
|
+
* As soon as an async handler is involved, synchronous parsing is not possible anymore.
|
|
503
|
+
*
|
|
504
|
+
* Boilerplate for proper parsing of multiple chunks with async handlers:
|
|
505
|
+
*
|
|
506
|
+
* ```typescript
|
|
507
|
+
* async function parseMultipleChunks(chunks: Uint32Array[]): Promise<void> {
|
|
508
|
+
* for (const chunk of chunks) {
|
|
509
|
+
* let result: void | Promise<boolean>;
|
|
510
|
+
* let prev: boolean | undefined;
|
|
511
|
+
* while (result = parser.parse(chunk, chunk.length, prev)) {
|
|
512
|
+
* prev = await result;
|
|
513
|
+
* }
|
|
514
|
+
* }
|
|
515
|
+
* // finished parsing all chunks...
|
|
516
|
+
* }
|
|
517
|
+
* ```
|
|
518
|
+
*/
|
|
519
|
+
public parse(data: Uint32Array, length: number, promiseResult?: boolean): void | Promise<boolean> {
|
|
520
|
+
let code = 0;
|
|
521
|
+
let transition = 0;
|
|
522
|
+
let start = 0;
|
|
523
|
+
let handlerResult: void | boolean | Promise<boolean>;
|
|
524
|
+
|
|
525
|
+
// resume from async handler
|
|
526
|
+
if (this._parseStack.state) {
|
|
527
|
+
// allow sync parser reset even in continuation mode
|
|
528
|
+
// Note: can be used to recover parser from improper continuation error below
|
|
529
|
+
if (this._parseStack.state === ParserStackType.RESET) {
|
|
530
|
+
this._parseStack.state = ParserStackType.NONE;
|
|
531
|
+
start = this._parseStack.chunkPos + 1; // continue with next codepoint in GROUND
|
|
532
|
+
} else {
|
|
533
|
+
if (promiseResult === undefined || this._parseStack.state === ParserStackType.FAIL) {
|
|
534
|
+
/**
|
|
535
|
+
* Reject further parsing on improper continuation after pausing. This is a really bad
|
|
536
|
+
* condition with screwed up execution order and prolly messed up terminal state,
|
|
537
|
+
* therefore we exit hard with an exception and reject any further parsing.
|
|
538
|
+
*
|
|
539
|
+
* Note: With `Terminal.write` usage this exception should never occur, as the top level
|
|
540
|
+
* calls are guaranteed to handle async conditions properly. If you ever encounter this
|
|
541
|
+
* exception in your terminal integration it indicates, that you injected data chunks to
|
|
542
|
+
* `InputHandler.parse` or `EscapeSequenceParser.parse` synchronously without waiting for
|
|
543
|
+
* continuation of a running async handler.
|
|
544
|
+
*
|
|
545
|
+
* It is possible to get rid of this error by calling `reset`. But dont rely on that, as
|
|
546
|
+
* the pending async handler still might mess up the terminal later. Instead fix the
|
|
547
|
+
* faulty async handling, so this error will not be thrown anymore.
|
|
548
|
+
*/
|
|
549
|
+
this._parseStack.state = ParserStackType.FAIL;
|
|
550
|
+
throw new Error('improper continuation due to previous async handler, giving up parsing');
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// we have to resume the old handler loop if:
|
|
554
|
+
// - return value of the promise was `false`
|
|
555
|
+
// - handlers are not exhausted yet
|
|
556
|
+
const handlers = this._parseStack.handlers;
|
|
557
|
+
let handlerPos = this._parseStack.handlerPos - 1;
|
|
558
|
+
switch (this._parseStack.state) {
|
|
559
|
+
case ParserStackType.CSI:
|
|
560
|
+
if (promiseResult === false && handlerPos > -1) {
|
|
561
|
+
for (; handlerPos >= 0; handlerPos--) {
|
|
562
|
+
handlerResult = (handlers as CsiHandlerType[])[handlerPos](this._params);
|
|
563
|
+
if (handlerResult === true) {
|
|
564
|
+
break;
|
|
565
|
+
} else if (handlerResult instanceof Promise) {
|
|
566
|
+
this._parseStack.handlerPos = handlerPos;
|
|
567
|
+
return handlerResult;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
this._parseStack.handlers = [];
|
|
572
|
+
break;
|
|
573
|
+
case ParserStackType.ESC:
|
|
574
|
+
if (promiseResult === false && handlerPos > -1) {
|
|
575
|
+
for (; handlerPos >= 0; handlerPos--) {
|
|
576
|
+
handlerResult = (handlers as EscHandlerType[])[handlerPos]();
|
|
577
|
+
if (handlerResult === true) {
|
|
578
|
+
break;
|
|
579
|
+
} else if (handlerResult instanceof Promise) {
|
|
580
|
+
this._parseStack.handlerPos = handlerPos;
|
|
581
|
+
return handlerResult;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
this._parseStack.handlers = [];
|
|
586
|
+
break;
|
|
587
|
+
case ParserStackType.DCS:
|
|
588
|
+
code = data[this._parseStack.chunkPos];
|
|
589
|
+
handlerResult = this._dcsParser.unhook(code !== 0x18 && code !== 0x1a, promiseResult);
|
|
590
|
+
if (handlerResult) {
|
|
591
|
+
return handlerResult;
|
|
592
|
+
}
|
|
593
|
+
if (code === 0x1b) this._parseStack.transition |= ParserState.ESCAPE;
|
|
594
|
+
this._params.reset();
|
|
595
|
+
this._params.addParam(0); // ZDM
|
|
596
|
+
this._collect = 0;
|
|
597
|
+
break;
|
|
598
|
+
case ParserStackType.OSC:
|
|
599
|
+
code = data[this._parseStack.chunkPos];
|
|
600
|
+
handlerResult = this._oscParser.end(code !== 0x18 && code !== 0x1a, promiseResult);
|
|
601
|
+
if (handlerResult) {
|
|
602
|
+
return handlerResult;
|
|
603
|
+
}
|
|
604
|
+
if (code === 0x1b) this._parseStack.transition |= ParserState.ESCAPE;
|
|
605
|
+
this._params.reset();
|
|
606
|
+
this._params.addParam(0); // ZDM
|
|
607
|
+
this._collect = 0;
|
|
608
|
+
break;
|
|
609
|
+
}
|
|
610
|
+
// cleanup before continuing with the main sync loop
|
|
611
|
+
this._parseStack.state = ParserStackType.NONE;
|
|
612
|
+
start = this._parseStack.chunkPos + 1;
|
|
613
|
+
this.precedingJoinState = 0;
|
|
614
|
+
this.currentState = this._parseStack.transition & TableAccess.TRANSITION_STATE_MASK;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// continue with main sync loop
|
|
619
|
+
|
|
620
|
+
// process input string
|
|
621
|
+
for (let i = start; i < length; ++i) {
|
|
622
|
+
code = data[i];
|
|
623
|
+
|
|
624
|
+
// normal transition & action lookup
|
|
625
|
+
transition = this._transitions.table[this.currentState << TableAccess.INDEX_STATE_SHIFT | (code < 0xa0 ? code : NON_ASCII_PRINTABLE)];
|
|
626
|
+
switch (transition >> TableAccess.TRANSITION_ACTION_SHIFT) {
|
|
627
|
+
case ParserAction.PRINT:
|
|
628
|
+
// read ahead with loop unrolling
|
|
629
|
+
// 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;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
break;
|
|
653
|
+
case ParserAction.EXECUTE:
|
|
654
|
+
if (this._executeHandlers[code]) this._executeHandlers[code]();
|
|
655
|
+
else this._executeHandlerFb(code);
|
|
656
|
+
this.precedingJoinState = 0;
|
|
657
|
+
break;
|
|
658
|
+
case ParserAction.IGNORE:
|
|
659
|
+
break;
|
|
660
|
+
case ParserAction.ERROR:
|
|
661
|
+
const inject: IParsingState = this._errorHandler(
|
|
662
|
+
{
|
|
663
|
+
position: i,
|
|
664
|
+
code,
|
|
665
|
+
currentState: this.currentState,
|
|
666
|
+
collect: this._collect,
|
|
667
|
+
params: this._params,
|
|
668
|
+
abort: false
|
|
669
|
+
});
|
|
670
|
+
if (inject.abort) return;
|
|
671
|
+
// inject values: currently not implemented
|
|
672
|
+
break;
|
|
673
|
+
case ParserAction.CSI_DISPATCH:
|
|
674
|
+
// Trigger CSI Handler
|
|
675
|
+
const handlers = this._csiHandlers[this._collect << 8 | code];
|
|
676
|
+
let j = handlers ? handlers.length - 1 : -1;
|
|
677
|
+
for (; j >= 0; j--) {
|
|
678
|
+
// true means success and to stop bubbling
|
|
679
|
+
// a promise indicates an async handler that needs to finish before progressing
|
|
680
|
+
handlerResult = handlers[j](this._params);
|
|
681
|
+
if (handlerResult === true) {
|
|
682
|
+
break;
|
|
683
|
+
} else if (handlerResult instanceof Promise) {
|
|
684
|
+
this._preserveStack(ParserStackType.CSI, handlers, j, transition, i);
|
|
685
|
+
return handlerResult;
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
if (j < 0) {
|
|
689
|
+
this._csiHandlerFb(this._collect << 8 | code, this._params);
|
|
690
|
+
}
|
|
691
|
+
this.precedingJoinState = 0;
|
|
692
|
+
break;
|
|
693
|
+
case ParserAction.PARAM:
|
|
694
|
+
// inner loop: digits (0x30 - 0x39) and ; (0x3b) and : (0x3a)
|
|
695
|
+
do {
|
|
696
|
+
switch (code) {
|
|
697
|
+
case 0x3b:
|
|
698
|
+
this._params.addParam(0); // ZDM
|
|
699
|
+
break;
|
|
700
|
+
case 0x3a:
|
|
701
|
+
this._params.addSubParam(-1);
|
|
702
|
+
break;
|
|
703
|
+
default: // 0x30 - 0x39
|
|
704
|
+
this._params.addDigit(code - 48);
|
|
705
|
+
}
|
|
706
|
+
} while (++i < length && (code = data[i]) > 0x2f && code < 0x3c);
|
|
707
|
+
i--;
|
|
708
|
+
break;
|
|
709
|
+
case ParserAction.COLLECT:
|
|
710
|
+
this._collect <<= 8;
|
|
711
|
+
this._collect |= code;
|
|
712
|
+
break;
|
|
713
|
+
case ParserAction.ESC_DISPATCH:
|
|
714
|
+
const handlersEsc = this._escHandlers[this._collect << 8 | code];
|
|
715
|
+
let jj = handlersEsc ? handlersEsc.length - 1 : -1;
|
|
716
|
+
for (; jj >= 0; jj--) {
|
|
717
|
+
// true means success and to stop bubbling
|
|
718
|
+
// a promise indicates an async handler that needs to finish before progressing
|
|
719
|
+
handlerResult = handlersEsc[jj]();
|
|
720
|
+
if (handlerResult === true) {
|
|
721
|
+
break;
|
|
722
|
+
} else if (handlerResult instanceof Promise) {
|
|
723
|
+
this._preserveStack(ParserStackType.ESC, handlersEsc, jj, transition, i);
|
|
724
|
+
return handlerResult;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
if (jj < 0) {
|
|
728
|
+
this._escHandlerFb(this._collect << 8 | code);
|
|
729
|
+
}
|
|
730
|
+
this.precedingJoinState = 0;
|
|
731
|
+
break;
|
|
732
|
+
case ParserAction.CLEAR:
|
|
733
|
+
this._params.reset();
|
|
734
|
+
this._params.addParam(0); // ZDM
|
|
735
|
+
this._collect = 0;
|
|
736
|
+
break;
|
|
737
|
+
case ParserAction.DCS_HOOK:
|
|
738
|
+
this._dcsParser.hook(this._collect << 8 | code, this._params);
|
|
739
|
+
break;
|
|
740
|
+
case ParserAction.DCS_PUT:
|
|
741
|
+
// inner loop - exit DCS_PUT: 0x18, 0x1a, 0x1b, 0x7f, 0x80 - 0x9f
|
|
742
|
+
// unhook triggered by: 0x1b, 0x9c (success) and 0x18, 0x1a (abort)
|
|
743
|
+
for (let j = i + 1; ; ++j) {
|
|
744
|
+
if (j >= length || (code = data[j]) === 0x18 || code === 0x1a || code === 0x1b || (code > 0x7f && code < NON_ASCII_PRINTABLE)) {
|
|
745
|
+
this._dcsParser.put(data, i, j);
|
|
746
|
+
i = j - 1;
|
|
747
|
+
break;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
break;
|
|
751
|
+
case ParserAction.DCS_UNHOOK:
|
|
752
|
+
handlerResult = this._dcsParser.unhook(code !== 0x18 && code !== 0x1a);
|
|
753
|
+
if (handlerResult) {
|
|
754
|
+
this._preserveStack(ParserStackType.DCS, [], 0, transition, i);
|
|
755
|
+
return handlerResult;
|
|
756
|
+
}
|
|
757
|
+
if (code === 0x1b) transition |= ParserState.ESCAPE;
|
|
758
|
+
this._params.reset();
|
|
759
|
+
this._params.addParam(0); // ZDM
|
|
760
|
+
this._collect = 0;
|
|
761
|
+
this.precedingJoinState = 0;
|
|
762
|
+
break;
|
|
763
|
+
case ParserAction.OSC_START:
|
|
764
|
+
this._oscParser.start();
|
|
765
|
+
break;
|
|
766
|
+
case ParserAction.OSC_PUT:
|
|
767
|
+
// inner loop: 0x20 (SP) included, 0x7F (DEL) included
|
|
768
|
+
for (let j = i + 1; ; j++) {
|
|
769
|
+
if (j >= length || (code = data[j]) < 0x20 || (code > 0x7f && code < NON_ASCII_PRINTABLE)) {
|
|
770
|
+
this._oscParser.put(data, i, j);
|
|
771
|
+
i = j - 1;
|
|
772
|
+
break;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
break;
|
|
776
|
+
case ParserAction.OSC_END:
|
|
777
|
+
handlerResult = this._oscParser.end(code !== 0x18 && code !== 0x1a);
|
|
778
|
+
if (handlerResult) {
|
|
779
|
+
this._preserveStack(ParserStackType.OSC, [], 0, transition, i);
|
|
780
|
+
return handlerResult;
|
|
781
|
+
}
|
|
782
|
+
if (code === 0x1b) transition |= ParserState.ESCAPE;
|
|
783
|
+
this._params.reset();
|
|
784
|
+
this._params.addParam(0); // ZDM
|
|
785
|
+
this._collect = 0;
|
|
786
|
+
this.precedingJoinState = 0;
|
|
787
|
+
break;
|
|
788
|
+
}
|
|
789
|
+
this.currentState = transition & TableAccess.TRANSITION_STATE_MASK;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}
|