]> git.proxmox.com Git - mirror_xterm.js.git/blame - src/Parser.ts
Merge pull request #926 from ficristo/search-fix
[mirror_xterm.js.git] / src / Parser.ts
CommitLineData
ef60e50e
DI
1/**
2 * @license MIT
3 */
4
659fb90c
DI
5import { C0 } from './EscapeSequences';
6import { IInputHandler } from './Interfaces';
aab67c2e 7import { CHARSETS, DEFAULT_CHARSET } from './Charsets';
659fb90c 8
fa3484cd
DI
9const normalStateHandler: {[key: string]: (parser: Parser, handler: IInputHandler) => void} = {};
10normalStateHandler[C0.BEL] = (parser, handler) => handler.bell();
11normalStateHandler[C0.LF] = (parser, handler) => handler.lineFeed();
659fb90c
DI
12normalStateHandler[C0.VT] = normalStateHandler[C0.LF];
13normalStateHandler[C0.FF] = normalStateHandler[C0.LF];
fa3484cd
DI
14normalStateHandler[C0.CR] = (parser, handler) => handler.carriageReturn();
15normalStateHandler[C0.BS] = (parser, handler) => handler.backspace();
16normalStateHandler[C0.HT] = (parser, handler) => handler.tab();
17normalStateHandler[C0.SO] = (parser, handler) => handler.shiftOut();
18normalStateHandler[C0.SI] = (parser, handler) => handler.shiftIn();
19normalStateHandler[C0.ESC] = (parser, handler) => parser.setState(ParserState.ESCAPED);
672dc1a2 20
ecd7e69f
DI
21// TODO: Remove terminal when parser owns params and currentParam
22const escapedStateHandler: {[key: string]: (parser: Parser, terminal: any) => void} = {};
23escapedStateHandler['['] = (parser, terminal) => {
24 // ESC [ Control Sequence Introducer (CSI is 0x9b)
25 terminal.params = [];
26 terminal.currentParam = 0;
27 parser.setState(ParserState.CSI_PARAM);
28};
29escapedStateHandler[']'] = (parser, terminal) => {
30 // ESC ] Operating System Command (OSC is 0x9d)
31 terminal.params = [];
32 terminal.currentParam = 0;
33 parser.setState(ParserState.OSC);
34};
35escapedStateHandler['P'] = (parser, terminal) => {
36 // ESC P Device Control String (DCS is 0x90)
37 terminal.params = [];
38 terminal.currentParam = 0;
39 parser.setState(ParserState.DCS);
40};
41escapedStateHandler['_'] = (parser, terminal) => {
42 // ESC _ Application Program Command ( APC is 0x9f).
43 parser.setState(ParserState.IGNORE);
4448ebe3 44};
ecd7e69f
DI
45escapedStateHandler['^'] = (parser, terminal) => {
46 // ESC ^ Privacy Message ( PM is 0x9e).
47 parser.setState(ParserState.IGNORE);
4448ebe3 48};
ecd7e69f
DI
49escapedStateHandler['c'] = (parser, terminal) => {
50 // ESC c Full Reset (RIS).
51 terminal.reset();
4448ebe3 52};
ecd7e69f
DI
53escapedStateHandler['E'] = (parser, terminal) => {
54 // ESC E Next Line ( NEL is 0x85).
73b4bfb5 55 terminal.buffer.x = 0;
ecd7e69f
DI
56 terminal.index();
57 parser.setState(ParserState.NORMAL);
4448ebe3 58};
ecd7e69f
DI
59escapedStateHandler['D'] = (parser, terminal) => {
60 // ESC D Index ( IND is 0x84).
61 terminal.index();
62 parser.setState(ParserState.NORMAL);
63};
64escapedStateHandler['M'] = (parser, terminal) => {
65 // ESC M Reverse Index ( RI is 0x8d).
66 terminal.reverseIndex();
67 parser.setState(ParserState.NORMAL);
68};
69escapedStateHandler['%'] = (parser, terminal) => {
70 // ESC % Select default/utf-8 character set.
71 // @ = default, G = utf-8
72 terminal.setgLevel(0);
aab67c2e 73 terminal.setgCharset(0, DEFAULT_CHARSET); // US (default)
ecd7e69f
DI
74 parser.setState(ParserState.NORMAL);
75 parser.skipNextChar();
76};
1b344ce7 77escapedStateHandler[C0.CAN] = (parser) => parser.setState(ParserState.NORMAL);
ecd7e69f 78
7572dd5f
DI
79const csiParamStateHandler: {[key: string]: (parser: Parser) => void} = {};
80csiParamStateHandler['?'] = (parser) => parser.setPrefix('?');
81csiParamStateHandler['>'] = (parser) => parser.setPrefix('>');
82csiParamStateHandler['!'] = (parser) => parser.setPrefix('!');
83csiParamStateHandler['0'] = (parser) => parser.setParam(parser.getParam() * 10);
84csiParamStateHandler['1'] = (parser) => parser.setParam(parser.getParam() * 10 + 1);
85csiParamStateHandler['2'] = (parser) => parser.setParam(parser.getParam() * 10 + 2);
86csiParamStateHandler['3'] = (parser) => parser.setParam(parser.getParam() * 10 + 3);
87csiParamStateHandler['4'] = (parser) => parser.setParam(parser.getParam() * 10 + 4);
88csiParamStateHandler['5'] = (parser) => parser.setParam(parser.getParam() * 10 + 5);
89csiParamStateHandler['6'] = (parser) => parser.setParam(parser.getParam() * 10 + 6);
90csiParamStateHandler['7'] = (parser) => parser.setParam(parser.getParam() * 10 + 7);
91csiParamStateHandler['8'] = (parser) => parser.setParam(parser.getParam() * 10 + 8);
92csiParamStateHandler['9'] = (parser) => parser.setParam(parser.getParam() * 10 + 9);
93csiParamStateHandler['$'] = (parser) => parser.setPostfix('$');
94csiParamStateHandler['"'] = (parser) => parser.setPostfix('"');
95csiParamStateHandler[' '] = (parser) => parser.setPostfix(' ');
96csiParamStateHandler['\''] = (parser) => parser.setPostfix('\'');
c7fa2d55 97csiParamStateHandler[';'] = (parser) => parser.finalizeParam();
1b344ce7 98csiParamStateHandler[C0.CAN] = (parser) => parser.setState(ParserState.NORMAL);
9942477b 99
1b344ce7 100const csiStateHandler: {[key: string]: (handler: IInputHandler, params: number[], prefix: string, postfix: string, parser: Parser) => void} = {};
f4846aa1
DI
101csiStateHandler['@'] = (handler, params, prefix) => handler.insertChars(params);
102csiStateHandler['A'] = (handler, params, prefix) => handler.cursorUp(params);
103csiStateHandler['B'] = (handler, params, prefix) => handler.cursorDown(params);
104csiStateHandler['C'] = (handler, params, prefix) => handler.cursorForward(params);
105csiStateHandler['D'] = (handler, params, prefix) => handler.cursorBackward(params);
106csiStateHandler['E'] = (handler, params, prefix) => handler.cursorNextLine(params);
107csiStateHandler['F'] = (handler, params, prefix) => handler.cursorPrecedingLine(params);
108csiStateHandler['G'] = (handler, params, prefix) => handler.cursorCharAbsolute(params);
109csiStateHandler['H'] = (handler, params, prefix) => handler.cursorPosition(params);
110csiStateHandler['I'] = (handler, params, prefix) => handler.cursorForwardTab(params);
111csiStateHandler['J'] = (handler, params, prefix) => handler.eraseInDisplay(params);
112csiStateHandler['K'] = (handler, params, prefix) => handler.eraseInLine(params);
113csiStateHandler['L'] = (handler, params, prefix) => handler.insertLines(params);
114csiStateHandler['M'] = (handler, params, prefix) => handler.deleteLines(params);
115csiStateHandler['P'] = (handler, params, prefix) => handler.deleteChars(params);
116csiStateHandler['S'] = (handler, params, prefix) => handler.scrollUp(params);
117csiStateHandler['T'] = (handler, params, prefix) => {
118 if (params.length < 2 && !prefix) {
119 handler.scrollDown(params);
120 }
121};
122csiStateHandler['X'] = (handler, params, prefix) => handler.eraseChars(params);
123csiStateHandler['Z'] = (handler, params, prefix) => handler.cursorBackwardTab(params);
124csiStateHandler['`'] = (handler, params, prefix) => handler.charPosAbsolute(params);
125csiStateHandler['a'] = (handler, params, prefix) => handler.HPositionRelative(params);
126csiStateHandler['b'] = (handler, params, prefix) => handler.repeatPrecedingCharacter(params);
127csiStateHandler['c'] = (handler, params, prefix) => handler.sendDeviceAttributes(params);
128csiStateHandler['d'] = (handler, params, prefix) => handler.linePosAbsolute(params);
129csiStateHandler['e'] = (handler, params, prefix) => handler.VPositionRelative(params);
130csiStateHandler['f'] = (handler, params, prefix) => handler.HVPosition(params);
131csiStateHandler['g'] = (handler, params, prefix) => handler.tabClear(params);
132csiStateHandler['h'] = (handler, params, prefix) => handler.setMode(params);
133csiStateHandler['l'] = (handler, params, prefix) => handler.resetMode(params);
134csiStateHandler['m'] = (handler, params, prefix) => handler.charAttributes(params);
135csiStateHandler['n'] = (handler, params, prefix) => handler.deviceStatus(params);
136csiStateHandler['p'] = (handler, params, prefix) => {
137 switch (prefix) {
138 case '!': handler.softReset(params); break;
139 }
140};
0bd469f5
DI
141csiStateHandler['q'] = (handler, params, prefix, postfix) => {
142 if (postfix === ' ') {
143 handler.setCursorStyle(params);
144 }
145};
9b662080
DI
146csiStateHandler['r'] = (handler, params) => handler.setScrollRegion(params);
147csiStateHandler['s'] = (handler, params) => handler.saveCursor(params);
148csiStateHandler['u'] = (handler, params) => handler.restoreCursor(params);
1b344ce7 149csiStateHandler[C0.CAN] = (handler, params, prefix, postfix, parser) => parser.setState(ParserState.NORMAL);
a31921ae
DI
150
151enum ParserState {
152 NORMAL = 0,
153 ESCAPED = 1,
c7fa2d55
DI
154 CSI_PARAM = 2,
155 CSI = 3,
156 OSC = 4,
157 CHARSET = 5,
158 DCS = 6,
159 IGNORE = 7
a31921ae
DI
160}
161
ef60e50e
DI
162/**
163 * The terminal's parser, all input into the terminal goes through the parser
164 * which parses and defers the actual input handling the the IInputHandler
165 * specified in the constructor.
166 */
a31921ae 167export class Parser {
ecd7e69f
DI
168 private _state: ParserState;
169 private _position: number;
a31921ae
DI
170
171 // TODO: Remove terminal when handler can do everything
172 constructor(
173 private _inputHandler: IInputHandler,
174 private _terminal: any
175 ) {
ecd7e69f 176 this._state = ParserState.NORMAL;
a31921ae
DI
177 }
178
ef60e50e
DI
179 /**
180 * Parse and handle data.
181 *
182 * @param data The data to parse.
183 */
2c3d98ab 184 public parse(data: string): ParserState {
ecd7e69f 185 let l = data.length, j, cs, ch, code, low;
a31921ae 186
604959a3
DI
187 if (this._terminal.debug) {
188 this._terminal.log('data: ' + data);
189 }
190
ecd7e69f 191 this._position = 0;
a31921ae
DI
192 // apply leftover surrogate high from last write
193 if (this._terminal.surrogate_high) {
194 data = this._terminal.surrogate_high + data;
195 this._terminal.surrogate_high = '';
196 }
197
ecd7e69f
DI
198 for (; this._position < l; this._position++) {
199 ch = data[this._position];
a31921ae
DI
200
201 // FIXME: higher chars than 0xa0 are not allowed in escape sequences
202 // --> maybe move to default
ecd7e69f 203 code = data.charCodeAt(this._position);
a31921ae
DI
204 if (0xD800 <= code && code <= 0xDBFF) {
205 // we got a surrogate high
206 // get surrogate low (next 2 bytes)
ecd7e69f 207 low = data.charCodeAt(this._position + 1);
a31921ae
DI
208 if (isNaN(low)) {
209 // end of data stream, save surrogate high
210 this._terminal.surrogate_high = ch;
211 continue;
212 }
213 code = ((code - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000;
ecd7e69f 214 ch += data.charAt(this._position + 1);
a31921ae
DI
215 }
216 // surrogate low - already handled above
217 if (0xDC00 <= code && code <= 0xDFFF)
218 continue;
219
ecd7e69f 220 switch (this._state) {
a31921ae 221 case ParserState.NORMAL:
fa3484cd
DI
222 if (ch in normalStateHandler) {
223 normalStateHandler[ch](this, this._inputHandler);
224 } else {
225 this._inputHandler.addChar(ch, code);
a31921ae
DI
226 }
227 break;
228 case ParserState.ESCAPED:
ecd7e69f
DI
229 if (ch in escapedStateHandler) {
230 escapedStateHandler[ch](this, this._terminal);
231 // Skip switch as it was just handled
232 break;
233 }
a31921ae 234 switch (ch) {
a31921ae
DI
235
236 // ESC (,),*,+,-,. Designate G0-G2 Character Set.
237 case '(': // <-- this seems to get all the attention
238 case ')':
239 case '*':
240 case '+':
241 case '-':
242 case '.':
243 switch (ch) {
244 case '(':
991b2843 245 this._terminal.gcharset = 0;
a31921ae
DI
246 break;
247 case ')':
991b2843 248 this._terminal.gcharset = 1;
a31921ae
DI
249 break;
250 case '*':
991b2843 251 this._terminal.gcharset = 2;
a31921ae
DI
252 break;
253 case '+':
991b2843 254 this._terminal.gcharset = 3;
a31921ae
DI
255 break;
256 case '-':
991b2843 257 this._terminal.gcharset = 1;
a31921ae
DI
258 break;
259 case '.':
991b2843 260 this._terminal.gcharset = 2;
a31921ae
DI
261 break;
262 }
ecd7e69f 263 this._state = ParserState.CHARSET;
a31921ae
DI
264 break;
265
266 // Designate G3 Character Set (VT300).
267 // A = ISO Latin-1 Supplemental.
268 // Not implemented.
269 case '/':
991b2843 270 this._terminal.gcharset = 3;
ecd7e69f
DI
271 this._state = ParserState.CHARSET;
272 this._position--;
a31921ae
DI
273 break;
274
275 // ESC N
276 // Single Shift Select of G2 Character Set
277 // ( SS2 is 0x8e). This affects next character only.
278 case 'N':
279 break;
280 // ESC O
281 // Single Shift Select of G3 Character Set
282 // ( SS3 is 0x8f). This affects next character only.
283 case 'O':
284 break;
285 // ESC n
286 // Invoke the G2 Character Set as GL (LS2).
287 case 'n':
991b2843 288 this._terminal.setgLevel(2);
a31921ae
DI
289 break;
290 // ESC o
291 // Invoke the G3 Character Set as GL (LS3).
292 case 'o':
991b2843 293 this._terminal.setgLevel(3);
a31921ae
DI
294 break;
295 // ESC |
296 // Invoke the G3 Character Set as GR (LS3R).
297 case '|':
991b2843 298 this._terminal.setgLevel(3);
a31921ae
DI
299 break;
300 // ESC }
301 // Invoke the G2 Character Set as GR (LS2R).
302 case '}':
991b2843 303 this._terminal.setgLevel(2);
a31921ae
DI
304 break;
305 // ESC ~
306 // Invoke the G1 Character Set as GR (LS1R).
307 case '~':
991b2843 308 this._terminal.setgLevel(1);
a31921ae
DI
309 break;
310
311 // ESC 7 Save Cursor (DECSC).
312 case '7':
f4846aa1 313 this._inputHandler.saveCursor();
ecd7e69f 314 this._state = ParserState.NORMAL;
a31921ae
DI
315 break;
316
317 // ESC 8 Restore Cursor (DECRC).
318 case '8':
f4846aa1 319 this._inputHandler.restoreCursor();
ecd7e69f 320 this._state = ParserState.NORMAL;
a31921ae
DI
321 break;
322
323 // ESC # 3 DEC line height/width
324 case '#':
ecd7e69f
DI
325 this._state = ParserState.NORMAL;
326 this._position++;
a31921ae
DI
327 break;
328
329 // ESC H Tab Set (HTS is 0x88).
330 case 'H':
991b2843 331 this._terminal.tabSet();
ecd7e69f 332 this._state = ParserState.NORMAL;
a31921ae
DI
333 break;
334
335 // ESC = Application Keypad (DECKPAM).
336 case '=':
991b2843
DI
337 this._terminal.log('Serial port requested application keypad.');
338 this._terminal.applicationKeypad = true;
339 this._terminal.viewport.syncScrollArea();
ecd7e69f 340 this._state = ParserState.NORMAL;
a31921ae
DI
341 break;
342
343 // ESC > Normal Keypad (DECKPNM).
344 case '>':
991b2843
DI
345 this._terminal.log('Switching back to normal keypad.');
346 this._terminal.applicationKeypad = false;
347 this._terminal.viewport.syncScrollArea();
ecd7e69f 348 this._state = ParserState.NORMAL;
a31921ae
DI
349 break;
350
351 default:
ecd7e69f 352 this._state = ParserState.NORMAL;
991b2843 353 this._terminal.error('Unknown ESC control: %s.', ch);
a31921ae
DI
354 break;
355 }
356 break;
357
358 case ParserState.CHARSET:
aab67c2e
DI
359 if (ch in CHARSETS) {
360 cs = CHARSETS[ch];
4448ebe3
DI
361 if (ch === '/') { // ISOLatin is actually /A
362 this.skipNextChar();
363 }
364 } else {
aab67c2e 365 cs = DEFAULT_CHARSET;
a31921ae 366 }
991b2843
DI
367 this._terminal.setgCharset(this._terminal.gcharset, cs);
368 this._terminal.gcharset = null;
ecd7e69f 369 this._state = ParserState.NORMAL;
a31921ae
DI
370 break;
371
372 case ParserState.OSC:
373 // OSC Ps ; Pt ST
374 // OSC Ps ; Pt BEL
375 // Set Text Parameters.
376 if (ch === C0.ESC || ch === C0.BEL) {
ecd7e69f 377 if (ch === C0.ESC) this._position++;
a31921ae 378
991b2843 379 this._terminal.params.push(this._terminal.currentParam);
a31921ae 380
991b2843 381 switch (this._terminal.params[0]) {
a31921ae
DI
382 case 0:
383 case 1:
384 case 2:
991b2843
DI
385 if (this._terminal.params[1]) {
386 this._terminal.title = this._terminal.params[1];
387 this._terminal.handleTitle(this._terminal.title);
a31921ae
DI
388 }
389 break;
390 case 3:
391 // set X property
392 break;
393 case 4:
394 case 5:
395 // change dynamic colors
396 break;
397 case 10:
398 case 11:
399 case 12:
400 case 13:
401 case 14:
402 case 15:
403 case 16:
404 case 17:
405 case 18:
406 case 19:
407 // change dynamic ui colors
408 break;
409 case 46:
410 // change log file
411 break;
412 case 50:
413 // dynamic font
414 break;
415 case 51:
416 // emacs shell
417 break;
418 case 52:
419 // manipulate selection data
420 break;
421 case 104:
422 case 105:
423 case 110:
424 case 111:
425 case 112:
426 case 113:
427 case 114:
428 case 115:
429 case 116:
430 case 117:
431 case 118:
432 // reset colors
433 break;
434 }
435
991b2843
DI
436 this._terminal.params = [];
437 this._terminal.currentParam = 0;
ecd7e69f 438 this._state = ParserState.NORMAL;
a31921ae 439 } else {
991b2843 440 if (!this._terminal.params.length) {
a31921ae 441 if (ch >= '0' && ch <= '9') {
991b2843
DI
442 this._terminal.currentParam =
443 this._terminal.currentParam * 10 + ch.charCodeAt(0) - 48;
a31921ae 444 } else if (ch === ';') {
991b2843
DI
445 this._terminal.params.push(this._terminal.currentParam);
446 this._terminal.currentParam = '';
a31921ae
DI
447 }
448 } else {
991b2843 449 this._terminal.currentParam += ch;
a31921ae
DI
450 }
451 }
452 break;
453
c7fa2d55 454 case ParserState.CSI_PARAM:
9942477b 455 if (ch in csiParamStateHandler) {
7572dd5f 456 csiParamStateHandler[ch](this);
a31921ae
DI
457 break;
458 }
c7fa2d55
DI
459 this.finalizeParam();
460 // Fall through the CSI as this character should be the CSI code.
ecd7e69f 461 this._state = ParserState.CSI;
a31921ae 462
c7fa2d55 463 case ParserState.CSI:
9942477b 464 if (ch in csiStateHandler) {
604959a3
DI
465 if (this._terminal.debug) {
466 this._terminal.log(`CSI ${this._terminal.prefix ? this._terminal.prefix : ''} ${this._terminal.params ? this._terminal.params.join(';') : ''} ${this._terminal.postfix ? this._terminal.postfix : ''} ${ch}`);
467 }
1b344ce7 468 csiStateHandler[ch](this._inputHandler, this._terminal.params, this._terminal.prefix, this._terminal.postfix, this);
f4846aa1
DI
469 } else {
470 this._terminal.error('Unknown CSI code: %s.', ch);
a31921ae
DI
471 }
472
ecd7e69f 473 this._state = ParserState.NORMAL;
991b2843
DI
474 this._terminal.prefix = '';
475 this._terminal.postfix = '';
a31921ae
DI
476 break;
477
478 case ParserState.DCS:
479 if (ch === C0.ESC || ch === C0.BEL) {
ecd7e69f 480 if (ch === C0.ESC) this._position++;
13088f55
DI
481 let pt;
482 let valid: boolean;
a31921ae 483
991b2843 484 switch (this._terminal.prefix) {
a31921ae
DI
485 // User-Defined Keys (DECUDK).
486 case '':
487 break;
488
489 // Request Status String (DECRQSS).
490 // test: echo -e '\eP$q"p\e\\'
491 case '$q':
d2b0d514 492 pt = this._terminal.currentParam;
13088f55 493 valid = false;
a31921ae
DI
494
495 switch (pt) {
496 // DECSCA
497 case '"q':
498 pt = '0"q';
499 break;
500
501 // DECSCL
502 case '"p':
503 pt = '61"p';
504 break;
505
506 // DECSTBM
507 case 'r':
508 pt = ''
4626e19b 509 + (this._terminal.buffer.scrollTop + 1)
a31921ae 510 + ';'
4626e19b 511 + (this._terminal.buffer.scrollBottom + 1)
a31921ae
DI
512 + 'r';
513 break;
514
515 // SGR
516 case 'm':
517 pt = '0m';
518 break;
519
520 default:
991b2843 521 this._terminal.error('Unknown DCS Pt: %s.', pt);
a31921ae
DI
522 pt = '';
523 break;
524 }
525
991b2843 526 this._terminal.send(C0.ESC + 'P' + +valid + '$r' + pt + C0.ESC + '\\');
a31921ae
DI
527 break;
528
529 // Set Termcap/Terminfo Data (xterm, experimental).
530 case '+p':
531 break;
532
533 // Request Termcap/Terminfo String (xterm, experimental)
534 // Regular xterm does not even respond to this sequence.
535 // This can cause a small glitch in vim.
536 // test: echo -ne '\eP+q6b64\e\\'
537 case '+q':
d2b0d514 538 pt = this._terminal.currentParam;
13088f55 539 valid = false;
a31921ae 540
991b2843 541 this._terminal.send(C0.ESC + 'P' + +valid + '+r' + pt + C0.ESC + '\\');
a31921ae
DI
542 break;
543
544 default:
991b2843 545 this._terminal.error('Unknown DCS prefix: %s.', this._terminal.prefix);
a31921ae
DI
546 break;
547 }
548
991b2843
DI
549 this._terminal.currentParam = 0;
550 this._terminal.prefix = '';
ecd7e69f 551 this._state = ParserState.NORMAL;
991b2843
DI
552 } else if (!this._terminal.currentParam) {
553 if (!this._terminal.prefix && ch !== '$' && ch !== '+') {
554 this._terminal.currentParam = ch;
555 } else if (this._terminal.prefix.length === 2) {
556 this._terminal.currentParam = ch;
a31921ae 557 } else {
991b2843 558 this._terminal.prefix += ch;
a31921ae
DI
559 }
560 } else {
991b2843 561 this._terminal.currentParam += ch;
a31921ae
DI
562 }
563 break;
564
565 case ParserState.IGNORE:
566 // For PM and APC.
567 if (ch === C0.ESC || ch === C0.BEL) {
ecd7e69f
DI
568 if (ch === C0.ESC) this._position++;
569 this._state = ParserState.NORMAL;
a31921ae
DI
570 }
571 break;
572 }
573 }
2c3d98ab 574 return this._state;
a31921ae 575 }
672dc1a2 576
ef60e50e
DI
577 /**
578 * Set the parser's current parsing state.
579 *
580 * @param state The new state.
581 */
fa3484cd 582 public setState(state: ParserState): void {
ecd7e69f 583 this._state = state;
fa3484cd
DI
584 }
585
ef60e50e
DI
586 /**
587 * Sets the parsier's current prefix. CSI codes can have prefixes of '?', '>'
588 * or '!'.
589 *
590 * @param prefix The prefix.
591 */
635a4d76 592 public setPrefix(prefix: string): void {
672dc1a2
DI
593 this._terminal.prefix = prefix;
594 }
595
ef60e50e
DI
596 /**
597 * Sets the parsier's current prefix. CSI codes can have postfixes of '$',
598 * '"', ' ', '\''.
599 *
600 * @param postfix The postfix.
601 */
602 public setPostfix(postfix: string): void {
603 this._terminal.postfix = postfix;
604 }
605
606 /**
607 * Sets the parser's current parameter.
608 *
609 * @param param the parameter.
610 */
672dc1a2
DI
611 public setParam(param: number) {
612 this._terminal.currentParam = param;
613 }
614
ef60e50e
DI
615 /**
616 * Gets the parser's current parameter.
617 */
672dc1a2
DI
618 public getParam(): number {
619 return this._terminal.currentParam;
620 }
635a4d76 621
ef60e50e
DI
622 /**
623 * Finalizes the parser's current parameter, adding it to the list of
624 * parameters and setting the new current parameter to 0.
625 */
c7fa2d55
DI
626 public finalizeParam(): void {
627 this._terminal.params.push(this._terminal.currentParam);
628 this._terminal.currentParam = 0;
629 }
630
ef60e50e
DI
631 /**
632 * Tell the parser to skip the next character.
633 */
ecd7e69f
DI
634 public skipNextChar(): void {
635 this._position++;
636 }
637
ef60e50e
DI
638 /**
639 * Tell the parser to repeat parsing the current character (for example if it
640 * needs parsing using a different state.
641 */
ecd7e69f
DI
642 // public repeatChar(): void {
643 // this._position--;
644 // }
a31921ae 645}