detached f593fc1

test(theme): table-drive the dimmer palette cases

commit
f593fc16cae52e609f966e931e8b3c7db3df9c9a
author
brice · · 2026-07-24 12:23 UTC
parent
1c0bc79
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
1 file · +91 -70
M internal/usecase/theme/theme_test.go +91 -70
@@ -468,80 +468,101 @@ func TestDimmerUsesReportedPalette(t *testing.T) {
468468 dimmer := NewDimmer(baseTheme)
469469 dimBG := func(raw renderer.RGB) renderer.RGB { return blendPercent(raw, background, dimmer.backgroundPercent) }
470470 dimFG := func(raw, bg renderer.RGB) renderer.RGB { return blendPercent(raw, bg, dimmer.foregroundPercent) }
471+ ptr := func(c renderer.RGB) *renderer.RGB { return &c }
471472
472- t.Run("indexed foreground blends from the reported palette color when known", func(t *testing.T) {
473- style := renderer.Style{Foreground: 2, Background: -1}
474- got := NewDimmer(withPalette).Dim(style)
475-
476- dimmedBG := dimBG(background)
477- require.Equal(t, dimmedBG, got.BackgroundRGB)
478- require.Equal(t, dimFG(reportedSlot2, dimmedBG), got.ForegroundRGB)
479- require.NotEqual(t, dimFG(xterm256Color(2), dimmedBG), got.ForegroundRGB, "must not use the xterm table when the palette is known")
480- })
481-
482- t.Run("indexed foreground falls back to xterm when the palette bit is unknown", func(t *testing.T) {
483- style := renderer.Style{Foreground: 2, Background: -1}
484- got := NewDimmer(unknownBits).Dim(style)
485-
486- dimmedBG := dimBG(background)
487- require.Equal(t, dimFG(xterm256Color(2), dimmedBG), got.ForegroundRGB)
488- })
489-
490- t.Run("indexed foreground falls back to xterm when UsePalette is disabled", func(t *testing.T) {
491- style := renderer.Style{Foreground: 2, Background: -1}
492- got := NewDimmer(paletteDisabled).Dim(style)
493-
494- dimmedBG := dimBG(background)
495- require.Equal(t, dimFG(xterm256Color(2), dimmedBG), got.ForegroundRGB)
496- })
497-
498- t.Run("indexed background blends from the reported palette color when known", func(t *testing.T) {
499- style := renderer.Style{Foreground: -1, Background: 4}
500- got := NewDimmer(withPalette).Dim(style)
501-
502- dimmedBG := dimBG(reportedSlot4)
503- require.Equal(t, dimmedBG, got.BackgroundRGB)
504- require.Equal(t, dimFG(foreground, dimmedBG), got.ForegroundRGB)
505- })
506-
507- t.Run("indexed background falls back to xterm when the palette bit is unknown", func(t *testing.T) {
508- style := renderer.Style{Foreground: -1, Background: 4}
509- got := NewDimmer(unknownBits).Dim(style)
510-
511- dimmedBG := dimBG(xterm256Color(4))
512- require.Equal(t, dimmedBG, got.BackgroundRGB)
513- })
514-
515- t.Run("indexed underline blends from the reported palette color when known", func(t *testing.T) {
516- style := renderer.Style{
517- Foreground: -1, Background: -1,
518- HasUnderlineColor: true, UnderlineColor: 6,
519- }
520- got := NewDimmer(withPalette).Dim(style)
521-
522- dimmedBG := dimBG(background)
523- require.True(t, got.HasUnderlineColorRGB)
524- require.Equal(t, dimFG(reportedSlot6, dimmedBG), got.UnderlineColorRGB)
525- })
526-
527- t.Run("indexed underline falls back to xterm when the palette bit is unknown", func(t *testing.T) {
528- style := renderer.Style{
529- Foreground: -1, Background: -1,
530- HasUnderlineColor: true, UnderlineColor: 6,
531- }
532- got := NewDimmer(unknownBits).Dim(style)
473+ underlined := renderer.Style{
474+ Foreground: -1, Background: -1,
475+ HasUnderlineColor: true, UnderlineColor: 6,
476+ }
533477
534- dimmedBG := dimBG(background)
535- require.Equal(t, dimFG(xterm256Color(6), dimmedBG), got.UnderlineColorRGB)
536- })
478+ cases := []struct {
479+ name string
480+ theme Theme
481+ style renderer.Style
482+ // Raw colors Dim's blends must start from; expected values are
483+ // derived from them with the same blend math Dim uses.
484+ fgSource renderer.RGB
485+ bgSource renderer.RGB
486+ underlineSource *renderer.RGB // nil when the style has no underline color
487+ forbidFGSource *renderer.RGB // a raw color Dim must NOT have blended from
488+ }{
489+ {
490+ name: "indexed foreground blends from the reported palette color when known",
491+ theme: withPalette,
492+ style: renderer.Style{Foreground: 2, Background: -1},
493+ fgSource: reportedSlot2,
494+ bgSource: background,
495+ forbidFGSource: ptr(xterm256Color(2)),
496+ },
497+ {
498+ name: "indexed foreground falls back to xterm when the palette bit is unknown",
499+ theme: unknownBits,
500+ style: renderer.Style{Foreground: 2, Background: -1},
501+ fgSource: xterm256Color(2),
502+ bgSource: background,
503+ },
504+ {
505+ name: "indexed foreground falls back to xterm when UsePalette is disabled",
506+ theme: paletteDisabled,
507+ style: renderer.Style{Foreground: 2, Background: -1},
508+ fgSource: xterm256Color(2),
509+ bgSource: background,
510+ },
511+ {
512+ name: "indexed background blends from the reported palette color when known",
513+ theme: withPalette,
514+ style: renderer.Style{Foreground: -1, Background: 4},
515+ fgSource: foreground,
516+ bgSource: reportedSlot4,
517+ },
518+ {
519+ name: "indexed background falls back to xterm when the palette bit is unknown",
520+ theme: unknownBits,
521+ style: renderer.Style{Foreground: -1, Background: 4},
522+ fgSource: foreground,
523+ bgSource: xterm256Color(4),
524+ },
525+ {
526+ name: "indexed underline blends from the reported palette color when known",
527+ theme: withPalette,
528+ style: underlined,
529+ fgSource: foreground,
530+ bgSource: background,
531+ underlineSource: ptr(reportedSlot6),
532+ },
533+ {
534+ name: "indexed underline falls back to xterm when the palette bit is unknown",
535+ theme: unknownBits,
536+ style: underlined,
537+ fgSource: foreground,
538+ bgSource: background,
539+ underlineSource: ptr(xterm256Color(6)),
540+ },
541+ {
542+ name: "256-cube index is untouched by a reported palette",
543+ theme: withPalette,
544+ style: renderer.Style{Foreground: 196, Background: -1},
545+ fgSource: xterm256Color(196),
546+ bgSource: background,
547+ },
548+ }
537549
538- t.Run("256-cube index is untouched by a reported palette", func(t *testing.T) {
539- style := renderer.Style{Foreground: 196, Background: -1}
540- got := NewDimmer(withPalette).Dim(style)
550+ for _, tc := range cases {
551+ t.Run(tc.name, func(t *testing.T) {
552+ got := NewDimmer(tc.theme).Dim(tc.style)
541553
542- dimmedBG := dimBG(background)
543- require.Equal(t, dimFG(xterm256Color(196), dimmedBG), got.ForegroundRGB)
544- })
554+ dimmedBG := dimBG(tc.bgSource)
555+ require.Equal(t, dimmedBG, got.BackgroundRGB)
556+ require.Equal(t, dimFG(tc.fgSource, dimmedBG), got.ForegroundRGB)
557+ if tc.forbidFGSource != nil {
558+ require.NotEqual(t, dimFG(*tc.forbidFGSource, dimmedBG), got.ForegroundRGB, "must not use the xterm table when the palette is known")
559+ }
560+ if tc.underlineSource != nil {
561+ require.True(t, got.HasUnderlineColorRGB)
562+ require.Equal(t, dimFG(*tc.underlineSource, dimmedBG), got.UnderlineColorRGB)
563+ }
564+ })
565+ }
545566 }
546567
547568 func TestStyleHelpersFallbackAndThemed(t *testing.T) {
@@ -468,80 +468,101 @@ func TestDimmerUsesReportedPalette(t *testing.T) {
468 dimmer := NewDimmer(baseTheme)468 dimmer := NewDimmer(baseTheme)
469 dimBG := func(raw renderer.RGB) renderer.RGB { return blendPercent(raw, background, dimmer.backgroundPercent) }469 dimBG := func(raw renderer.RGB) renderer.RGB { return blendPercent(raw, background, dimmer.backgroundPercent) }
470 dimFG := func(raw, bg renderer.RGB) renderer.RGB { return blendPercent(raw, bg, dimmer.foregroundPercent) }470 dimFG := func(raw, bg renderer.RGB) renderer.RGB { return blendPercent(raw, bg, dimmer.foregroundPercent) }
471+ ptr := func(c renderer.RGB) *renderer.RGB { return &c }
471 472
472- t.Run("indexed foreground blends from the reported palette color when known", func(t *testing.T) {473+ underlined := renderer.Style{
473- style := renderer.Style{Foreground: 2, Background: -1}474+ Foreground: -1, Background: -1,
474- got := NewDimmer(withPalette).Dim(style)475+ HasUnderlineColor: true, UnderlineColor: 6,
475-476+ }
476- dimmedBG := dimBG(background)
477- require.Equal(t, dimmedBG, got.BackgroundRGB)
478- require.Equal(t, dimFG(reportedSlot2, dimmedBG), got.ForegroundRGB)
479- require.NotEqual(t, dimFG(xterm256Color(2), dimmedBG), got.ForegroundRGB, "must not use the xterm table when the palette is known")
480- })
481-
482- t.Run("indexed foreground falls back to xterm when the palette bit is unknown", func(t *testing.T) {
483- style := renderer.Style{Foreground: 2, Background: -1}
484- got := NewDimmer(unknownBits).Dim(style)
485-
486- dimmedBG := dimBG(background)
487- require.Equal(t, dimFG(xterm256Color(2), dimmedBG), got.ForegroundRGB)
488- })
489-
490- t.Run("indexed foreground falls back to xterm when UsePalette is disabled", func(t *testing.T) {
491- style := renderer.Style{Foreground: 2, Background: -1}
492- got := NewDimmer(paletteDisabled).Dim(style)
493-
494- dimmedBG := dimBG(background)
495- require.Equal(t, dimFG(xterm256Color(2), dimmedBG), got.ForegroundRGB)
496- })
497-
498- t.Run("indexed background blends from the reported palette color when known", func(t *testing.T) {
499- style := renderer.Style{Foreground: -1, Background: 4}
500- got := NewDimmer(withPalette).Dim(style)
501-
502- dimmedBG := dimBG(reportedSlot4)
503- require.Equal(t, dimmedBG, got.BackgroundRGB)
504- require.Equal(t, dimFG(foreground, dimmedBG), got.ForegroundRGB)
505- })
506-
507- t.Run("indexed background falls back to xterm when the palette bit is unknown", func(t *testing.T) {
508- style := renderer.Style{Foreground: -1, Background: 4}
509- got := NewDimmer(unknownBits).Dim(style)
510-
511- dimmedBG := dimBG(xterm256Color(4))
512- require.Equal(t, dimmedBG, got.BackgroundRGB)
513- })
514-
515- t.Run("indexed underline blends from the reported palette color when known", func(t *testing.T) {
516- style := renderer.Style{
517- Foreground: -1, Background: -1,
518- HasUnderlineColor: true, UnderlineColor: 6,
519- }
520- got := NewDimmer(withPalette).Dim(style)
521-
522- dimmedBG := dimBG(background)
523- require.True(t, got.HasUnderlineColorRGB)
524- require.Equal(t, dimFG(reportedSlot6, dimmedBG), got.UnderlineColorRGB)
525- })
526-
527- t.Run("indexed underline falls back to xterm when the palette bit is unknown", func(t *testing.T) {
528- style := renderer.Style{
529- Foreground: -1, Background: -1,
530- HasUnderlineColor: true, UnderlineColor: 6,
531- }
532- got := NewDimmer(unknownBits).Dim(style)
533 477
534- dimmedBG := dimBG(background)478+ cases := []struct {
535- require.Equal(t, dimFG(xterm256Color(6), dimmedBG), got.UnderlineColorRGB)479+ name string
536- })480+ theme Theme
481+ style renderer.Style
482+ // Raw colors Dim's blends must start from; expected values are
483+ // derived from them with the same blend math Dim uses.
484+ fgSource renderer.RGB
485+ bgSource renderer.RGB
486+ underlineSource *renderer.RGB // nil when the style has no underline color
487+ forbidFGSource *renderer.RGB // a raw color Dim must NOT have blended from
488+ }{
489+ {
490+ name: "indexed foreground blends from the reported palette color when known",
491+ theme: withPalette,
492+ style: renderer.Style{Foreground: 2, Background: -1},
493+ fgSource: reportedSlot2,
494+ bgSource: background,
495+ forbidFGSource: ptr(xterm256Color(2)),
496+ },
497+ {
498+ name: "indexed foreground falls back to xterm when the palette bit is unknown",
499+ theme: unknownBits,
500+ style: renderer.Style{Foreground: 2, Background: -1},
501+ fgSource: xterm256Color(2),
502+ bgSource: background,
503+ },
504+ {
505+ name: "indexed foreground falls back to xterm when UsePalette is disabled",
506+ theme: paletteDisabled,
507+ style: renderer.Style{Foreground: 2, Background: -1},
508+ fgSource: xterm256Color(2),
509+ bgSource: background,
510+ },
511+ {
512+ name: "indexed background blends from the reported palette color when known",
513+ theme: withPalette,
514+ style: renderer.Style{Foreground: -1, Background: 4},
515+ fgSource: foreground,
516+ bgSource: reportedSlot4,
517+ },
518+ {
519+ name: "indexed background falls back to xterm when the palette bit is unknown",
520+ theme: unknownBits,
521+ style: renderer.Style{Foreground: -1, Background: 4},
522+ fgSource: foreground,
523+ bgSource: xterm256Color(4),
524+ },
525+ {
526+ name: "indexed underline blends from the reported palette color when known",
527+ theme: withPalette,
528+ style: underlined,
529+ fgSource: foreground,
530+ bgSource: background,
531+ underlineSource: ptr(reportedSlot6),
532+ },
533+ {
534+ name: "indexed underline falls back to xterm when the palette bit is unknown",
535+ theme: unknownBits,
536+ style: underlined,
537+ fgSource: foreground,
538+ bgSource: background,
539+ underlineSource: ptr(xterm256Color(6)),
540+ },
541+ {
542+ name: "256-cube index is untouched by a reported palette",
543+ theme: withPalette,
544+ style: renderer.Style{Foreground: 196, Background: -1},
545+ fgSource: xterm256Color(196),
546+ bgSource: background,
547+ },
548+ }
537 549
538- t.Run("256-cube index is untouched by a reported palette", func(t *testing.T) {550+ for _, tc := range cases {
539- style := renderer.Style{Foreground: 196, Background: -1}551+ t.Run(tc.name, func(t *testing.T) {
540- got := NewDimmer(withPalette).Dim(style)552+ got := NewDimmer(tc.theme).Dim(tc.style)
541 553
542- dimmedBG := dimBG(background)554+ dimmedBG := dimBG(tc.bgSource)
543- require.Equal(t, dimFG(xterm256Color(196), dimmedBG), got.ForegroundRGB)555+ require.Equal(t, dimmedBG, got.BackgroundRGB)
544- })556+ require.Equal(t, dimFG(tc.fgSource, dimmedBG), got.ForegroundRGB)
557+ if tc.forbidFGSource != nil {
558+ require.NotEqual(t, dimFG(*tc.forbidFGSource, dimmedBG), got.ForegroundRGB, "must not use the xterm table when the palette is known")
559+ }
560+ if tc.underlineSource != nil {
561+ require.True(t, got.HasUnderlineColorRGB)
562+ require.Equal(t, dimFG(*tc.underlineSource, dimmedBG), got.UnderlineColorRGB)
563+ }
564+ })
565+ }
545 }566 }
546 567
547 func TestStyleHelpersFallbackAndThemed(t *testing.T) {568 func TestStyleHelpersFallbackAndThemed(t *testing.T) {

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 12

Tags 11

↑↓ moveenter openesc close