]> git.proxmox.com Git - mirror_xterm.js.git/blame - src/Parser.ts
Move parsing logic into Parser.ts
[mirror_xterm.js.git] / src / Parser.ts
CommitLineData
659fb90c
DI
1import { C0 } from './EscapeSequences';
2import { IInputHandler } from './Interfaces';
3
a31921ae 4const normalStateHandler: {[key: string]: (handler: IInputHandler) => void} = {};
659fb90c
DI
5normalStateHandler[C0.BEL] = (handler) => handler.bell();
6normalStateHandler[C0.LF] = (handler) => handler.lineFeed();
7normalStateHandler[C0.VT] = normalStateHandler[C0.LF];
8normalStateHandler[C0.FF] = normalStateHandler[C0.LF];
9normalStateHandler[C0.CR] = (handler) => handler.carriageReturn();
665a11ac 10normalStateHandler[C0.BS] = (handler) => handler.backspace();
659fb90c
DI
11normalStateHandler[C0.HT] = (handler) => handler.tab();
12normalStateHandler[C0.SO] = (handler) => handler.shiftOut();
13normalStateHandler[C0.SI] = (handler) => handler.shiftIn();
a31921ae
DI
14
15enum ParserState {
16 NORMAL = 0,
17 ESCAPED = 1,
18 CSI = 2,
19 OSC = 3,
20 CHARSET = 4,
21 DCS = 5,
22 IGNORE = 6
23}
24
25export class Parser {
26 private state: ParserState;
27
28 // TODO: Remove terminal when handler can do everything
29 constructor(
30 private _inputHandler: IInputHandler,
31 private _terminal: any
32 ) {
33 this.state = ParserState.NORMAL;
34 }
35
36 public parse(data: string) {
37 let l = data.length, i = 0, j, cs, ch, code, low, ch_width, row;
38
39 // apply leftover surrogate high from last write
40 if (this._terminal.surrogate_high) {
41 data = this._terminal.surrogate_high + data;
42 this._terminal.surrogate_high = '';
43 }
44
45 for (; i < l; i++) {
46 ch = data[i];
47
48 // FIXME: higher chars than 0xa0 are not allowed in escape sequences
49 // --> maybe move to default
50 code = data.charCodeAt(i);
51 if (0xD800 <= code && code <= 0xDBFF) {
52 // we got a surrogate high
53 // get surrogate low (next 2 bytes)
54 low = data.charCodeAt(i+1);
55 if (isNaN(low)) {
56 // end of data stream, save surrogate high
57 this._terminal.surrogate_high = ch;
58 continue;
59 }
60 code = ((code - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000;
61 ch += data.charAt(i+1);
62 }
63 // surrogate low - already handled above
64 if (0xDC00 <= code && code <= 0xDFFF)
65 continue;
66
67 if (this.state === ParserState.NORMAL) {
68 if (ch in normalStateHandler) {
69 normalStateHandler[ch](this._inputHandler);
70 // Skip switch statement (eventually everything will be handled this way
71 continue;
72 }
73 }
74
75 switch (this.state) {
76 case ParserState.NORMAL:
77 switch (ch) {
78 case C0.ESC:
79 this.state = ParserState.ESCAPED;
80 break;
81
82 default:
83 // ' '
84 // calculate print space
85 // expensive call, therefore we save width in line buffer
86 ch_width = wcwidth(code);
87
88 if (ch >= ' ') {
89 if (this.charset && this.charset[ch]) {
90 ch = this.charset[ch];
91 }
92
93 row = this.y + this.ybase;
94
95 // insert combining char in last cell
96 // FIXME: needs handling after cursor jumps
97 if (!ch_width && this.x) {
98 // dont overflow left
99 if (this.lines.get(row)[this.x-1]) {
100 if (!this.lines.get(row)[this.x-1][2]) {
101
102 // found empty cell after fullwidth, need to go 2 cells back
103 if (this.lines.get(row)[this.x-2])
104 this.lines.get(row)[this.x-2][1] += ch;
105
106 } else {
107 this.lines.get(row)[this.x-1][1] += ch;
108 }
109 this.updateRange(this.y);
110 }
111 break;
112 }
113
114 // goto next line if ch would overflow
115 // TODO: needs a global min terminal width of 2
116 if (this.x+ch_width-1 >= this.cols) {
117 // autowrap - DECAWM
118 if (this.wraparoundMode) {
119 this.x = 0;
120 this.y++;
121 if (this.y > this.scrollBottom) {
122 this.y--;
123 this.scroll();
124 }
125 } else {
126 this.x = this.cols-1;
127 if(ch_width===2) // FIXME: check for xterm behavior
128 continue;
129 }
130 }
131 row = this.y + this.ybase;
132
133 // insert mode: move characters to right
134 if (this.insertMode) {
135 // do this twice for a fullwidth char
136 for (var moves=0; moves<ch_width; ++moves) {
137 // remove last cell, if it's width is 0
138 // we have to adjust the second last cell as well
139 var removed = this.lines.get(this.y + this.ybase).pop();
140 if (removed[2]===0
141 && this.lines.get(row)[this.cols-2]
142 && this.lines.get(row)[this.cols-2][2]===2)
143 this.lines.get(row)[this.cols-2] = [this.curAttr, ' ', 1];
144
145 // insert empty cell at cursor
146 this.lines.get(row).splice(this.x, 0, [this.curAttr, ' ', 1]);
147 }
148 }
149
150 this.lines.get(row)[this.x] = [this.curAttr, ch, ch_width];
151 this.x++;
152 this.updateRange(this.y);
153
154 // fullwidth char - set next cell width to zero and advance cursor
155 if (ch_width===2) {
156 this.lines.get(row)[this.x] = [this.curAttr, '', 0];
157 this.x++;
158 }
159 }
160 break;
161 }
162 break;
163 case ParserState.ESCAPED:
164 switch (ch) {
165 // ESC [ Control Sequence Introducer ( CSI is 0x9b).
166 case '[':
167 this.params = [];
168 this.currentParam = 0;
169 this.state = csi;
170 break;
171
172 // ESC ] Operating System Command ( OSC is 0x9d).
173 case ']':
174 this.params = [];
175 this.currentParam = 0;
176 this.state = osc;
177 break;
178
179 // ESC P Device Control String ( DCS is 0x90).
180 case 'P':
181 this.params = [];
182 this.currentParam = 0;
183 this.state = dcs;
184 break;
185
186 // ESC _ Application Program Command ( APC is 0x9f).
187 case '_':
188 this.state = ParserState.IGNORE;
189 break;
190
191 // ESC ^ Privacy Message ( PM is 0x9e).
192 case '^':
193 this.state = ParserState.IGNORE;
194 break;
195
196 // ESC c Full Reset (RIS).
197 case 'c':
198 this.reset();
199 break;
200
201 // ESC E Next Line ( NEL is 0x85).
202 // ESC D Index ( IND is 0x84).
203 case 'E':
204 this.x = 0;
205 ;
206 case 'D':
207 this.index();
208 break;
209
210 // ESC M Reverse Index ( RI is 0x8d).
211 case 'M':
212 this.reverseIndex();
213 break;
214
215 // ESC % Select default/utf-8 character set.
216 // @ = default, G = utf-8
217 case '%':
218 //this.charset = null;
219 this.setgLevel(0);
220 this.setgCharset(0, Terminal.charsets.US);
221 this.state = ParserState.NORMAL;
222 i++;
223 break;
224
225 // ESC (,),*,+,-,. Designate G0-G2 Character Set.
226 case '(': // <-- this seems to get all the attention
227 case ')':
228 case '*':
229 case '+':
230 case '-':
231 case '.':
232 switch (ch) {
233 case '(':
234 this.gcharset = 0;
235 break;
236 case ')':
237 this.gcharset = 1;
238 break;
239 case '*':
240 this.gcharset = 2;
241 break;
242 case '+':
243 this.gcharset = 3;
244 break;
245 case '-':
246 this.gcharset = 1;
247 break;
248 case '.':
249 this.gcharset = 2;
250 break;
251 }
252 this.state = charset;
253 break;
254
255 // Designate G3 Character Set (VT300).
256 // A = ISO Latin-1 Supplemental.
257 // Not implemented.
258 case '/':
259 this.gcharset = 3;
260 this.state = ParserState.CHARSET;
261 i--;
262 break;
263
264 // ESC N
265 // Single Shift Select of G2 Character Set
266 // ( SS2 is 0x8e). This affects next character only.
267 case 'N':
268 break;
269 // ESC O
270 // Single Shift Select of G3 Character Set
271 // ( SS3 is 0x8f). This affects next character only.
272 case 'O':
273 break;
274 // ESC n
275 // Invoke the G2 Character Set as GL (LS2).
276 case 'n':
277 this.setgLevel(2);
278 break;
279 // ESC o
280 // Invoke the G3 Character Set as GL (LS3).
281 case 'o':
282 this.setgLevel(3);
283 break;
284 // ESC |
285 // Invoke the G3 Character Set as GR (LS3R).
286 case '|':
287 this.setgLevel(3);
288 break;
289 // ESC }
290 // Invoke the G2 Character Set as GR (LS2R).
291 case '}':
292 this.setgLevel(2);
293 break;
294 // ESC ~
295 // Invoke the G1 Character Set as GR (LS1R).
296 case '~':
297 this.setgLevel(1);
298 break;
299
300 // ESC 7 Save Cursor (DECSC).
301 case '7':
302 this.saveCursor();
303 this.state = ParserState.NORMAL;
304 break;
305
306 // ESC 8 Restore Cursor (DECRC).
307 case '8':
308 this.restoreCursor();
309 this.state = ParserState.NORMAL;
310 break;
311
312 // ESC # 3 DEC line height/width
313 case '#':
314 this.state = ParserState.NORMAL;
315 i++;
316 break;
317
318 // ESC H Tab Set (HTS is 0x88).
319 case 'H':
320 this.tabSet();
321 break;
322
323 // ESC = Application Keypad (DECKPAM).
324 case '=':
325 this.log('Serial port requested application keypad.');
326 this.applicationKeypad = true;
327 this.viewport.syncScrollArea();
328 this.state = ParserState.NORMAL;
329 break;
330
331 // ESC > Normal Keypad (DECKPNM).
332 case '>':
333 this.log('Switching back to normal keypad.');
334 this.applicationKeypad = false;
335 this.viewport.syncScrollArea();
336 this.state = ParserState.NORMAL;
337 break;
338
339 default:
340 this.state = ParserState.NORMAL;
341 this.error('Unknown ESC control: %s.', ch);
342 break;
343 }
344 break;
345
346 case ParserState.CHARSET:
347 switch (ch) {
348 case '0': // DEC Special Character and Line Drawing Set.
349 cs = Terminal.charsets.SCLD;
350 break;
351 case 'A': // UK
352 cs = Terminal.charsets.UK;
353 break;
354 case 'B': // United States (USASCII).
355 cs = Terminal.charsets.US;
356 break;
357 case '4': // Dutch
358 cs = Terminal.charsets.Dutch;
359 break;
360 case 'C': // Finnish
361 case '5':
362 cs = Terminal.charsets.Finnish;
363 break;
364 case 'R': // French
365 cs = Terminal.charsets.French;
366 break;
367 case 'Q': // FrenchCanadian
368 cs = Terminal.charsets.FrenchCanadian;
369 break;
370 case 'K': // German
371 cs = Terminal.charsets.German;
372 break;
373 case 'Y': // Italian
374 cs = Terminal.charsets.Italian;
375 break;
376 case 'E': // NorwegianDanish
377 case '6':
378 cs = Terminal.charsets.NorwegianDanish;
379 break;
380 case 'Z': // Spanish
381 cs = Terminal.charsets.Spanish;
382 break;
383 case 'H': // Swedish
384 case '7':
385 cs = Terminal.charsets.Swedish;
386 break;
387 case '=': // Swiss
388 cs = Terminal.charsets.Swiss;
389 break;
390 case '/': // ISOLatin (actually /A)
391 cs = Terminal.charsets.ISOLatin;
392 i++;
393 break;
394 default: // Default
395 cs = Terminal.charsets.US;
396 break;
397 }
398 this.setgCharset(this.gcharset, cs);
399 this.gcharset = null;
400 this.state = ParserState.NORMAL;
401 break;
402
403 case ParserState.OSC:
404 // OSC Ps ; Pt ST
405 // OSC Ps ; Pt BEL
406 // Set Text Parameters.
407 if (ch === C0.ESC || ch === C0.BEL) {
408 if (ch === C0.ESC) i++;
409
410 this.params.push(this.currentParam);
411
412 switch (this.params[0]) {
413 case 0:
414 case 1:
415 case 2:
416 if (this.params[1]) {
417 this.title = this.params[1];
418 this.handleTitle(this.title);
419 }
420 break;
421 case 3:
422 // set X property
423 break;
424 case 4:
425 case 5:
426 // change dynamic colors
427 break;
428 case 10:
429 case 11:
430 case 12:
431 case 13:
432 case 14:
433 case 15:
434 case 16:
435 case 17:
436 case 18:
437 case 19:
438 // change dynamic ui colors
439 break;
440 case 46:
441 // change log file
442 break;
443 case 50:
444 // dynamic font
445 break;
446 case 51:
447 // emacs shell
448 break;
449 case 52:
450 // manipulate selection data
451 break;
452 case 104:
453 case 105:
454 case 110:
455 case 111:
456 case 112:
457 case 113:
458 case 114:
459 case 115:
460 case 116:
461 case 117:
462 case 118:
463 // reset colors
464 break;
465 }
466
467 this.params = [];
468 this.currentParam = 0;
469 this.state = ParserState.NORMAL;
470 } else {
471 if (!this.params.length) {
472 if (ch >= '0' && ch <= '9') {
473 this.currentParam =
474 this.currentParam * 10 + ch.charCodeAt(0) - 48;
475 } else if (ch === ';') {
476 this.params.push(this.currentParam);
477 this.currentParam = '';
478 }
479 } else {
480 this.currentParam += ch;
481 }
482 }
483 break;
484
485 case csi:
486 // '?', '>', '!'
487 if (ch === '?' || ch === '>' || ch === '!') {
488 this.prefix = ch;
489 break;
490 }
491
492 // 0 - 9
493 if (ch >= '0' && ch <= '9') {
494 this.currentParam = this.currentParam * 10 + ch.charCodeAt(0) - 48;
495 break;
496 }
497
498 // '$', '"', ' ', '\''
499 if (ch === '$' || ch === '"' || ch === ' ' || ch === '\'') {
500 this.postfix = ch;
501 break;
502 }
503
504 this.params.push(this.currentParam);
505 this.currentParam = 0;
506
507 // ';'
508 if (ch === ';') break;
509
510 this.state = ParserState.NORMAL;
511
512 switch (ch) {
513 // CSI Ps A
514 // Cursor Up Ps Times (default = 1) (CUU).
515 case 'A':
516 this.cursorUp(this.params);
517 break;
518
519 // CSI Ps B
520 // Cursor Down Ps Times (default = 1) (CUD).
521 case 'B':
522 this.cursorDown(this.params);
523 break;
524
525 // CSI Ps C
526 // Cursor Forward Ps Times (default = 1) (CUF).
527 case 'C':
528 this.cursorForward(this.params);
529 break;
530
531 // CSI Ps D
532 // Cursor Backward Ps Times (default = 1) (CUB).
533 case 'D':
534 this.cursorBackward(this.params);
535 break;
536
537 // CSI Ps ; Ps H
538 // Cursor Position [row;column] (default = [1,1]) (CUP).
539 case 'H':
540 this.cursorPos(this.params);
541 break;
542
543 // CSI Ps J Erase in Display (ED).
544 case 'J':
545 this.eraseInDisplay(this.params);
546 break;
547
548 // CSI Ps K Erase in Line (EL).
549 case 'K':
550 this.eraseInLine(this.params);
551 break;
552
553 // CSI Pm m Character Attributes (SGR).
554 case 'm':
555 if (!this.prefix) {
556 this.charAttributes(this.params);
557 }
558 break;
559
560 // CSI Ps n Device Status Report (DSR).
561 case 'n':
562 if (!this.prefix) {
563 this.deviceStatus(this.params);
564 }
565 break;
566
567 /**
568 * Additions
569 */
570
571 // CSI Ps @
572 // Insert Ps (Blank) Character(s) (default = 1) (ICH).
573 case '@':
574 this.insertChars(this.params);
575 break;
576
577 // CSI Ps E
578 // Cursor Next Line Ps Times (default = 1) (CNL).
579 case 'E':
580 this.cursorNextLine(this.params);
581 break;
582
583 // CSI Ps F
584 // Cursor Preceding Line Ps Times (default = 1) (CNL).
585 case 'F':
586 this.cursorPrecedingLine(this.params);
587 break;
588
589 // CSI Ps G
590 // Cursor Character Absolute [column] (default = [row,1]) (CHA).
591 case 'G':
592 this.cursorCharAbsolute(this.params);
593 break;
594
595 // CSI Ps L
596 // Insert Ps Line(s) (default = 1) (IL).
597 case 'L':
598 this.insertLines(this.params);
599 break;
600
601 // CSI Ps M
602 // Delete Ps Line(s) (default = 1) (DL).
603 case 'M':
604 this.deleteLines(this.params);
605 break;
606
607 // CSI Ps P
608 // Delete Ps Character(s) (default = 1) (DCH).
609 case 'P':
610 this.deleteChars(this.params);
611 break;
612
613 // CSI Ps X
614 // Erase Ps Character(s) (default = 1) (ECH).
615 case 'X':
616 this.eraseChars(this.params);
617 break;
618
619 // CSI Pm ` Character Position Absolute
620 // [column] (default = [row,1]) (HPA).
621 case '`':
622 this.charPosAbsolute(this.params);
623 break;
624
625 // 141 61 a * HPR -
626 // Horizontal Position Relative
627 case 'a':
628 this.HPositionRelative(this.params);
629 break;
630
631 // CSI P s c
632 // Send Device Attributes (Primary DA).
633 // CSI > P s c
634 // Send Device Attributes (Secondary DA)
635 case 'c':
636 this.sendDeviceAttributes(this.params);
637 break;
638
639 // CSI Pm d
640 // Line Position Absolute [row] (default = [1,column]) (VPA).
641 case 'd':
642 this.linePosAbsolute(this.params);
643 break;
644
645 // 145 65 e * VPR - Vertical Position Relative
646 case 'e':
647 this.VPositionRelative(this.params);
648 break;
649
650 // CSI Ps ; Ps f
651 // Horizontal and Vertical Position [row;column] (default =
652 // [1,1]) (HVP).
653 case 'f':
654 this.HVPosition(this.params);
655 break;
656
657 // CSI Pm h Set Mode (SM).
658 // CSI ? Pm h - mouse escape codes, cursor escape codes
659 case 'h':
660 this.setMode(this.params);
661 break;
662
663 // CSI Pm l Reset Mode (RM).
664 // CSI ? Pm l
665 case 'l':
666 this.resetMode(this.params);
667 break;
668
669 // CSI Ps ; Ps r
670 // Set Scrolling Region [top;bottom] (default = full size of win-
671 // dow) (DECSTBM).
672 // CSI ? Pm r
673 case 'r':
674 this.setScrollRegion(this.params);
675 break;
676
677 // CSI s
678 // Save cursor (ANSI.SYS).
679 case 's':
680 this.saveCursor(this.params);
681 break;
682
683 // CSI u
684 // Restore cursor (ANSI.SYS).
685 case 'u':
686 this.restoreCursor(this.params);
687 break;
688
689 /**
690 * Lesser Used
691 */
692
693 // CSI Ps I
694 // Cursor Forward Tabulation Ps tab stops (default = 1) (CHT).
695 case 'I':
696 this.cursorForwardTab(this.params);
697 break;
698
699 // CSI Ps S Scroll up Ps lines (default = 1) (SU).
700 case 'S':
701 this.scrollUp(this.params);
702 break;
703
704 // CSI Ps T Scroll down Ps lines (default = 1) (SD).
705 // CSI Ps ; Ps ; Ps ; Ps ; Ps T
706 // CSI > Ps; Ps T
707 case 'T':
708 // if (this.prefix === '>') {
709 // this.resetTitleModes(this.params);
710 // break;
711 // }
712 // if (this.params.length > 2) {
713 // this.initMouseTracking(this.params);
714 // break;
715 // }
716 if (this.params.length < 2 && !this.prefix) {
717 this.scrollDown(this.params);
718 }
719 break;
720
721 // CSI Ps Z
722 // Cursor Backward Tabulation Ps tab stops (default = 1) (CBT).
723 case 'Z':
724 this.cursorBackwardTab(this.params);
725 break;
726
727 // CSI Ps b Repeat the preceding graphic character Ps times (REP).
728 case 'b':
729 this.repeatPrecedingCharacter(this.params);
730 break;
731
732 // CSI Ps g Tab Clear (TBC).
733 case 'g':
734 this.tabClear(this.params);
735 break;
736
737 // CSI Pm i Media Copy (MC).
738 // CSI ? Pm i
739 // case 'i':
740 // this.mediaCopy(this.params);
741 // break;
742
743 // CSI Pm m Character Attributes (SGR).
744 // CSI > Ps; Ps m
745 // case 'm': // duplicate
746 // if (this.prefix === '>') {
747 // this.setResources(this.params);
748 // } else {
749 // this.charAttributes(this.params);
750 // }
751 // break;
752
753 // CSI Ps n Device Status Report (DSR).
754 // CSI > Ps n
755 // case 'n': // duplicate
756 // if (this.prefix === '>') {
757 // this.disableModifiers(this.params);
758 // } else {
759 // this.deviceStatus(this.params);
760 // }
761 // break;
762
763 // CSI > Ps p Set pointer mode.
764 // CSI ! p Soft terminal reset (DECSTR).
765 // CSI Ps$ p
766 // Request ANSI mode (DECRQM).
767 // CSI ? Ps$ p
768 // Request DEC private mode (DECRQM).
769 // CSI Ps ; Ps " p
770 case 'p':
771 switch (this.prefix) {
772 // case '>':
773 // this.setPointerMode(this.params);
774 // break;
775 case '!':
776 this.softReset(this.params);
777 break;
778 // case '?':
779 // if (this.postfix === '$') {
780 // this.requestPrivateMode(this.params);
781 // }
782 // break;
783 // default:
784 // if (this.postfix === '"') {
785 // this.setConformanceLevel(this.params);
786 // } else if (this.postfix === '$') {
787 // this.requestAnsiMode(this.params);
788 // }
789 // break;
790 }
791 break;
792
793 // CSI Ps q Load LEDs (DECLL).
794 // CSI Ps SP q
795 // CSI Ps " q
796 // case 'q':
797 // if (this.postfix === ' ') {
798 // this.setCursorStyle(this.params);
799 // break;
800 // }
801 // if (this.postfix === '"') {
802 // this.setCharProtectionAttr(this.params);
803 // break;
804 // }
805 // this.loadLEDs(this.params);
806 // break;
807
808 // CSI Ps ; Ps r
809 // Set Scrolling Region [top;bottom] (default = full size of win-
810 // dow) (DECSTBM).
811 // CSI ? Pm r
812 // CSI Pt; Pl; Pb; Pr; Ps$ r
813 // case 'r': // duplicate
814 // if (this.prefix === '?') {
815 // this.restorePrivateValues(this.params);
816 // } else if (this.postfix === '$') {
817 // this.setAttrInRectangle(this.params);
818 // } else {
819 // this.setScrollRegion(this.params);
820 // }
821 // break;
822
823 // CSI s Save cursor (ANSI.SYS).
824 // CSI ? Pm s
825 // case 's': // duplicate
826 // if (this.prefix === '?') {
827 // this.savePrivateValues(this.params);
828 // } else {
829 // this.saveCursor(this.params);
830 // }
831 // break;
832
833 // CSI Ps ; Ps ; Ps t
834 // CSI Pt; Pl; Pb; Pr; Ps$ t
835 // CSI > Ps; Ps t
836 // CSI Ps SP t
837 // case 't':
838 // if (this.postfix === '$') {
839 // this.reverseAttrInRectangle(this.params);
840 // } else if (this.postfix === ' ') {
841 // this.setWarningBellVolume(this.params);
842 // } else {
843 // if (this.prefix === '>') {
844 // this.setTitleModeFeature(this.params);
845 // } else {
846 // this.manipulateWindow(this.params);
847 // }
848 // }
849 // break;
850
851 // CSI u Restore cursor (ANSI.SYS).
852 // CSI Ps SP u
853 // case 'u': // duplicate
854 // if (this.postfix === ' ') {
855 // this.setMarginBellVolume(this.params);
856 // } else {
857 // this.restoreCursor(this.params);
858 // }
859 // break;
860
861 // CSI Pt; Pl; Pb; Pr; Pp; Pt; Pl; Pp$ v
862 // case 'v':
863 // if (this.postfix === '$') {
864 // this.copyRectagle(this.params);
865 // }
866 // break;
867
868 // CSI Pt ; Pl ; Pb ; Pr ' w
869 // case 'w':
870 // if (this.postfix === '\'') {
871 // this.enableFilterRectangle(this.params);
872 // }
873 // break;
874
875 // CSI Ps x Request Terminal Parameters (DECREQTPARM).
876 // CSI Ps x Select Attribute Change Extent (DECSACE).
877 // CSI Pc; Pt; Pl; Pb; Pr$ x
878 // case 'x':
879 // if (this.postfix === '$') {
880 // this.fillRectangle(this.params);
881 // } else {
882 // this.requestParameters(this.params);
883 // //this.__(this.params);
884 // }
885 // break;
886
887 // CSI Ps ; Pu ' z
888 // CSI Pt; Pl; Pb; Pr$ z
889 // case 'z':
890 // if (this.postfix === '\'') {
891 // this.enableLocatorReporting(this.params);
892 // } else if (this.postfix === '$') {
893 // this.eraseRectangle(this.params);
894 // }
895 // break;
896
897 // CSI Pm ' {
898 // CSI Pt; Pl; Pb; Pr$ {
899 // case '{':
900 // if (this.postfix === '\'') {
901 // this.setLocatorEvents(this.params);
902 // } else if (this.postfix === '$') {
903 // this.selectiveEraseRectangle(this.params);
904 // }
905 // break;
906
907 // CSI Ps ' |
908 // case '|':
909 // if (this.postfix === '\'') {
910 // this.requestLocatorPosition(this.params);
911 // }
912 // break;
913
914 // CSI P m SP }
915 // Insert P s Column(s) (default = 1) (DECIC), VT420 and up.
916 // case '}':
917 // if (this.postfix === ' ') {
918 // this.insertColumns(this.params);
919 // }
920 // break;
921
922 // CSI P m SP ~
923 // Delete P s Column(s) (default = 1) (DECDC), VT420 and up
924 // case '~':
925 // if (this.postfix === ' ') {
926 // this.deleteColumns(this.params);
927 // }
928 // break;
929
930 default:
931 this.error('Unknown CSI code: %s.', ch);
932 break;
933 }
934
935 this.prefix = '';
936 this.postfix = '';
937 break;
938
939 case ParserState.DCS:
940 if (ch === C0.ESC || ch === C0.BEL) {
941 if (ch === C0.ESC) i++;
942
943 switch (this.prefix) {
944 // User-Defined Keys (DECUDK).
945 case '':
946 break;
947
948 // Request Status String (DECRQSS).
949 // test: echo -e '\eP$q"p\e\\'
950 case '$q':
951 var pt = this.currentParam
952 , valid = false;
953
954 switch (pt) {
955 // DECSCA
956 case '"q':
957 pt = '0"q';
958 break;
959
960 // DECSCL
961 case '"p':
962 pt = '61"p';
963 break;
964
965 // DECSTBM
966 case 'r':
967 pt = ''
968 + (this.scrollTop + 1)
969 + ';'
970 + (this.scrollBottom + 1)
971 + 'r';
972 break;
973
974 // SGR
975 case 'm':
976 pt = '0m';
977 break;
978
979 default:
980 this.error('Unknown DCS Pt: %s.', pt);
981 pt = '';
982 break;
983 }
984
985 this.send(C0.ESC + 'P' + +valid + '$r' + pt + C0.ESC + '\\');
986 break;
987
988 // Set Termcap/Terminfo Data (xterm, experimental).
989 case '+p':
990 break;
991
992 // Request Termcap/Terminfo String (xterm, experimental)
993 // Regular xterm does not even respond to this sequence.
994 // This can cause a small glitch in vim.
995 // test: echo -ne '\eP+q6b64\e\\'
996 case '+q':
997 var pt = this.currentParam
998 , valid = false;
999
1000 this.send(C0.ESC + 'P' + +valid + '+r' + pt + C0.ESC + '\\');
1001 break;
1002
1003 default:
1004 this.error('Unknown DCS prefix: %s.', this.prefix);
1005 break;
1006 }
1007
1008 this.currentParam = 0;
1009 this.prefix = '';
1010 this.state = ParserState.NORMAL;
1011 } else if (!this.currentParam) {
1012 if (!this.prefix && ch !== '$' && ch !== '+') {
1013 this.currentParam = ch;
1014 } else if (this.prefix.length === 2) {
1015 this.currentParam = ch;
1016 } else {
1017 this.prefix += ch;
1018 }
1019 } else {
1020 this.currentParam += ch;
1021 }
1022 break;
1023
1024 case ParserState.IGNORE:
1025 // For PM and APC.
1026 if (ch === C0.ESC || ch === C0.BEL) {
1027 if (ch === C0.ESC) i++;
1028 this.state = ParserState.NORMAL;
1029 }
1030 break;
1031 }
1032 }
1033 }
1034}