@@ -278,10 +278,12 @@ const mockTerminal = {
278278 open : vi . fn ( ) ,
279279 onData : vi . fn ( ( ) => vi . fn ( ) ) , // Return dispose function
280280 onResize : vi . fn ( ( ) => vi . fn ( ) ) ,
281+ onRender : vi . fn ( ( ) => vi . fn ( ) ) ,
281282 onSelectionChange : vi . fn ( ( ) => vi . fn ( ) ) ,
282283 attachCustomKeyEventHandler : vi . fn ( ) ,
283284 hasSelection : vi . fn ( ( ) => false ) ,
284285 getSelection : vi . fn ( ( ) => "" ) ,
286+ input : vi . fn ( ) ,
285287 write : vi . fn ( ) ,
286288 writeln : vi . fn ( ) ,
287289 scrollLines : vi . fn ( ) ,
@@ -297,6 +299,9 @@ const mockTerminal = {
297299 getLine : vi . fn ( ( row : number ) => mockBufferLines . get ( row ) ) ,
298300 } ,
299301 } ,
302+ parser : {
303+ registerOscHandler : vi . fn ( ( ) => ( { dispose : vi . fn ( ) } ) ) ,
304+ } ,
300305 options : { } ,
301306} ;
302307
@@ -356,6 +361,8 @@ describe("XtermHost", () => {
356361 mockTerminal . write . mockImplementation ( ( _data : Uint8Array | string , callback ?: ( ) => void ) => {
357362 callback ?.( ) ;
358363 } ) ;
364+ mockTerminal . onRender . mockImplementation ( ( ) => vi . fn ( ) ) ;
365+ mockTerminal . input . mockImplementation ( ( ) => { } ) ;
359366 mockTerminal . writeln . mockImplementation ( ( ) => { } ) ;
360367 mockTerminal . reset . mockImplementation ( ( ) => { } ) ;
361368 mockTerminal . scrollLines . mockImplementation ( ( amount : number ) => {
@@ -1204,7 +1211,7 @@ describe("XtermHost", () => {
12041211 expect . objectContaining ( {
12051212 theme : expect . objectContaining ( {
12061213 ...getThemeById ( "mint-light" ) . terminalTheme ,
1207- background : "transparent " ,
1214+ background : "#00000000 " ,
12081215 } ) ,
12091216 } )
12101217 ) ;
@@ -2703,9 +2710,10 @@ describe("XtermHost", () => {
27032710
27042711 expect ( Terminal ) . toHaveBeenCalledWith (
27052712 expect . objectContaining ( {
2713+ allowTransparency : true ,
27062714 theme : expect . objectContaining ( {
27072715 ...getThemeById ( "mint-dark" ) . terminalTheme ,
2708- background : "transparent " ,
2716+ background : "#00000000 " ,
27092717 } ) ,
27102718 } )
27112719 ) ;
@@ -2724,9 +2732,10 @@ describe("XtermHost", () => {
27242732
27252733 expect ( Terminal ) . toHaveBeenCalledWith (
27262734 expect . objectContaining ( {
2735+ allowTransparency : true ,
27272736 theme : expect . objectContaining ( {
27282737 ...getThemeById ( "mint-light" ) . terminalTheme ,
2729- background : "transparent " ,
2738+ background : "#00000000 " ,
27302739 } ) ,
27312740 } )
27322741 ) ;
@@ -2761,7 +2770,7 @@ describe("XtermHost", () => {
27612770 expect . objectContaining ( {
27622771 theme : expect . objectContaining ( {
27632772 ...getThemeById ( "mint-dark" ) . terminalTheme ,
2764- background : "transparent " ,
2773+ background : "#00000000 " ,
27652774 } ) ,
27662775 } )
27672776 ) ;
@@ -2786,7 +2795,7 @@ describe("XtermHost", () => {
27862795 expect . objectContaining ( {
27872796 theme : expect . objectContaining ( {
27882797 ...getThemeById ( "graphite-light" ) . terminalTheme ,
2789- background : "transparent " ,
2798+ background : "#00000000 " ,
27902799 } ) ,
27912800 } )
27922801 ) ;
@@ -2827,13 +2836,133 @@ describe("XtermHost", () => {
28272836 expect . objectContaining ( {
28282837 theme : expect . objectContaining ( {
28292838 ...getThemeById ( "graphite-light" ) . terminalTheme ,
2830- background : "transparent " ,
2839+ background : "#00000000 " ,
28312840 } ) ,
28322841 } )
28332842 ) ;
28342843 } ) ;
28352844 } ) ;
28362845
2846+ it ( "reports semantic terminal colors for OSC 10/11 queries while keeping the rendered background transparent" , async ( ) => {
2847+ const store = createStore ( ) ;
2848+ const sendTerminalInput = vi . fn ( ) . mockResolvedValue ( undefined ) ;
2849+ store . set ( themeAtom , "mint-light" ) ;
2850+ store . set ( wsClientAtom , {
2851+ sendTerminalInput,
2852+ sendCommand : vi . fn ( ) . mockResolvedValue ( { status : "ok" } ) ,
2853+ subscribe : vi . fn ( ( ) => ( ) => { } ) ,
2854+ getStatus : vi . fn ( ( ) => "connected" ) ,
2855+ onStatus : vi . fn ( ( ) => ( ) => { } ) ,
2856+ } as never ) ;
2857+
2858+ render (
2859+ < Provider store = { store } >
2860+ < XtermHost terminalId = "osc-query-terminal" workspaceId = "test-workspace" />
2861+ </ Provider >
2862+ ) ;
2863+
2864+ const fgHandlerCall = mockTerminal . parser . registerOscHandler . mock . calls . find (
2865+ ( [ ident ] ) => ident === 10
2866+ ) ;
2867+ const bgHandlerCall = mockTerminal . parser . registerOscHandler . mock . calls . find (
2868+ ( [ ident ] ) => ident === 11
2869+ ) ;
2870+
2871+ expect ( fgHandlerCall ) . toBeTruthy ( ) ;
2872+ expect ( bgHandlerCall ) . toBeTruthy ( ) ;
2873+
2874+ const fgHandler = fgHandlerCall ?. [ 1 ] as
2875+ | ( ( data : string ) => boolean | Promise < boolean > )
2876+ | undefined ;
2877+ const bgHandler = bgHandlerCall ?. [ 1 ] as
2878+ | ( ( data : string ) => boolean | Promise < boolean > )
2879+ | undefined ;
2880+
2881+ await act ( async ( ) => {
2882+ expect ( await fgHandler ?.( "?" ) ) . toBe ( true ) ;
2883+ expect ( await bgHandler ?.( "?" ) ) . toBe ( true ) ;
2884+ } ) ;
2885+
2886+ await waitFor ( ( ) => {
2887+ expect ( sendTerminalInput ) . toHaveBeenNthCalledWith (
2888+ 1 ,
2889+ "osc-query-terminal" ,
2890+ textEncoder . encode ( "\u001b]10;rgb:1f1f/2323/2828\u001b\\" ) ,
2891+ "system" ,
2892+ undefined
2893+ ) ;
2894+ expect ( sendTerminalInput ) . toHaveBeenNthCalledWith (
2895+ 2 ,
2896+ "osc-query-terminal" ,
2897+ textEncoder . encode ( "\u001b]11;rgb:fcfc/ffff/fdfd\u001b\\" ) ,
2898+ "system" ,
2899+ undefined
2900+ ) ;
2901+ } ) ;
2902+
2903+ expect ( mockTerminal . options ) . toEqual (
2904+ expect . objectContaining ( {
2905+ theme : expect . objectContaining ( {
2906+ ...getThemeById ( "mint-light" ) . terminalTheme ,
2907+ background : "#00000000" ,
2908+ } ) ,
2909+ } )
2910+ ) ;
2911+ } ) ;
2912+
2913+ it ( "normalizes rendered ANSI cell backgrounds to the active surface opacity" , async ( ) => {
2914+ const store = createStore ( ) ;
2915+ store . set ( themeAtom , "mint-light" ) ;
2916+ store . set ( appearancePersonalizationAtom , {
2917+ version : 1 ,
2918+ common : {
2919+ backgroundMode : "image" ,
2920+ backgroundAssetId : "asset-terminal-material-alpha" ,
2921+ backgroundFit : "cover" ,
2922+ backgroundDimness : 18 ,
2923+ backgroundBlur : 4 ,
2924+ glassEnabled : true ,
2925+ glassIntensity : 28 ,
2926+ surfaceOpacity : 52 ,
2927+ } ,
2928+ desktop : { } ,
2929+ mobile : { } ,
2930+ } ) ;
2931+
2932+ let renderListener : ( ( viewport : { start : number ; end : number } ) => void ) | undefined ;
2933+ mockTerminal . onRender . mockImplementationOnce ( ( listener ) => {
2934+ renderListener = listener ;
2935+ return vi . fn ( ) ;
2936+ } ) ;
2937+
2938+ const { container } = render (
2939+ < Provider store = { store } >
2940+ < XtermHost terminalId = "terminal-material-alpha" workspaceId = "test-workspace" />
2941+ </ Provider >
2942+ ) ;
2943+
2944+ const host = container . querySelector ( ".xterm-host" ) as HTMLDivElement | null ;
2945+ expect ( host ) . toBeTruthy ( ) ;
2946+ expect ( renderListener ) . toBeTypeOf ( "function" ) ;
2947+
2948+ const rowsElement = document . createElement ( "div" ) ;
2949+ rowsElement . className = "xterm-rows" ;
2950+ const row = document . createElement ( "div" ) ;
2951+ const cell = document . createElement ( "span" ) ;
2952+ cell . textContent = "你好" ;
2953+ cell . style . backgroundColor = "rgb(55, 55, 55)" ;
2954+ cell . style . color = "rgb(255, 255, 255)" ;
2955+ row . appendChild ( cell ) ;
2956+ rowsElement . appendChild ( row ) ;
2957+ host ! . appendChild ( rowsElement ) ;
2958+
2959+ await act ( async ( ) => {
2960+ renderListener ?.( { start : 0 , end : 0 } ) ;
2961+ } ) ;
2962+
2963+ expect ( cell . style . backgroundColor ) . toBe ( "rgba(55, 55, 55, 0.52)" ) ;
2964+ } ) ;
2965+
28372966 it ( "uses the high-contrast dark terminal palette for hc-dark" , async ( ) => {
28382967 const { Terminal } = await import ( "@xterm/xterm" ) ;
28392968 const store = createStore ( ) ;
@@ -2849,7 +2978,7 @@ describe("XtermHost", () => {
28492978 expect . objectContaining ( {
28502979 theme : expect . objectContaining ( {
28512980 ...getThemeById ( "hc-dark" ) . terminalTheme ,
2852- background : "transparent " ,
2981+ background : "#00000000 " ,
28532982 } ) ,
28542983 } )
28552984 ) ;
0 commit comments