Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ That said, these are more guidelines rather than hardset rules, though the proje

### Features

- [#1843](https://github.com/ClementTsang/bottom/pull/1843): Use light variant of theme automatically when terminal background is light.
- [#1812](https://github.com/ClementTsang/bottom/pull/1812): Add `free_arc` option to subtract ARC from total memory usage.

### Bug Fixes
Expand Down
52 changes: 38 additions & 14 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ time = { version = "0.3.44", features = ["local-offset", "formatting", "macros"]
schemars = { version = "1.0.4", optional = true }
serde_json = { version = "1.0.145", optional = true }
strum = { version = "0.27.2", features = ["derive"], optional = true }
terminal-colorsaurus = "1.0.1"

[target.'cfg(unix)'.dependencies]
libc = "0.2.176"
Expand Down
3 changes: 2 additions & 1 deletion docs/content/configuration/config-file/styling.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ bottom has a few built-in themes:
- [Nord](https://www.nordtheme.com/)
- [Gruvbox](https://github.com/morhetz/gruvbox)

These themes all also have light variants to support terminals using lighter colours.
These themes all also have light variants to support terminals using lighter colours. The light variants will be used
automatically if your terminal is using a light background.

To set the theme from the command line:

Expand Down
3 changes: 0 additions & 3 deletions sample_configs/default_config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -231,11 +231,8 @@
#[styles] # Uncomment if you want to use custom styling
# Built-in themes. Valid values are:
# - "default"
# - "default-light"
# - "gruvbox"
# - "gruvbox-light"
# - "nord"
# - "nord-light".
Comment on lines -237 to -241
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, my gut reaction is that I'm not a huge fan of not being able to override the automatic settings, though I'm also not sure how certain interactions should behave in that case.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The (ugly?) workarounds off the top of my head to support this are either:

  • Add -dark variants to mirror -light, and ignore auto-detection for those.
  • Add a flag to explicitly set light/dark modes for existing themes, though I'm not a huge fan of having another flag for this unless necessary.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Open to any other suggestions/opinions)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a few ideas in mind, but all of them involve some amount of breaking changes:

  • we could keep the light variants as is: if the user has explicitly specified a light variant, we pick it, if not, we do detection. This would still confuse users if on the off chance they decide to launch bottom on a light terminal background and expect the dark variant to show up.
  • Add corresponding separate dark variants (as you mentioned) - if variants are specified explicitly, we don't do detection, and if variants are not specified (just the name is specified), we do detection. This will cause a similar gotcha as above (although that's still a very niche edge case).

I wanted an implementation as clean as possible without confusing existing users.

There is an argument that can be made for allowing users to override the theme - which is, the auto-detection for some terminal is so bad that they have to specify the light variant. I'm not sure how probable this is though.

#
# This will have the lowest precedence if a custom colour palette is set,
# or overridden if the command-line flag for a built-in theme is set.
Expand Down
5 changes: 1 addition & 4 deletions schema/v0.9/bottom.json
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,8 @@
"default": "default",
"enum": [
"default",
"default-light",
"gruvbox",
"gruvbox-light",
"nord",
"nord-light"
Comment on lines -178 to -182
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't change this file, this is the schema for an old release so this doesn't really make sense, since these changes wouldn't apply to that version.

If you're going to update the schema, run the schema updating script ./scripts/schema/generate.sh to update nightly's schema automatically. We can then cut the nightly schema for a stable release when necessary.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, my bad. I have reverted the change.

I tried running ./scripts/schema/generate.sh - it ran successfully but didn't make any changes in the schema/nightly/bottom.json file.

"nord"
],
"description": "Built-in themes",
"type": "string"
Expand Down
3 changes: 0 additions & 3 deletions src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,11 +481,8 @@ pub(crate) const CONFIG_TEXT: &str = r#"# This is a default config file for bott
#[styles] # Uncomment if you want to use custom styling
# Built-in themes. Valid values are:
# - "default"
# - "default-light"
# - "gruvbox"
# - "gruvbox-light"
# - "nord"
# - "nord-light".
#
# This will have the lowest precedence if a custom colour palette is set,
# or overridden if the command-line flag for a built-in theme is set.
Expand Down
10 changes: 2 additions & 8 deletions src/options/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -616,24 +616,18 @@ pub struct StyleArgs {
value_name = "SCHEME",
value_parser = [
"default",
"default-light",
"gruvbox",
"gruvbox-light",
"nord",
"nord-light",
],
hide_possible_values = true,
help = indoc! {
"Use a built-in color theme, use '--help' for info on the colors. [possible values: default, default-light, gruvbox, gruvbox-light, nord, nord-light]",
"Use a built-in color theme, use '--help' for info on the colors. [possible values: default, gruvbox, nord]",
},
long_help = indoc! {
"Use a pre-defined color theme. Currently supported themes are:
- default
- default-light (default but adjusted for lighter backgrounds)
- gruvbox (a bright theme with 'retro groove' colors)
- gruvbox-light (gruvbox but adjusted for lighter backgrounds)
- nord (an arctic, north-bluish color palette)
- nord-light (nord but adjusted for lighter backgrounds)"
- nord (an arctic, north-bluish color palette)"
}
)]
pub theme: Option<String>,
Expand Down
68 changes: 58 additions & 10 deletions src/options/config/style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use memory::MemoryStyle;
use network::NetworkStyle;
use serde::{Deserialize, Serialize};
use tables::TableStyle;
use terminal_colorsaurus::{QueryOptions, ThemeMode, theme_mode};
use tui::{style::Style, widgets::BorderType};
use utils::{opt, set_colour, set_colour_list, set_style};
use widgets::WidgetStyle;
Expand Down Expand Up @@ -141,7 +142,7 @@ impl Styles {
Some(theme) => Self::from_theme(theme)?,
None => match config.styles.as_ref().and_then(|s| s.theme.as_ref()) {
Some(theme) => Self::from_theme(theme)?,
None => Self::default(),
None => Self::from_theme("default")?,
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Any reason to change this line?

Copy link
Copy Markdown
Author

@rashil2000 rashil2000 Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self::default() here will skip automatic detection if the user has no theme specified in the config file.

},
};

Expand All @@ -155,13 +156,29 @@ impl Styles {

fn from_theme(theme: &str) -> anyhow::Result<Self> {
let lower_case = theme.to_lowercase();

// Detect terminal theme mode.
// Prefer dark palette if detection fails.
let is_dark = theme_mode(QueryOptions::default())
.map(|mode| mode == ThemeMode::Dark)
.unwrap_or(true);

match lower_case.as_str() {
"default" => Ok(Self::default_style()),
"default-light" => Ok(Self::default_light_mode()),
"gruvbox" => Ok(Self::gruvbox_palette()),
"gruvbox-light" => Ok(Self::gruvbox_light_palette()),
"nord" => Ok(Self::nord_palette()),
"nord-light" => Ok(Self::nord_light_palette()),
"default" => Ok(if is_dark {
Self::default_style()
} else {
Self::default_light_mode()
}),
"gruvbox" => Ok(if is_dark {
Self::gruvbox_palette()
} else {
Self::gruvbox_light_palette()
}),
"nord" => Ok(if is_dark {
Self::nord_palette()
} else {
Self::nord_light_palette()
}),
_ => Err(
OptionError::other(format!("'{theme}' is an invalid built-in color scheme."))
.into(),
Expand Down Expand Up @@ -270,10 +287,41 @@ mod test {
#[test]
fn built_in_colour_schemes_work() {
Styles::from_theme("default").unwrap();
Styles::from_theme("default-light").unwrap();
Styles::from_theme("gruvbox").unwrap();
Styles::from_theme("gruvbox-light").unwrap();
Styles::from_theme("nord").unwrap();
Styles::from_theme("nord-light").unwrap();
}

#[test]
fn invalid_theme_returns_error() {
let result = Styles::from_theme("nonexistent-theme");
assert!(result.is_err());
assert!(
result
.unwrap_err()
.to_string()
.contains("invalid built-in color scheme")
);
}

#[test]
fn theme_case_insensitive() {
// Theme names should work regardless of case
Styles::from_theme("DEFAULT").unwrap();
Styles::from_theme("GruvBox").unwrap();
Styles::from_theme("NORD").unwrap();
}

#[test]
fn theme_detection_does_not_panic() {
// Ensure theme detection doesn't panic in non-interactive environments (CI)
// This verifies the .unwrap_or(true) fallback works correctly
let default_style = Styles::from_theme("default").unwrap();
let gruvbox_style = Styles::from_theme("gruvbox").unwrap();
let nord_style = Styles::from_theme("nord").unwrap();

// Verify styles have expected color properties set (not all default)
assert_ne!(default_style.ram_style, Style::default());
assert_ne!(gruvbox_style.ram_style, Style::default());
assert_ne!(nord_style.ram_style, Style::default());
}
}
3 changes: 0 additions & 3 deletions tests/valid_configs/styling_2.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@

# Built-in themes. Valid values are:
# - "default"
# - "default-light"
# - "gruvbox"
# - "gruvbox-light"
# - "nord"
# - "nord-light".

# This will have the lowest precedence if a custom colour palette is set,
# or overriden if the command-line flag for a built-in theme is set.
Expand Down