Enable 24-bit RGB colors by default

I think `set_color ff0000` should default to outputting true-color sequences.
Unfortunately there is no good and widely-supported way to query for true-color
support.  `COLORTERM=truecolor` doesn't work in some cases such as ssh.

Since many terminals nowadays implement the RGB sequences, let's try using
them by default.

Note that Emacs's ansi-term implements truecolor now.

See also the discussion around
https://github.com/fish-shell/fish-shell/pull/11345#issuecomment-2794920900

Closes #11372
This commit is contained in:
Johannes Altmanninger
2025-04-11 13:29:49 +02:00
parent e7270915ac
commit 6fcb418ae3
4 changed files with 37 additions and 56 deletions

View File

@@ -26,6 +26,11 @@ Deprecations and removed features
set -Ua fish_features no-ignore-terminfo
- The `--install` option when fish is built as self-installable was removed. If you need to write out fish's data you can use the new `status list-files` and `status get-file` subcommands, but it should no longer be necessary. (:issue:`11143`)
- RGB colors (``set_color ff0000``) now default to using 24-bit RGB true-color commands, even if the terminal does not advertise support via ``COLORTERM``.
- To go back to using the nearest match from the 256-color palette, use ``set fish_term24bit 0`` or ``set COLORTERM 0``.
- To make the nearest-match logic use the 16 color palette instead, use ``set fish_term256 0``.
- Inside macOS Terminal.app, fish makes an attempt to still use the palette colors.
If that doesn't work, use ``set fish_term24bit 0``.
Scripting improvements
----------------------

View File

@@ -22,7 +22,13 @@ Valid colors include:
The *br*- (as in 'bright') forms are full-brightness variants of the 8 standard-brightness colors on many terminals. **brblack** has higher brightness than **black** - towards gray.
An RGB value with three or six hex digits, such as A0FF33 or f2f can be used. Fish will choose the closest supported color. A three digit value is equivalent to specifying each digit twice; e.g., ``set_color 2BC`` is the same as ``set_color 22BBCC``. Hexadecimal RGB values can be in lower or uppercase. Depending on the capabilities of your terminal (and the level of support ``set_color`` has for it) the actual color may be approximated by a nearby matching reserved color.
An RGB value with three or six hex digits, such as A0FF33 or f2f can be used.
A three digit value is equivalent to specifying each digit twice; e.g., ``set_color 2BC`` is the same as ``set_color 22BBCC``.
Hexadecimal RGB values can be in lower or uppercase.
If :envvar:`fish_term24bit` is set to 0, fish will translate RGB values to the nearest color on the 256-color palette.
If :envvar:`fish_term256` is also set to 0, fish will translate them to the 16-color palette instead.
Fish launched as ``fish -d term_support`` will include diagnostic messages that indicate the color support mode in use.
A second color may be given as a desired fallback color. e.g. ``set_color 124212 brblue`` will instruct set_color to use *brblue* if a terminal is not capable of the exact shade of grey desired. This is very useful when an 8 or 16 color terminal might otherwise not use a color.
@@ -72,17 +78,3 @@ Examples
set_color blue; echo "Violets are blue"
set_color 62A; echo "Eggplants are dark purple"
set_color normal; echo "Normal is nice" # Resets the background too
Terminal Capability Detection
-----------------------------
Fish uses some heuristics to determine what colors a terminal supports to avoid sending sequences that it won't understand.
In particular it will:
- Enable 24-bit ("true-color") even if the $TERM entry only reports 256 colors. This includes modern xterm, VTE-based terminals like Gnome Terminal, Konsole and iTerm2.
To force true-color support on or off, set :envvar:`fish_term24bit` to "1" for on and 0 for off - ``set -g fish_term24bit 1``.
Fish launched as ``fish -d term_support`` will include diagnostic messages that indicate the color support mode in use.

View File

@@ -1566,12 +1566,12 @@ You can change the settings of fish by changing the values of certain variables.
.. envvar:: fish_term24bit
If this is set to 1, fish will assume the terminal understands 24-bit RGB color sequences, and won't translate them to the 256 or 16 color palette.
This is often detected automatically.
If this is set to 0, fish will not output 24-bit RGB true-color sequences but the nearest color on the 256 color palette (or the 16 color palette, if :envvar:`fish_term256` is 0).
.. envvar:: fish_term256
If this is set to 0, fish will not output 256 colors, but translate colors down to the 16 color palette.
If this is set to 0 and :envvar:`fish_term24bit` is 0, translate RGB colors down to the 16 color palette.
Also, if this is set to 0, :doc:`set_color <cmds/set_color>`/` commands such as ``set_color ff0000 red`` will prefer the named color.
.. envvar:: fish_ambiguous_width

View File

@@ -382,6 +382,7 @@ fn update_fish_color_support(vars: &EnvStack) {
let term = vars.get_unless_empty(L!("TERM"));
let term = term.as_ref().map_or(L!(""), |term| &term.as_list()[0]);
let is_xterm_16color = term == "xterm-16color";
let supports_256color = if let Some(fish_term256) = vars.get(L!("fish_term256")) {
let ok = crate::wcstringutil::bool_from_string(&fish_term256.as_string());
@@ -392,10 +393,10 @@ fn update_fish_color_support(vars: &EnvStack) {
);
ok
} else {
term != "xterm-16color"
!is_xterm_16color
};
let mut supports_24bit = false;
let supports_24bit;
if let Some(fish_term24bit) = vars.get(L!("fish_term24bit")).map(|v| v.as_string()) {
// $fish_term24bit
supports_24bit = crate::wcstringutil::bool_from_string(&fish_term24bit);
@@ -408,19 +409,14 @@ fn update_fish_color_support(vars: &EnvStack) {
"disabled"
}
);
} else if vars.get(L!("STY")).is_some() || term.starts_with(L!("eterm")) {
// Screen and emacs' ansi-term swallow true-color sequences, so we ignore them unless
// force-enabled.
} else if vars.get(L!("STY")).is_some() {
// Screen requires "truecolor on" to enable true-color sequences, so we ignore them
// unless force-enabled.
supports_24bit = false;
FLOG!(
term_support,
"True-color support: disabled for eterm/screen"
);
FLOG!(term_support, "True-color support: disabled for screen");
} else if let Some(ct) = vars.get(L!("COLORTERM")).map(|v| v.as_string()) {
// If someone sets $COLORTERM, that's the sort of color they want.
if ct == "truecolor" || ct == "24bit" {
supports_24bit = true;
}
supports_24bit = ct == "truecolor" || ct == "24bit";
FLOG!(
term_support,
"True-color support",
@@ -432,32 +428,20 @@ fn update_fish_color_support(vars: &EnvStack) {
"per $COLORTERM",
ct
);
} else if vars.get(L!("KONSOLE_VERSION")).is_some()
|| vars.get(L!("KONSOLE_PROFILE_NAME")).is_some()
{
// All Konsole versions that use $KONSOLE_VERSION are new enough to support this, so no
// check is needed.
supports_24bit = true;
FLOG!(term_support, "True-color support: enabled for Konsole");
} else if let Some(it) = vars.get(L!("ITERM_SESSION_ID")).map(|v| v.as_string()) {
// Supporting versions of iTerm include a colon here.
// We assume that if this is iTerm it can't also be st, so having this check inside is okay.
if !it.contains(':') {
supports_24bit = true;
FLOG!(term_support, "True-color support: enabled for iTerm");
}
} else if term.starts_with("st-") {
supports_24bit = true;
FLOG!(term_support, "True-color support: enabling for st");
} else if let Some(vte) = vars.get(L!("VTE_VERSION")).map(|v| v.as_string()) {
if fish_wcstoi(&vte).unwrap_or(0) > 3600 {
supports_24bit = true;
FLOG!(
term_support,
"True-color support: enabled for VTE version",
vte
);
}
} else {
supports_24bit = !is_xterm_16color
&& !vars
.get_unless_empty(L!("TERM_PROGRAM"))
.is_some_and(|term| term.as_list()[0] == "Apple_Terminal");
FLOG!(
term_support,
"True-color support",
if supports_24bit {
"enabled"
} else {
"disabled"
},
);
}
let mut color_support = ColorSupport::default();