Use default color in default theme for light-theme terminals (#16509)

Closes #16477
Closes #15847

Change the default theme to use the ANSI default color (`39m`) instead
of white (`37m`).
The goal of this is to improve readability on light-theme terminals.

I tested this change across **5 dark themes** (Catppuccin Mocha, Ayu
Mirage, Tokyo Night, Dracula, Apprentice) and **5 light themes**
(Catppuccin Latte, Gruvbox Light, Solarized Light, Tokyo Night Day,
Paper Color Light), in both **foot** and **alacritty** terminals.

- On most dark themes, there is little to no visual difference
(sometimes slightly better contrast).
- On light themes (e.g. Solarized Light), switching to the default color
makes text significantly more readable.

I attached a screenshot below using Solarized Light in alacritty.  
The left side is using white color while the right side shows the new
change using default color:

<img width="1351" height="507" alt="Comparison of white vs default color
on Solarized Light theme"
src="https://github.com/user-attachments/assets/db80fe07-0cea-4a4b-ba14-e6a31f29cfe1"
/>

## Release notes summary

Improve the colors in the default theme for light-theme terminals by
switching from white to default color.


## Tasks after submitting



N/A
This commit is contained in:
Paul Pare
2025-08-26 06:08:35 +08:00
committed by GitHub
parent ca0e9614ad
commit 61e9f8780e
7 changed files with 113 additions and 113 deletions

View File

@@ -18,7 +18,7 @@ pub fn default_shape_color(shape: &str) -> Style {
"shape_filepath" => Style::new().fg(Color::Cyan),
"shape_flag" => Style::new().fg(Color::Blue).bold(),
"shape_float" => Style::new().fg(Color::Purple).bold(),
"shape_garbage" => Style::new().fg(Color::White).on(Color::Red).bold(),
"shape_garbage" => Style::new().fg(Color::Default).on(Color::Red).bold(),
"shape_glob_interpolation" => Style::new().fg(Color::Cyan).bold(),
"shape_globpattern" => Style::new().fg(Color::Cyan).bold(),
"shape_int" => Style::new().fg(Color::Purple).bold(),

View File

@@ -113,27 +113,27 @@ impl<'a> StyleComputer<'a> {
// Create the hashmap
#[rustfmt::skip]
let mut map: StyleMapping = [
("separator".to_string(), ComputableStyle::Static(Color::White.normal())),
("separator".to_string(), ComputableStyle::Static(Color::Default.normal())),
("leading_trailing_space_bg".to_string(), ComputableStyle::Static(Style::default().on(Color::Rgb(128, 128, 128)))),
("header".to_string(), ComputableStyle::Static(Color::Green.bold())),
("empty".to_string(), ComputableStyle::Static(Color::Blue.normal())),
("bool".to_string(), ComputableStyle::Static(Color::LightCyan.normal())),
("int".to_string(), ComputableStyle::Static(Color::White.normal())),
("int".to_string(), ComputableStyle::Static(Color::Default.normal())),
("filesize".to_string(), ComputableStyle::Static(Color::Cyan.normal())),
("duration".to_string(), ComputableStyle::Static(Color::White.normal())),
("duration".to_string(), ComputableStyle::Static(Color::Default.normal())),
("datetime".to_string(), ComputableStyle::Static(Color::Purple.normal())),
("range".to_string(), ComputableStyle::Static(Color::White.normal())),
("float".to_string(), ComputableStyle::Static(Color::White.normal())),
("string".to_string(), ComputableStyle::Static(Color::White.normal())),
("nothing".to_string(), ComputableStyle::Static(Color::White.normal())),
("binary".to_string(), ComputableStyle::Static(Color::White.normal())),
("cell-path".to_string(), ComputableStyle::Static(Color::White.normal())),
("range".to_string(), ComputableStyle::Static(Color::Default.normal())),
("float".to_string(), ComputableStyle::Static(Color::Default.normal())),
("string".to_string(), ComputableStyle::Static(Color::Default.normal())),
("nothing".to_string(), ComputableStyle::Static(Color::Default.normal())),
("binary".to_string(), ComputableStyle::Static(Color::Default.normal())),
("cell-path".to_string(), ComputableStyle::Static(Color::Default.normal())),
("row_index".to_string(), ComputableStyle::Static(Color::Green.bold())),
("record".to_string(), ComputableStyle::Static(Color::White.normal())),
("list".to_string(), ComputableStyle::Static(Color::White.normal())),
("block".to_string(), ComputableStyle::Static(Color::White.normal())),
("record".to_string(), ComputableStyle::Static(Color::Default.normal())),
("list".to_string(), ComputableStyle::Static(Color::Default.normal())),
("block".to_string(), ComputableStyle::Static(Color::Default.normal())),
("hints".to_string(), ComputableStyle::Static(Color::DarkGray.normal())),
("search_result".to_string(), ComputableStyle::Static(Color::White.normal().on(Color::Red))),
("search_result".to_string(), ComputableStyle::Static(Color::Default.normal().on(Color::Red))),
].into_iter().collect();
for (key, value) in &config.color_config {

View File

@@ -75,7 +75,7 @@ impl Command for Find {
description: "Search and highlight text for a term in a string.",
example: r#"'Cargo.toml' | find Cargo"#,
result: Some(Value::test_string(
"\u{1b}[37m\u{1b}[0m\u{1b}[41;37mCargo\u{1b}[0m\u{1b}[37m.toml\u{1b}[0m"
"\u{1b}[39m\u{1b}[0m\u{1b}[41;39mCargo\u{1b}[0m\u{1b}[39m.toml\u{1b}[0m"
.to_owned(),
)),
},
@@ -93,10 +93,10 @@ impl Command for Find {
result: Some(Value::list(
vec![
Value::test_string(
"\u{1b}[37m\u{1b}[0m\u{1b}[41;37ml\u{1b}[0m\u{1b}[37marry\u{1b}[0m",
"\u{1b}[39m\u{1b}[0m\u{1b}[41;39ml\u{1b}[0m\u{1b}[39marry\u{1b}[0m",
),
Value::test_string(
"\u{1b}[37mcur\u{1b}[0m\u{1b}[41;37ml\u{1b}[0m\u{1b}[37my\u{1b}[0m",
"\u{1b}[39mcur\u{1b}[0m\u{1b}[41;39ml\u{1b}[0m\u{1b}[39my\u{1b}[0m",
),
],
Span::test_data(),
@@ -108,11 +108,11 @@ impl Command for Find {
result: Some(Value::list(
vec![
Value::test_string(
"\u{1b}[37ma\u{1b}[0m\u{1b}[41;37mbc\u{1b}[0m\u{1b}[37m\u{1b}[0m"
"\u{1b}[39ma\u{1b}[0m\u{1b}[41;39mbc\u{1b}[0m\u{1b}[39m\u{1b}[0m"
.to_string(),
),
Value::test_string(
"\u{1b}[37ma\u{1b}[0m\u{1b}[41;37mbf\u{1b}[0m\u{1b}[37m\u{1b}[0m"
"\u{1b}[39ma\u{1b}[0m\u{1b}[41;39mbf\u{1b}[0m\u{1b}[39m\u{1b}[0m"
.to_string(),
),
],
@@ -125,11 +125,11 @@ impl Command for Find {
result: Some(Value::list(
vec![
Value::test_string(
"\u{1b}[37m\u{1b}[0m\u{1b}[41;37maB\u{1b}[0m\u{1b}[37mc\u{1b}[0m"
"\u{1b}[39m\u{1b}[0m\u{1b}[41;39maB\u{1b}[0m\u{1b}[39mc\u{1b}[0m"
.to_string(),
),
Value::test_string(
"\u{1b}[37m\u{1b}[0m\u{1b}[41;37mab\u{1b}[0m\u{1b}[37mf\u{1b}[0m"
"\u{1b}[39m\u{1b}[0m\u{1b}[41;39mab\u{1b}[0m\u{1b}[39mf\u{1b}[0m"
.to_string(),
),
],
@@ -141,7 +141,7 @@ impl Command for Find {
example: r#"[[version name]; ['0.1.0' nushell] ['0.1.1' fish] ['0.2.0' zsh]] | find --regex "nu""#,
result: Some(Value::test_list(vec![Value::test_record(record! {
"version" => Value::test_string("0.1.0"),
"name" => Value::test_string("\u{1b}[37m\u{1b}[0m\u{1b}[41;37mnu\u{1b}[0m\u{1b}[37mshell\u{1b}[0m".to_string()),
"name" => Value::test_string("\u{1b}[39m\u{1b}[0m\u{1b}[41;39mnu\u{1b}[0m\u{1b}[39mshell\u{1b}[0m".to_string()),
})])),
},
Example {
@@ -165,7 +165,7 @@ impl Command for Find {
vec![Value::list(
vec![
Value::test_string(
"\u{1b}[37mLa\u{1b}[0m\u{1b}[41;37mrr\u{1b}[0m\u{1b}[37my\u{1b}[0m",
"\u{1b}[39mLa\u{1b}[0m\u{1b}[41;39mrr\u{1b}[0m\u{1b}[39my\u{1b}[0m",
),
Value::test_string("Moe"),
],
@@ -202,7 +202,7 @@ impl Command for Find {
result: Some(Value::list(
vec![Value::test_record(record! {
"col1" => Value::test_string(
"\u{1b}[37m\u{1b}[0m\u{1b}[41;37mmoe\u{1b}[0m\u{1b}[37m\u{1b}[0m"
"\u{1b}[39m\u{1b}[0m\u{1b}[41;39mmoe\u{1b}[0m\u{1b}[39m\u{1b}[0m"
.to_string(),
),
"col2" => Value::test_string("larry".to_string()),
@@ -217,10 +217,10 @@ impl Command for Find {
result: Some(Value::list(
vec![
Value::test_string(
"\u{1b}[37mAnd roses are bl\u{1b}[0m\u{1b}[41;37mue\u{1b}[0m\u{1b}[37m\u{1b}[0m",
"\u{1b}[39mAnd roses are bl\u{1b}[0m\u{1b}[41;39mue\u{1b}[0m\u{1b}[39m\u{1b}[0m",
),
Value::test_string(
"\u{1b}[37mAlter their h\u{1b}[0m\u{1b}[41;37mue\u{1b}[0m\u{1b}[37m\u{1b}[0m",
"\u{1b}[39mAlter their h\u{1b}[0m\u{1b}[41;39mue\u{1b}[0m\u{1b}[39m\u{1b}[0m",
),
],
Span::test_data(),
@@ -230,7 +230,7 @@ impl Command for Find {
description: "Find in a multi-line string without splitting the input into a list of lines",
example: r#""Violets are red\nAnd roses are blue\nWhen metamaterials\nAlter their hue" | find --multiline "ue""#,
result: Some(Value::test_string(
"\u{1b}[37mViolets are red\nAnd roses are bl\u{1b}[0m\u{1b}[41;37mue\u{1b}[0m\u{1b}[37m\nWhen metamaterials\nAlter their h\u{1b}[0m\u{1b}[41;37mue\u{1b}[0m\u{1b}[37m\u{1b}[0m",
"\u{1b}[39mViolets are red\nAnd roses are bl\u{1b}[0m\u{1b}[41;39mue\u{1b}[0m\u{1b}[39m\nWhen metamaterials\nAlter their h\u{1b}[0m\u{1b}[41;39mue\u{1b}[0m\u{1b}[39m\u{1b}[0m",
)),
},
]

View File

@@ -7,7 +7,7 @@ fn find_with_list_search_with_string() {
assert_eq!(
actual.out,
"\u{1b}[37m\u{1b}[0m\u{1b}[41;37mmoe\u{1b}[0m\u{1b}[37m\u{1b}[0m"
"\u{1b}[39m\u{1b}[0m\u{1b}[41;39mmoe\u{1b}[0m\u{1b}[39m\u{1b}[0m"
);
assert_eq!(actual_no_highlight.out, "moe");
}
@@ -19,7 +19,7 @@ fn find_with_list_search_with_char() {
assert_eq!(
actual.out,
"[\"\\u001b[37m\\u001b[0m\\u001b[41;37ml\\u001b[0m\\u001b[37marry\\u001b[0m\",\"\\u001b[37mcur\\u001b[0m\\u001b[41;37ml\\u001b[0m\\u001b[37my\\u001b[0m\"]"
"[\"\\u001b[39m\\u001b[0m\\u001b[41;39ml\\u001b[0m\\u001b[39marry\\u001b[0m\",\"\\u001b[39mcur\\u001b[0m\\u001b[41;39ml\\u001b[0m\\u001b[39my\\u001b[0m\"]"
);
assert_eq!(actual_no_highlight.out, "[\"larry\",\"curly\"]");
}
@@ -35,7 +35,7 @@ fn find_with_bytestream_search_with_char() {
assert_eq!(
actual.out,
"\u{1b}[37m\u{1b}[0m\u{1b}[41;37mABC\u{1b}[0m\u{1b}[37m\u{1b}[0m"
"\u{1b}[39m\u{1b}[0m\u{1b}[41;39mABC\u{1b}[0m\u{1b}[39m\u{1b}[0m"
);
assert_eq!(actual_no_highlight.out, "ABC");
}
@@ -56,7 +56,7 @@ fn find_with_string_search_with_string() {
assert_eq!(
actual.out,
"\u{1b}[37mCargo.\u{1b}[0m\u{1b}[41;37mtoml\u{1b}[0m\u{1b}[37m\u{1b}[0m"
"\u{1b}[39mCargo.\u{1b}[0m\u{1b}[41;39mtoml\u{1b}[0m\u{1b}[39m\u{1b}[0m"
);
assert_eq!(actual_no_highlight.out, "Cargo.toml");
}
@@ -80,7 +80,7 @@ fn find_with_filepath_search_with_string() {
assert_eq!(
actual.out,
"[\"\\u001b[37m\\u001b[0m\\u001b[41;37marep\\u001b[0m\\u001b[37mas.clu\\u001b[0m\"]"
"[\"\\u001b[39m\\u001b[0m\\u001b[41;39marep\\u001b[0m\\u001b[39mas.clu\\u001b[0m\"]"
);
assert_eq!(actual_no_highlight.out, "[\"arepas.clu\"]");
}
@@ -95,7 +95,7 @@ fn find_with_filepath_search_with_multiple_patterns() {
assert_eq!(
actual.out,
"[\"\\u001b[37m\\u001b[0m\\u001b[41;37mami\\u001b[0m\\u001b[37mgos.txt\\u001b[0m\",\"\\u001b[37m\\u001b[0m\\u001b[41;37marep\\u001b[0m\\u001b[37mas.clu\\u001b[0m\"]"
"[\"\\u001b[39m\\u001b[0m\\u001b[41;39mami\\u001b[0m\\u001b[39mgos.txt\\u001b[0m\",\"\\u001b[39m\\u001b[0m\\u001b[41;39marep\\u001b[0m\\u001b[39mas.clu\\u001b[0m\"]"
);
assert_eq!(actual_no_highlight.out, "[\"amigos.txt\",\"arepas.clu\"]");
}
@@ -121,7 +121,7 @@ fn find_with_regex_in_table_keeps_row_if_one_column_matches() {
assert_eq!(
actual.out,
r#"["\u001b[37mMauri\u001b[0m\u001b[41;37mce\u001b[0m\u001b[37m\u001b[0m","\u001b[37mLauren\u001b[0m\u001b[41;37mce\u001b[0m\u001b[37m\u001b[0m"]"#
r#"["\u001b[39mMauri\u001b[0m\u001b[41;39mce\u001b[0m\u001b[39m\u001b[0m","\u001b[39mLauren\u001b[0m\u001b[41;39mce\u001b[0m\u001b[39m\u001b[0m"]"#
);
assert_eq!(actual_no_highlight.out, r#"["Maurice","Laurence"]"#);
}
@@ -225,7 +225,7 @@ fn find_with_string_search_with_special_char_1() {
assert_eq!(
actual.out,
"[{\"d\":\"\\u001b[37ma\\u001b[0m\\u001b[41;37m?\\u001b[0m\\u001b[37mb\\u001b[0m\"}]"
"[{\"d\":\"\\u001b[39ma\\u001b[0m\\u001b[41;39m?\\u001b[0m\\u001b[39mb\\u001b[0m\"}]"
);
assert_eq!(actual_no_highlight.out, "[{\"d\":\"a?b\"}]");
}
@@ -238,7 +238,7 @@ fn find_with_string_search_with_special_char_2() {
assert_eq!(
actual.out,
"[{\"d\":\"\\u001b[37ma\\u001b[0m\\u001b[41;37m*\\u001b[0m\\u001b[37mb\\u001b[0m\"}]"
"[{\"d\":\"\\u001b[39ma\\u001b[0m\\u001b[41;39m*\\u001b[0m\\u001b[39mb\\u001b[0m\"}]"
);
assert_eq!(actual_no_highlight.out, "[{\"d\":\"a*b\"}]");
}
@@ -251,7 +251,7 @@ fn find_with_string_search_with_special_char_3() {
assert_eq!(
actual.out,
"[{\"d\":\"\\u001b[37ma\\u001b[0m\\u001b[41;37m{1}\\u001b[0m\\u001b[37mb\\u001b[0m\"}]"
"[{\"d\":\"\\u001b[39ma\\u001b[0m\\u001b[41;39m{1}\\u001b[0m\\u001b[39mb\\u001b[0m\"}]"
);
assert_eq!(actual_no_highlight.out, "[{\"d\":\"a{1}b\"}]");
}
@@ -264,7 +264,7 @@ fn find_with_string_search_with_special_char_4() {
assert_eq!(
actual.out,
"[{\"d\":\"\\u001b[37ma\\u001b[0m\\u001b[41;37m[\\u001b[0m\\u001b[37m]b\\u001b[0m\"}]"
"[{\"d\":\"\\u001b[39ma\\u001b[0m\\u001b[41;39m[\\u001b[0m\\u001b[39m]b\\u001b[0m\"}]"
);
assert_eq!(actual_no_highlight.out, "[{\"d\":\"a[]b\"}]");
}
@@ -277,7 +277,7 @@ fn find_with_string_search_with_special_char_5() {
assert_eq!(
actual.out,
"[{\"d\":\"\\u001b[37ma[\\u001b[0m\\u001b[41;37m]\\u001b[0m\\u001b[37mb\\u001b[0m\"}]"
"[{\"d\":\"\\u001b[39ma[\\u001b[0m\\u001b[41;39m]\\u001b[0m\\u001b[39mb\\u001b[0m\"}]"
);
assert_eq!(actual_no_highlight.out, "[{\"d\":\"a[]b\"}]");
}
@@ -290,7 +290,7 @@ fn find_with_string_search_with_special_char_6() {
assert_eq!(
actual.out,
"[{\"d\":\"\\u001b[37ma\\u001b[0m\\u001b[41;37m[]\\u001b[0m\\u001b[37mb\\u001b[0m\"}]"
"[{\"d\":\"\\u001b[39ma\\u001b[0m\\u001b[41;39m[]\\u001b[0m\\u001b[39mb\\u001b[0m\"}]"
);
assert_eq!(actual_no_highlight.out, "[{\"d\":\"a[]b\"}]");
}
@@ -308,6 +308,6 @@ fn find_and_highlight_in_nested_list() {
assert_eq!(
actual.out,
r#"[["\u001b[37m\u001b[0m\u001b[41;37mfoo\u001b[0m\u001b[37m\u001b[0m","bar"],["\u001b[37m\u001b[0m\u001b[41;37mfoo\u001b[0m\u001b[37m\u001b[0m","baz"]]"#
r#"[["\u001b[39m\u001b[0m\u001b[41;39mfoo\u001b[0m\u001b[39m\u001b[0m","bar"],["\u001b[39m\u001b[0m\u001b[41;39mfoo\u001b[0m\u001b[39m\u001b[0m","baz"]]"#
);
}

File diff suppressed because one or more lines are too long

View File

@@ -2,7 +2,7 @@
export def dark-theme [] {
{
# color for nushell primitives
separator: white
separator: default
leading_trailing_space_bg: { attr: n } # no fg, no bg, attr none effectively turns this off
header: green_bold
empty: blue
@@ -10,20 +10,20 @@ export def dark-theme [] {
# The value (in this case, a bool) is piped into the closure.
# eg) {|| if $in { 'light_cyan' } else { 'light_gray' } }
bool: light_cyan
int: white
int: default
filesize: cyan
duration: white
duration: default
datetime: purple
range: white
float: white
string: white
nothing: white
binary: white
cell-path: white
range: default
float: default
string: default
nothing: default
binary: default
cell-path: default
row_index: green_bold
record: white
list: white
block: white
record: default
list: default
block: default
hints: dark_gray
search_result: { bg: red fg: white }
shape_binary: purple_bold

View File

@@ -2,29 +2,29 @@
#
# version = "0.106.2"
$env.config.color_config = {
separator: white
separator: default
leading_trailing_space_bg: { attr: n }
header: green_bold
empty: blue
bool: light_cyan
int: white
int: default
filesize: cyan
duration: white
duration: default
datetime: purple
range: white
float: white
string: white
nothing: white
binary: white
cell-path: white
range: default
float: default
string: default
nothing: default
binary: default
cell-path: default
row_index: green_bold
record: white
list: white
record: default
list: default
closure: green_bold
glob:cyan_bold
block: white
block: default
hints: dark_gray
search_result: { bg: red fg: white }
search_result: { bg: red fg: default }
shape_binary: purple_bold
shape_block: blue_bold
shape_bool: light_cyan
@@ -61,7 +61,7 @@ $env.config.color_config = {
shape_vardecl: purple
shape_raw_string: light_purple
shape_garbage: {
fg: white
fg: default
bg: red
attr: b
}