license import { deepStrictEqual , strictEqual , throws } from 'assert' ; import { Terminal } from 'headless/public/Terminal' ; import { ITerminalOptions } from 'xterm-headless' ; let term ; describe ( 'Headless API Tests' , function ( ) : void { beforeEach ( ( ) => { term = new Terminal ( ) ; } ) ; it ( 'Default options' , async ( ) => { strictEqual ( term . cols , 80 ) ; strictEqual ( term . rows , 24 ) ; } ) ; it ( 'Proposed API check' , async ( ) => { term = new Terminal ( { allowProposedApi : false } ) ; throws ( ( ) => term . buffer , ( error ) => error . message === 'You must set the allowProposedApi option to true to use proposed API' ) ; } ) ; it ( 'write' , async ( ) => { await writeSync ( 'foo' ) ; await writeSync ( 'bar' ) ; await writeSync ( '文' ) ; lineEquals ( 0 , 'foobar文' ) ; } ) ; it ( 'write with callback' , async ( ) => { let result ; await new Promise < void > ( r => { term . write ( 'foo' , ( ) => { result = 'a' ; } ) ; term . write ( 'bar' , ( ) => { result += 'b' ; } ) ; term . write ( '文' , ( ) => { result += 'c' ; r ( ) ; } ) ; } ) ; lineEquals ( 0 , 'foobar文' ) ; strictEqual ( result , 'abc' ) ; } ) ; it ( 'write - bytes (UTF8)' , async ( ) => { await writeSync ( new Uint8Array ( [ 102 , 111 , 111 ] ) ) ; await writeSync ( new Uint8Array ( [ 98 , 97 , 114 ] ) ) ; await writeSync ( new Uint8Array ( [ 230 , 150 , 135 ] ) ) ; lineEquals ( 0 , 'foobar文' ) ; } ) ; it ( 'write - bytes (UTF8) with callback' , async ( ) => { let result ; await new Promise < void > ( r => { term . write ( new Uint8Array ( [ 102 , 111 , 111 ] ) , ( ) => { result = 'A' ; } ) ; term . write ( new Uint8Array ( [ 98 , 97 , 114 ] ) , ( ) => { result += 'B' ; } ) ; term . write ( new Uint8Array ( [ 230 , 150 , 135 ] ) , ( ) => { result += 'C' ; r ( ) ; } ) ; } ) ; lineEquals ( 0 , 'foobar文' ) ; strictEqual ( result , 'ABC' ) ; } ) ; it ( 'writeln' , async ( ) => { await writelnSync ( 'foo' ) ; await writelnSync ( 'bar' ) ; await writelnSync ( '文' ) ; lineEquals ( 0 , 'foo' ) ; lineEquals ( 1 , 'bar' ) ; lineEquals ( 2 , '文' ) ; } ) ; it ( 'writeln with callback' , async ( ) => { let result ; await new Promise < void > ( r => { term . writeln ( 'foo' , ( ) => { result = '1' ; } ) ; term . writeln ( 'bar' , ( ) => { result += '2' ; } ) ; term . writeln ( '文' , ( ) => { result += '3' ; r ( ) ; } ) ; } ) ; lineEquals ( 0 , 'foo' ) ; lineEquals ( 1 , 'bar' ) ; lineEquals ( 2 , '文' ) ; strictEqual ( result , '123' ) ; } ) ; it ( 'writeln - bytes (UTF8)' , async ( ) => { await writelnSync ( new Uint8Array ( [ 102 , 111 , 111 ] ) ) ; await writelnSync ( new Uint8Array ( [ 98 , 97 , 114 ] ) ) ; await writelnSync ( new Uint8Array ( [ 230 , 150 , 135 ] ) ) ; lineEquals ( 0 , 'foo' ) ; lineEquals ( 1 , 'bar' ) ; lineEquals ( 2 , '文' ) ; } ) ; it ( 'clear' , async ( ) => { term = new Terminal ( { rows : 5 } ) ; for ( let i = 0 ; i < 10 ; i ++ ) { await writeSync ( '\n\rtest' + i ) ; } term . clear ( ) ; strictEqual ( term . buffer . active . length , 5 ) ; lineEquals ( 0 , 'test9' ) ; for ( let i = 1 ; i < 5 ; i ++ ) { lineEquals ( i , '' ) ; } } ) ; it ( 'getOption, setOption' , async ( ) => { strictEqual ( term . getOption ( 'scrollback' ) , 1000 ) ; term . setOption ( 'scrollback' , 50 ) ; strictEqual ( term . getOption ( 'scrollback' ) , 50 ) ; } ) ; describe ( 'options' , ( ) => { const termOptions = { cols : 80 , rows : 24 } ; beforeEach ( async ( ) => { term = new Terminal ( termOptions ) ; } ) ; it ( 'get options' , ( ) => { const options = term . options ; strictEqual ( options . cols , 80 ) ; strictEqual ( options . rows , 24 ) ; } ) ; it ( 'set options' , async ( ) => { const options = term . options ; throws ( ( ) => options . cols = 40 ) ; throws ( ( ) => options . rows = 20 ) ; term . options . scrollback = 1 ; strictEqual ( term . options . scrollback , 1 ) ; term . options = { fontSize : 12 , fontFamily : 'Arial' } ; strictEqual ( term . options . fontSize , 12 ) ; strictEqual ( term . options . fontFamily , 'Arial' ) ; } ) ; } ) ; describe ( 'loadAddon' , ( ) => { it ( 'constructor' , async ( ) => { term = new Terminal ( { cols : 5 } ) ; let cols = 0 ; term . loadAddon ( { activate : ( t ) => cols = t . cols , dispose : ( ) => { } } ) ; strictEqual ( cols , 5 ) ; } ) ; it ( 'dispose (addon)' , async ( ) => { let disposeCalled = false ; const addon = { activate : ( ) => { } , dispose : ( ) => disposeCalled = true } ; term . loadAddon ( addon ) ; strictEqual ( disposeCalled , false ) ; addon . dispose ( ) ; strictEqual ( disposeCalled , true ) ; } ) ; it ( 'dispose (terminal)' , async ( ) => { let disposeCalled = false ; term . loadAddon ( { activate : ( ) => { } , dispose : ( ) => disposeCalled = true } ) ; strictEqual ( disposeCalled , false ) ; term . dispose ( ) ; strictEqual ( disposeCalled , true ) ; } ) ; } ) ; describe ( 'Events' , ( ) => { it ( 'onCursorMove' , async ( ) => { let callCount = 0 ; term . onCursorMove ( e => callCount ++ ) ; await writeSync ( 'foo' ) ; strictEqual ( callCount , 1 ) ; await writeSync ( 'bar' ) ; strictEqual ( callCount , 2 ) ; } ) ; it ( 'onData' , async ( ) => { const calls = [ ] ; term . onData ( e => calls . push ( e ) ) ; await writeSync ( '\x1b[5n' ) ; deepStrictEqual ( calls , [ '\x1b[0n' ] ) ; } ) ; it ( 'onLineFeed' , async ( ) => { let callCount = 0 ; term . onLineFeed ( ( ) => callCount ++ ) ; await writelnSync ( 'foo' ) ; strictEqual ( callCount , 1 ) ; await writelnSync ( 'bar' ) ; strictEqual ( callCount , 2 ) ; } ) ; it ( 'onScroll' , async ( ) => { term = new Terminal ( { rows : 5 } ) ; const calls = [ ] ; term . onScroll ( e => calls . push ( e ) ) ; for ( let i = 0 ; i < 4 ; i ++ ) { await writelnSync ( 'foo' ) ; } deepStrictEqual ( calls , [ ] ) ; await writelnSync ( 'bar' ) ; deepStrictEqual ( calls , [ 1 ] ) ; await writelnSync ( 'baz' ) ; deepStrictEqual ( calls , [ 1 , 2 ] ) ; } ) ; it ( 'onResize' , async ( ) => { const calls = [ ] ; term . onResize ( e => calls . push ( [ e . cols , e . rows ] ) ) ; deepStrictEqual ( calls , [ ] ) ; term . resize ( 10 , 5 ) ; deepStrictEqual ( calls , [ [ 10 , 5 ] ] ) ; term . resize ( 20 , 15 ) ; deepStrictEqual ( calls , [ [ 10 , 5 ] , [ 20 , 15 ] ] ) ; } ) ; it ( 'onTitleChange' , async ( ) => { const calls = [ ] ; term . onTitleChange ( e => calls . push ( e ) ) ; deepStrictEqual ( calls , [ ] ) ; await writeSync ( '\x1b]2;foo\x9c' ) ; deepStrictEqual ( calls , [ 'foo' ] ) ; } ) ; it ( 'onBell' , async ( ) => { const calls = [ ] ; term . onBell ( ( ) => calls . push ( true ) ) ; deepStrictEqual ( calls , [ ] ) ; await writeSync ( '\x07' ) ; deepStrictEqual ( calls , [ true ] ) ; } ) ; } ) ; describe ( 'buffer' , ( ) => { it ( 'cursorX, cursorY' , async ( ) => { term = new Terminal ( { rows : 5 , cols : 5 } ) ; strictEqual ( term . buffer . active . cursorX , 0 ) ; strictEqual ( term . buffer . active . cursorY , 0 ) ; await writeSync ( 'foo' ) ; strictEqual ( term . buffer . active . cursorX , 3 ) ; strictEqual ( term . buffer . active . cursorY , 0 ) ; await writeSync ( '\n' ) ; strictEqual ( term . buffer . active . cursorX , 3 ) ; strictEqual ( term . buffer . active . cursorY , 1 ) ; await writeSync ( '\r' ) ; strictEqual ( term . buffer . active . cursorX , 0 ) ; strictEqual ( term . buffer . active . cursorY , 1 ) ; await writeSync ( 'abcde' ) ; strictEqual ( term . buffer . active . cursorX , 5 ) ; strictEqual ( term . buffer . active . cursorY , 1 ) ; await writeSync ( '\n\r\n\n\n\n\n' ) ; strictEqual ( term . buffer . active . cursorX , 0 ) ; strictEqual ( term . buffer . active . cursorY , 4 ) ; } ) ; it ( 'viewportY' , async ( ) => { term = new Terminal ( { rows : 5 } ) ; strictEqual ( term . buffer . active . viewportY , 0 ) ; await writeSync ( '\n\n\n\n' ) ; strictEqual ( term . buffer . active . viewportY , 0 ) ; await writeSync ( '\n' ) ; strictEqual ( term . buffer . active . viewportY , 1 ) ; await writeSync ( '\n\n\n\n' ) ; strictEqual ( term . buffer . active . viewportY , 5 ) ; term . scrollLines ( - 1 ) ; strictEqual ( term . buffer . active . viewportY , 4 ) ; term . scrollToTop ( ) ; strictEqual ( term . buffer . active . viewportY , 0 ) ; } ) ; it ( 'baseY' , async ( ) => { term = new Terminal ( { rows : 5 } ) ; strictEqual ( term . buffer . active . baseY , 0 ) ; await writeSync ( '\n\n\n\n' ) ; strictEqual ( term . buffer . active . baseY , 0 ) ; await writeSync ( '\n' ) ; strictEqual ( term . buffer . active . baseY , 1 ) ; await writeSync ( '\n\n\n\n' ) ; strictEqual ( term . buffer . active . baseY , 5 ) ; term . scrollLines ( - 1 ) ; strictEqual ( term . buffer . active . baseY , 5 ) ; term . scrollToTop ( ) ; strictEqual ( term . buffer . active . baseY , 5 ) ; } ) ; it ( 'length' , async ( ) => { term = new Terminal ( { rows : 5 } ) ; strictEqual ( term . buffer . active . length , 5 ) ; await writeSync ( '\n\n\n\n' ) ; strictEqual ( term . buffer . active . length , 5 ) ; await writeSync ( '\n' ) ; strictEqual ( term . buffer . active . length , 6 ) ; await writeSync ( '\n\n\n\n' ) ; strictEqual ( term . buffer . active . length , 10 ) ; } ) ; describe ( 'getLine' , ( ) => { it ( 'invalid index' , async ( ) => { term = new Terminal ( { rows : 5 } ) ; strictEqual ( term . buffer . active . getLine ( - 1 ) , undefined ) ; strictEqual ( term . buffer . active . getLine ( 5 ) , undefined ) ; } ) ; it ( 'isWrapped' , async ( ) => { term = new Terminal ( { cols : 5 } ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . isWrapped , false ) ; strictEqual ( term . buffer . active . getLine ( 1 ) ! . isWrapped , false ) ; await writeSync ( 'abcde' ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . isWrapped , false ) ; strictEqual ( term . buffer . active . getLine ( 1 ) ! . isWrapped , false ) ; await writeSync ( 'f' ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . isWrapped , false ) ; strictEqual ( term . buffer . active . getLine ( 1 ) ! . isWrapped , true ) ; } ) ; it ( 'translateToString' , async ( ) => { term = new Terminal ( { cols : 5 } ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . translateToString ( ) , '     ' ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . translateToString ( true ) , '' ) ; await writeSync ( 'foo' ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . translateToString ( ) , 'foo  ' ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . translateToString ( true ) , 'foo' ) ; await writeSync ( 'bar' ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . translateToString ( ) , 'fooba' ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . translateToString ( true ) , 'fooba' ) ; strictEqual ( term . buffer . active . getLine ( 1 ) ! . translateToString ( true ) , 'r' ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . translateToString ( false , 1 ) , 'ooba' ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . translateToString ( false , 1 , 3 ) , 'oo' ) ; } ) ; it ( 'getCell' , async ( ) => { term = new Terminal ( { cols : 5 } ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . getCell ( - 1 ) , undefined ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . getCell ( 5 ) , undefined ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . getCell ( 0 ) ! . getChars ( ) , '' ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . getCell ( 0 ) ! . getWidth ( ) , 1 ) ; await writeSync ( 'a文' ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . getCell ( 0 ) ! . getChars ( ) , 'a' ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . getCell ( 0 ) ! . getWidth ( ) , 1 ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . getCell ( 1 ) ! . getChars ( ) , '文' ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . getCell ( 1 ) ! . getWidth ( ) , 2 ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . getCell ( 2 ) ! . getChars ( ) , '' ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . getCell ( 2 ) ! . getWidth ( ) , 0 ) ; } ) ; } ) ; it ( 'active, normal, alternate' , async ( ) => { term = new Terminal ( { cols : 5 } ) ; strictEqual ( term . buffer . active . type , 'normal' ) ; strictEqual ( term . buffer . normal . type , 'normal' ) ; strictEqual ( term . buffer . alternate . type , 'alternate' ) ; await writeSync ( 'norm ' ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . translateToString ( ) , 'norm ' ) ; strictEqual ( term . buffer . normal . getLine ( 0 ) ! . translateToString ( ) , 'norm ' ) ; strictEqual ( term . buffer . alternate . getLine ( 0 ) , undefined ) ; await writeSync ( '\x1b[?47h\r' ) ; strictEqual ( term . buffer . active . type , 'alternate' ) ; strictEqual ( term . buffer . normal . type , 'normal' ) ; strictEqual ( term . buffer . alternate . type , 'alternate' ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . translateToString ( ) , '     ' ) ; await writeSync ( 'alt  ' ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . translateToString ( ) , 'alt  ' ) ; strictEqual ( term . buffer . normal . getLine ( 0 ) ! . translateToString ( ) , 'norm ' ) ; strictEqual ( term . buffer . alternate . getLine ( 0 ) ! . translateToString ( ) , 'alt  ' ) ; await writeSync ( '\x1b[?47l\r' ) ; strictEqual ( term . buffer . active . type , 'normal' ) ; strictEqual ( term . buffer . normal . type , 'normal' ) ; strictEqual ( term . buffer . alternate . type , 'alternate' ) ; strictEqual ( term . buffer . active . getLine ( 0 ) ! . translateToString ( ) , 'norm ' ) ; strictEqual ( term . buffer . normal . getLine ( 0 ) ! . translateToString ( ) , 'norm ' ) ; strictEqual ( term . buffer . alternate . getLine ( 0 ) , undefined ) ; } ) ; } ) ; describe ( 'modes' , ( ) => { it ( 'defaults' , ( ) => { deepStrictEqual ( term . modes , { applicationCursorKeysMode : false , applicationKeypadMode : false , bracketedPasteMode : false , insertMode : false , mouseTrackingMode : 'none' , originMode : false , reverseWraparoundMode : false , sendFocusMode : false , wraparoundMode : true } ) ; } ) ; it ( 'applicationCursorKeysMode' , async ( ) => { await writeSync ( '\x1b[?1h' ) ; strictEqual ( term . modes . applicationCursorKeysMode , true ) ; await writeSync ( '\x1b[?1l' ) ; strictEqual ( term . modes . applicationCursorKeysMode , false ) ; } ) ; it ( 'applicationKeypadMode' , async ( ) => { await writeSync ( '\x1b[?66h' ) ; strictEqual ( term . modes . applicationKeypadMode , true ) ; await writeSync ( '\x1b[?66l' ) ; strictEqual ( term . modes . applicationKeypadMode , false ) ; } ) ; it ( 'bracketedPasteMode' , async ( ) => { await writeSync ( '\x1b[?2004h' ) ; strictEqual ( term . modes . bracketedPasteMode , true ) ; await writeSync ( '\x1b[?2004l' ) ; strictEqual ( term . modes . bracketedPasteMode , false ) ; } ) ; it ( 'insertMode' , async ( ) => { await writeSync ( '\x1b[4h' ) ; strictEqual ( term . modes . insertMode , true ) ; await writeSync ( '\x1b[4l' ) ; strictEqual ( term . modes . insertMode , false ) ; } ) ; it ( 'mouseTrackingMode' , async ( ) => { await writeSync ( '\x1b[?9h' ) ; strictEqual ( term . modes . mouseTrackingMode , 'x10' ) ; await writeSync ( '\x1b[?9l' ) ; strictEqual ( term . modes . mouseTrackingMode , 'none' ) ; await writeSync ( '\x1b[?1000h' ) ; strictEqual ( term . modes . mouseTrackingMode , 'vt200' ) ; await writeSync ( '\x1b[?1000l' ) ; strictEqual ( term . modes . mouseTrackingMode , 'none' ) ; await writeSync ( '\x1b[?1002h' ) ; strictEqual ( term . modes . mouseTrackingMode , 'drag' ) ; await writeSync ( '\x1b[?1002l' ) ; strictEqual ( term . modes . mouseTrackingMode , 'none' ) ; await writeSync ( '\x1b[?1003h' ) ; strictEqual ( term . modes . mouseTrackingMode , 'any' ) ; await writeSync ( '\x1b[?1003l' ) ; strictEqual ( term . modes . mouseTrackingMode , 'none' ) ; } ) ; it ( 'originMode' , async ( ) => { await writeSync ( '\x1b[?6h' ) ; strictEqual ( term . modes . originMode , true ) ; await writeSync ( '\x1b[?6l' ) ; strictEqual ( term . modes . originMode , false ) ; } ) ; it ( 'reverseWraparoundMode' , async ( ) => { await writeSync ( '\x1b[?45h' ) ; strictEqual ( term . modes . reverseWraparoundMode , true ) ; await writeSync ( '\x1b[?45l' ) ; strictEqual ( term . modes . reverseWraparoundMode , false ) ; } ) ; it ( 'sendFocusMode' , async ( ) => { await writeSync ( '\x1b[?1004h' ) ; strictEqual ( term . modes . sendFocusMode , true ) ; await writeSync ( '\x1b[?1004l' ) ; strictEqual ( term . modes . sendFocusMode , false ) ; } ) ; it ( 'wraparoundMode' , async ( ) => { await writeSync ( '\x1b[?7h' ) ; strictEqual ( term . modes . wraparoundMode , true ) ; await writeSync ( '\x1b[?7l' ) ; strictEqual ( term . modes . wraparoundMode , false ) ; } ) ; } ) ; it ( 'dispose' , async ( ) => { term . dispose ( ) ; strictEqual ( ( term as any ) . _core . _isDisposed , true ) ; } ) ; } ) ; function writeSync ( text ) { return new Promise < void > ( r => term . write ( text , r ) ) ; } function writelnSync ( text ) { return new Promise < void > ( r => term . writeln ( text , r ) ) ; } function lineEquals ( index , text ) { strictEqual ( term . buffer . active . getLine ( index ) ! . translateToString ( true ) , text ) ; }