@@ -124,7 +124,8 @@ var normal = 0
124124 , osc = 3
125125 , charset = 4
126126 , dcs = 5
127- , ignore = 6 ;
127+ , ignore = 6
128+ , UDK = { type : 'udk' } ;
128129
129130/**
130131 * Terminal
@@ -1440,7 +1441,7 @@ Terminal.prototype.write = function(data) {
14401441
14411442 // this.log(JSON.stringify(data.replace(/\x1b/g, '^[')));
14421443
1443- for ( ; i < l ; i ++ ) {
1444+ for ( ; i < l ; i ++ , this . lch = ch ) {
14441445 ch = data [ i ] ;
14451446 switch ( this . state ) {
14461447 case normal :
@@ -1556,7 +1557,8 @@ Terminal.prototype.write = function(data) {
15561557 // ESC P Device Control String ( DCS is 0x90).
15571558 case 'P' :
15581559 this . params = [ ] ;
1559- this . currentParam = 0 ;
1560+ this . prefix = '' ;
1561+ this . currentParam = '' ;
15601562 this . state = dcs ;
15611563 break ;
15621564
@@ -1779,8 +1781,14 @@ Terminal.prototype.write = function(data) {
17791781 // OSC Ps ; Pt ST
17801782 // OSC Ps ; Pt BEL
17811783 // Set Text Parameters.
1782- if ( ch === '\x1b' || ch === '\x07' ) {
1783- if ( ch === '\x1b' ) i ++ ;
1784+ if ( ( this . lch === '\x1b' && ch === '\\' ) || ch === '\x07' ) {
1785+ if ( this . lch === '\x1b' ) {
1786+ if ( typeof this . currentParam === 'string' ) {
1787+ this . currentParam = this . currentParam . slice ( 0 , - 1 ) ;
1788+ } else if ( typeof this . currentParam == 'number' ) {
1789+ this . currentParam = ( this . currentParam - ( '\x1b' . charCodeAt ( 0 ) - 48 ) ) / 10 ;
1790+ }
1791+ }
17841792
17851793 this . params . push ( this . currentParam ) ;
17861794
@@ -2312,94 +2320,159 @@ Terminal.prototype.write = function(data) {
23122320 break ;
23132321
23142322 case dcs :
2315- if ( ch === '\x1b' || ch === '\x07' ) {
2316- if ( ch === '\x1b' ) i ++ ;
2323+ if ( ( this . lch === '\x1b' && ch === '\\' ) || ch === '\x07' ) {
2324+ // Workarounds:
2325+ if ( this . prefix === 'tmux;\x1b' ) {
2326+ // `DCS tmux; Pt ST` may contain a Pt with an ST
2327+ // XXX Does tmux work this way?
2328+ // if (this.lch === '\x1b' & data[i + 1] === '\x1b' && data[i + 2] === '\\') {
2329+ // this.currentParam += ch;
2330+ // continue;
2331+ // }
2332+ // Tmux only accepts ST, not BEL:
2333+ if ( ch === '\x07' ) {
2334+ this . currentParam += ch ;
2335+ continue ;
2336+ }
2337+ }
2338+
2339+ if ( this . lch === '\x1b' ) {
2340+ if ( typeof this . currentParam === 'string' ) {
2341+ this . currentParam = this . currentParam . slice ( 0 , - 1 ) ;
2342+ } else if ( typeof this . currentParam == 'number' ) {
2343+ this . currentParam = ( this . currentParam - ( '\x1b' . charCodeAt ( 0 ) - 48 ) ) / 10 ;
2344+ }
2345+ }
2346+
2347+ this . params . push ( this . currentParam ) ;
2348+ this . currentParam = '' ;
2349+
2350+ var pt = this . params [ this . params . length - 1 ] ;
23172351
23182352 switch ( this . prefix ) {
23192353 // User-Defined Keys (DECUDK).
2320- case '' :
2354+ // DCS Ps; Ps| Pt ST
2355+ case UDK :
2356+ this . emit ( 'udk' , {
2357+ clearAll : this . params [ 0 ] === 0 ,
2358+ eraseBelow : this . params [ 0 ] === 1 ,
2359+ lockKeys : this . params [ 1 ] === 0 ,
2360+ dontLockKeys : this . params [ 1 ] === 1 ,
2361+ keyList : ( this . params [ 2 ] + '' ) . split ( ';' ) . map ( function ( part ) {
2362+ part = part . split ( '/' ) ;
2363+ return {
2364+ keyCode : part [ 0 ] ,
2365+ hexKeyValue : part [ 1 ]
2366+ } ;
2367+ } )
2368+ } ) ;
23212369 break ;
23222370
23232371 // Request Status String (DECRQSS).
2372+ // DCS $ q Pt ST
23242373 // test: echo -e '\eP$q"p\e\\'
23252374 case '$q' :
2326- var pt = this . currentParam
2327- , valid = false ;
2375+ var valid = 0 ;
23282376
23292377 switch ( pt ) {
23302378 // DECSCA
2379+ // CSI Ps " q
23312380 case '"q' :
23322381 pt = '0"q' ;
2382+ valid = 1 ;
23332383 break ;
23342384
23352385 // DECSCL
2386+ // CSI Ps ; Ps " p
23362387 case '"p' :
2337- pt = '61"p' ;
2388+ pt = '61;0"p' ;
2389+ valid = 1 ;
23382390 break ;
23392391
23402392 // DECSTBM
2393+ // CSI Ps ; Ps r
23412394 case 'r' :
23422395 pt = ''
23432396 + ( this . scrollTop + 1 )
23442397 + ';'
23452398 + ( this . scrollBottom + 1 )
23462399 + 'r' ;
2400+ valid = 1 ;
23472401 break ;
23482402
23492403 // SGR
2404+ // CSI Pm m
23502405 case 'm' :
2351- pt = '0m' ;
2406+ // TODO: Parse this.curAttr here.
2407+ // pt = '0m';
2408+ // valid = 1;
2409+ valid = 0 ; // Not implemented.
23522410 break ;
23532411
23542412 default :
23552413 this . error ( 'Unknown DCS Pt: %s.' , pt ) ;
2356- pt = '' ;
2414+ valid = 0 ; // unimplemented
23572415 break ;
23582416 }
23592417
2360- this . send ( '\x1bP' + + valid + '$r' + pt + '\x1b\\' ) ;
2418+ this . send ( '\x1bP' + valid + '$r' + pt + '\x1b\\' ) ;
23612419 break ;
23622420
23632421 // Set Termcap/Terminfo Data (xterm, experimental).
2422+ // DCS + p Pt ST
23642423 case '+p' :
2424+ this . emit ( 'set terminfo' , {
2425+ name : this . params [ 0 ]
2426+ } ) ;
23652427 break ;
23662428
23672429 // Request Termcap/Terminfo String (xterm, experimental)
23682430 // Regular xterm does not even respond to this sequence.
23692431 // This can cause a small glitch in vim.
2432+ // DCS + q Pt ST
23702433 // test: echo -ne '\eP+q6b64\e\\'
23712434 case '+q' :
2372- var pt = this . currentParam
2373- , valid = false ;
2374-
2435+ var valid = false ;
23752436 this . send ( '\x1bP' + + valid + '+r' + pt + '\x1b\\' ) ;
23762437 break ;
23772438
2439+ // Implement tmux sequence forwarding is
2440+ // someone uses term.js for a multiplexer.
2441+ // DCS tmux; ESC Pt ST
2442+ case 'tmux;\x1b' :
2443+ this . emit ( 'passthrough' , pt ) ;
2444+ break ;
2445+
23782446 default :
2379- this . error ( 'Unknown DCS prefix: %s.' , this . prefix ) ;
2447+ this . error ( 'Unknown DCS prefix: %s.' , pt ) ;
23802448 break ;
23812449 }
23822450
2383- this . currentParam = 0 ;
2451+ this . currentParam = '' ;
23842452 this . prefix = '' ;
23852453 this . state = normal ;
2386- } else if ( ! this . currentParam ) {
2387- if ( ! this . prefix && ch !== '$' && ch !== '+' ) {
2388- this . currentParam = ch ;
2389- } else if ( this . prefix . length === 2 ) {
2390- this . currentParam = ch ;
2391- } else {
2392- this . prefix += ch ;
2393- }
23942454 } else {
23952455 this . currentParam += ch ;
2456+ if ( ! this . prefix ) {
2457+ if ( / ^ \d * ; \d * \| / . test ( this . currentParam ) ) {
2458+ this . prefix = UDK ;
2459+ this . params = this . currentParam . split ( / [ ; | ] / ) . map ( function ( n ) {
2460+ if ( ! n . length ) return 0 ;
2461+ return + n ;
2462+ } ) . slice ( 0 , - 1 ) ;
2463+ this . currentParam = '' ;
2464+ } else if ( / ^ [ $ + ] [ a - z A - Z ] / . test ( this . currentParam )
2465+ || / ^ \w + ; \x1b / . test ( this . currentParam ) ) {
2466+ this . prefix = this . currentParam ;
2467+ this . currentParam = '' ;
2468+ }
2469+ }
23962470 }
23972471 break ;
23982472
23992473 case ignore :
24002474 // For PM and APC.
2401- if ( ch === '\x1b' || ch === '\x07' ) {
2402- if ( ch === '\x1b' ) i ++ ;
2475+ if ( ( this . lch === '\x1b' && ch === '\\' ) || ch === '\x07' ) {
24032476 this . state = normal ;
24042477 }
24052478 break ;
0 commit comments