Skip to content

Add dark and light color themes - #6065

Merged
stefanhaller merged 16 commits into
masterfrom
dark-and-light-themes
Sep 27, 2026
Merged

stefanhaller merged 16 commits into
masterfrom
dark-and-light-themes

Conversation

@stefanhaller

Copy link
Copy Markdown
Collaborator

Make it possible to override gui.theme colors for light or dark backgrounds, by setting them in gui.darkTheme or gui.lightTheme, respectively; this is often necessary when there isn't a single color that looks good in both.

Use this to provide better defaults for the background color of a selected line, and to add a color for the background of an inactive selected line (used in unfocused views), which didn't have one by default.

Also, provide a way to turn off the "bold" highlighting of the selected line, which was hard-coded and couldn't be changed; there's a new config setting gui.theme.selectedLineFgColor that is [bold] by default (so existing behavior is unchanged), but can be set to [default] to remove the bold. This addresses #2304.

@stefanhaller
stefanhaller added this pull request to stack #6064 September 26, 2026 17:28
@stefanhaller stefanhaller added the enhancement New feature or request label Sep 26, 2026
@stefanhaller
stefanhaller force-pushed the dark-and-light-themes branch 2 times, most recently from 9ac3853 to 00c87c0 Compare September 27, 2026 06:09
Base automatically changed from diff-renderer-color-scheme to master September 27, 2026 06:16
stefanhaller and others added 16 commits September 27, 2026 08:16
gui.branchColors has been deprecated in favor of gui.branchColorPatterns
since 0.44.0. We are about to move gui.branchColorPatterns into
gui.theme, and the deprecated key would have to move along with it.
Migrate it instead, so that we can remove it.

gui.branchColors matched its keys against the part of a branch name
before the first slash. The pattern ^<key>(/|$), with the key escaped,
matches the same branches.

If gui.branchColorPatterns is set, gui.branchColors has no effect; in
that case the migration removes it. This check is done per file. So if
the global config sets gui.branchColorPatterns and a repo config sets
only gui.branchColors, the repo's colors were ignored so far, and now
they apply.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The next commit needs it for a single color.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
If several patterns in gui.branchColorPatterns match a branch, the color
it gets is picked at random, and it can change from one render to the
next. The patterns are kept in a Go map, and Go randomizes the order in
which a map is iterated.

Keep the patterns in a list instead, in the order in which they are
written, and let the first match win. If a repo's config file has
patterns too, put them in front of those of the global config file,
because they are more specific.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
We are about to add overrides of gui.theme for dark and light
backgrounds. Author and branch colors need them too, because a color
that reads well on a dark background may be hard to read on a light
one. Move them into gui.theme, so that the overrides cover them without
a mechanism of their own.

The migration of gui.branchColors creates gui.branchColorPatterns, so it
now has to run before the moves.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Since gui.colorScheme exists, the name reads as if the function set that
config. That gets more confusing once gui.colorScheme decides which
theme the function applies.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
We are about to add gui.darkTheme and gui.lightTheme, with the same type
as gui.theme. The schema generator stores a struct type as one
definition that all its properties refer to, and setDefaultVals writes
the defaults of each path into that definition. The overrides would
then claim the defaults of gui.theme, both in the schema and in
Config.md.

Give each property whose struct definition is shared a copy of its own.
In Config.md, print only the description of every copy after the first,
so that the fields aren't listed several times.

Nothing in the config shares a struct definition yet, so the generated
files don't change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A color that reads well on a dark background can be hard to read on a
light one, and the other way round. If you switch your terminal between
dark and light, there is often no single set of theme colors that works
for both (#4366).

Add two overrides of gui.theme, one for each kind of background.
gui.colorScheme, or else what the terminal tells us, decides which one
applies. A field that is set in the override replaces the one in
gui.theme. Author colors and branch color patterns are merged by entry
instead, so that an override doesn't have to repeat the entries it
doesn't change.

When the terminal's background changes, re-apply the theme and
re-render all views, not only the ones that show author colors.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A later commit shows the hashes of commits outside the bisect range in a
dimmer variant of the default text color. A darker shade of a terminal
palette color can't be derived, because we don't know what the palette
is, so leave the shading to the terminal and use its faint attribute,
SGR 2. In gookit/color that attribute is called OpFuzzy.

Terminals that don't implement SGR 2 render the text in its normal color.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Config.md lists strikethrough as a modifier for theme colors, but only
GetTextStyle knows it. GetGocuiStyle turns an unknown name into white,
and white OR-ed with a palette color is white. So if you set a border
color to [red, strikethrough], you get a white border without
strikethrough. The same goes for the parts of the selected line,
options text and default text colors that gocui draws.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The faint attribute makes text recede on dark and light backgrounds
alike, without having to pick a gray for each. Let users use it in the
theme.

Some theme colors go through both GetTextStyle and GetGocuiStyle, so
both have to know it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
While bisecting, the hashes of the commits outside the bisect range are
black. On a dark gray background this makes them recede, but on a black
one they are invisible, and on a light one they stand out more than any
other hash.

Draw them in faint text instead. The terminal shades faint text toward
its background, whatever that is.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Some theme colors can't have one default that suits both dark and light
backgrounds. A gray background for the selected line of an inactive
view has to be lighter than the terminal's background if that is dark,
and darker if it is light.

Give such fields a default for each kind of background. Derive it from
the terminal's background color if the terminal tells us, so that it
keeps the same distance from the background however dark or light that
is, and takes on its tint. Otherwise, assume a black or white
background.

These defaults can't be the defaults of gui.theme. We would then have
to tell whether a value there came from the user or from the built-in
defaults, because only the user's value should win over a background
default. Keep them apart from the user config instead, and leave these
fields empty in the defaults of gui.theme, so that a value there always
comes from the user. Tests ensure that no field has both kinds of
defaults, and that both kinds of background set the same fields.

Start with inactiveViewSelectedLineBgColor: the background mixed with
30% white if it is dark (#4d4d4d on black), or with 15% black if it is
light (#d9d9d9 on white). A gray background shows where the selection
is in a view without the focus more clearly than the bold text we used
so far.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The borders of inactive windows are drawn in the terminal's default text
color, so they are as prominent as the text inside the windows. Draw
them in faint text instead. The terminal shades faint text toward its
background, so this works on dark and light backgrounds alike, and also
on backgrounds that are neither black nor white. The titles of inactive
windows use the same color, so they are dimmed too.

Terminals that don't support faint text draw the borders in the default
color, as before.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
On a light background, the selected line is black text on the palette's
blue. With most palettes, this is hard to read. Light palettes make all
their colors dark enough to read as text on the light background, so
none of them works well as a background for text.

On a light background, mix 25% of #0064ff into the terminal's background
instead. On white, this gives #bfd8ff. The colored text on the selected
line then stays as readable as it is elsewhere.

On a dark background, keep the palette's blue. Dark palettes make it
dark enough to work as a background, and it keeps working on terminals
with only 8 colors. There, a color mixed from a dark background would
turn into black.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gocui draws the palette colors 0 to 7 on the selected line in their
bright variants. This was meant for the blue highlight on a dark
background, but in most dark palettes the bright variants are so close
to the normal ones that it's barely visible. Elsewhere it makes the text
harder to read. In many palettes, the bright variants are lighter, and
they don't work on the light highlight of a light background. Solarized
maps most of its bright colors to its grays, so colored text on the
selected line turns gray.

Draw the text of the selected line in the same colors as on the other
lines.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The text of the selected line is always bold. Some users don't like
this (#2304), but there is no way to turn it off. Setting
selectedLineBgColor doesn't help. Its attributes apply to the text too,
so it can add bold, but it can't take it away.

Add gui.theme.selectedLineFgColor for the text of the selected line, in
focused and unfocused views alike. Its attributes are added to those of
the text, and a color replaces the colors of the text. It is [bold] by
default, so nothing changes unless you set it; 'default' leaves the
text as it is.

Putting bold into the default of selectedLineBgColor instead wouldn't
work well. To turn it off, you would have to replace the whole list, and
lose the color that is computed from the terminal's background.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@stefanhaller
stefanhaller merged commit 58fe972 into master Sep 27, 2026
12 checks passed
@stefanhaller
stefanhaller deleted the dark-and-light-themes branch September 27, 2026 06:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant