@@ -139,7 +139,7 @@ function getSyntaxRules(theme: Theme): SyntaxRule[] {
139139 } ,
140140 {
141141 scope : [ "markup.raw.inline" ] ,
142- style : { foreground : theme . markdownCode , background : theme . background } ,
142+ style : { foreground : theme . markdownCode , background : theme . backgroundElement } ,
143143 } ,
144144 { scope : [ "markup.link" ] , style : { foreground : theme . markdownLink , underline : true } } ,
145145 { scope : [ "spell" , "nospell" ] , style : { foreground : theme . text } } ,
@@ -353,3 +353,84 @@ describe("dark theme: regression check", () => {
353353 } ,
354354 )
355355} )
356+
357+ // ─── Tests for #704 fixes ──────────────────────────────────────────────────
358+
359+ describe ( "light theme: markup.raw.inline uses backgroundElement (issue #704)" , ( ) => {
360+ test . each ( LIGHT_THEMES ) (
361+ "%s: markup.raw.inline has non-transparent background" ,
362+ ( _name , themeJson ) => {
363+ const resolved = resolveTheme ( themeJson , "light" )
364+ const rules = getSyntaxRules ( resolved )
365+
366+ const inlineRule = rules . find ( ( r ) => r . scope . includes ( "markup.raw.inline" ) )
367+ expect ( inlineRule ) . toBeDefined ( )
368+ expect ( inlineRule ! . style . background ) . toBeDefined ( )
369+ // backgroundElement should never be fully transparent
370+ expect ( inlineRule ! . style . background ! . a ) . toBeGreaterThan ( 0 )
371+ } ,
372+ )
373+
374+ test . each ( LIGHT_THEMES ) (
375+ "%s: markup.raw.inline foreground is readable on its background" ,
376+ ( _name , themeJson ) => {
377+ const resolved = resolveTheme ( themeJson , "light" )
378+ const rules = getSyntaxRules ( resolved )
379+
380+ const inlineRule = rules . find ( ( r ) => r . scope . includes ( "markup.raw.inline" ) ) !
381+ const fg = inlineRule . style . foreground !
382+ const bg = inlineRule . style . background !
383+
384+ const ratio = contrastRatio ( fg , bg )
385+ expect ( ratio ) . toBeGreaterThanOrEqual ( 2 )
386+ } ,
387+ )
388+ } )
389+
390+ describe ( "system theme: light mode foreground fallback (issue #704)" , ( ) => {
391+ // Simulate what generateSystem does when defaultForeground is missing
392+ // and mode is "light" — the fallback should NOT use palette[7] (#c0c0c0)
393+ test ( "light mode fallback foreground is dark, not #c0c0c0" , ( ) => {
394+ const PALETTE_7 = RGBA . fromHex ( "#c0c0c0" )
395+ const LIGHT_FALLBACK = RGBA . fromHex ( "#1a1a1a" )
396+ const WHITE_BG = RGBA . fromHex ( "#ffffff" )
397+
398+ // In light mode, we should use #1a1a1a, not #c0c0c0
399+ const ratio = contrastRatio ( LIGHT_FALLBACK , WHITE_BG )
400+ expect ( ratio ) . toBeGreaterThanOrEqual ( 3 )
401+
402+ // palette[7] would be nearly invisible
403+ const badRatio = contrastRatio ( PALETTE_7 , WHITE_BG )
404+ expect ( badRatio ) . toBeLessThan ( 2 ) // confirms the bug
405+ } )
406+ } )
407+
408+ describe ( "COLORFGBG detection (issue #704)" , ( ) => {
409+ // Test the parsing logic used in getTerminalBackgroundColor fallback
410+ function parseCOLORFGBG ( value : string ) : "dark" | "light" | null {
411+ const parts = value . split ( ";" )
412+ const bg = parseInt ( parts [ parts . length - 1 ] )
413+ if ( isNaN ( bg ) ) return null
414+ return bg >= 8 ? "light" : "dark"
415+ }
416+
417+ test ( "COLORFGBG=0;15 -> light (white bg)" , ( ) => {
418+ expect ( parseCOLORFGBG ( "0;15" ) ) . toBe ( "light" )
419+ } )
420+
421+ test ( "COLORFGBG=15;0 -> dark (black bg)" , ( ) => {
422+ expect ( parseCOLORFGBG ( "15;0" ) ) . toBe ( "dark" )
423+ } )
424+
425+ test ( "COLORFGBG=0;7;15 -> light (3-part, last is bg)" , ( ) => {
426+ expect ( parseCOLORFGBG ( "0;7;15" ) ) . toBe ( "light" )
427+ } )
428+
429+ test ( "COLORFGBG=15;0;0 -> dark (3-part, last is bg)" , ( ) => {
430+ expect ( parseCOLORFGBG ( "15;0;0" ) ) . toBe ( "dark" )
431+ } )
432+
433+ test ( "invalid COLORFGBG -> null" , ( ) => {
434+ expect ( parseCOLORFGBG ( "abc" ) ) . toBe ( null )
435+ } )
436+ } )
0 commit comments