Merge color scheme options into theme / BAT_THEME

This commit is contained in:
Tau Gärtli 2024-08-18 14:59:14 +02:00
parent b9b981f657
commit bc42149a72
No known key found for this signature in database
12 changed files with 83 additions and 142 deletions

View File

@ -32,7 +32,6 @@ Register-ArgumentCompleter -Native -CommandName '{{PROJECT_EXECUTABLE}}' -Script
[CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'When to use colors (*auto*, never, always).')
[CompletionResult]::new('--italic-text', 'italic-text', [CompletionResultType]::ParameterName, 'Use italics in output (always, *never*)')
[CompletionResult]::new('--decorations', 'decorations', [CompletionResultType]::ParameterName, 'When to show the decorations (*auto*, never, always).')
[CompletionResult]::new('--color-scheme', 'color-scheme', [CompletionResultType]::ParameterName, 'Whether to choose a dark or light syntax highlighting theme (*auto*, auto:always, dark, light, system).')
[CompletionResult]::new('--paging', 'paging', [CompletionResultType]::ParameterName, 'Specify when to use the pager, or use `-P` to disable (*auto*, never, always).')
[CompletionResult]::new('--pager', 'pager', [CompletionResultType]::ParameterName, 'Determine which pager to use.')
[CompletionResult]::new('-m', 'm', [CompletionResultType]::ParameterName, 'Use the specified syntax for files matching the glob pattern (''*.cpp:C++'').')

View File

@ -104,8 +104,6 @@ _bat() {
COMPREPLY=($(compgen -W "auto never always" -- "$cur"))
return 0
;;
--color-scheme)
COMPREPLY=($(compgen -W "auto auto:always dark light system" -- "$cur"))
--italic-text)
COMPREPLY=($(compgen -W "always never" -- "$cur"))
return 0
@ -176,7 +174,6 @@ _bat() {
--theme
--theme-dark
--theme-light
--color-scheme
--list-themes
--squeeze-blank
--squeeze-limit

View File

@ -99,13 +99,6 @@ set -l color_opts '
'
set -l decorations_opts $color_opts
set -l paging_opts $color_opts
set -l color_scheme_opts "
auto\t'Use the terminal\'s color scheme if the output is not redirected (default)'
auto:always\t'Always use the terminal\'s color scheme'
dark\t'Use a dark syntax highlighting theme'
light\t'Use a light syntax highlighting theme'
system\t'Query the OS for its color scheme (macOS only)'
"
# Include some examples so we can indicate the default.
set -l pager_opts '
@ -150,8 +143,6 @@ complete -c $bat -l config-file -f -d "Display location of configuration file" -
complete -c $bat -l decorations -x -a "$decorations_opts" -d "When to use --style decorations" -n __bat_no_excl_args
complete -c $bat -l color-scheme -x -a "$color_scheme_opts" -d "Whether to choose a dark or light syntax highlighting theme" -n __bat_no_excl_args
complete -c $bat -l diagnostic -d "Print diagnostic info for bug reports" -n __fish_is_first_arg
complete -c $bat -s d -l diff -d "Only show lines with Git changes" -n __bat_no_excl_args

View File

@ -40,7 +40,6 @@ _{{PROJECT_EXECUTABLE}}_main() {
--color='[specify when to use colors]:when:(auto never always)'
--italic-text='[use italics in output]:when:(always never)'
--decorations='[specify when to show the decorations]:when:(auto never always)'
--color-scheme="[whether to choose a dark or light syntax highlighting theme]:scheme:(auto auto:always dark light system)"
--paging='[specify when to use the pager]:when:(auto never always)'
'(-m --map-syntax)'{-m+,--map-syntax=}'[map a glob pattern to an existing syntax name]: :->syntax-maps'
'(--theme)'--theme='[set the color theme for syntax highlighting]:theme:->themes'

View File

@ -117,24 +117,6 @@ Specify when to use the decorations that have been specified via '\-\-style'. Th
automatic mode only enables decorations if an interactive terminal is detected. Possible
values: *auto*, never, always.
.HP
\fB\-\-detect\-color\-scheme\fR <when>
.IP
Specify when to query the terminal for its colors in order to pick an appropriate syntax
highlighting theme. Use \fB\-\-theme-light\fP and \fB\-\-theme-dark\fP (or the environment variables
\fBBAT_THEME_LIGHT\fP and \fBBAT_THEME_DARK\fP) to configure which themes are picked. You can also use
\fP\-\-theme\fP to set a theme that is used regardless of the terminal's colors.
.IP
\fI<when>\fP can be one of:
.RS
.IP "\fBauto\fP"
Only query the terminals colors if the output is not redirected. This is to prevent
race conditions with pagers such as less.
.IP "never"
Never query the terminal for its colors and assume that the terminal has a dark background.
.IP "always"
Always query the terminal for its colors, regardless of whether or not the output is redirected.
.RE
.HP
\fB\-f\fR, \fB\-\-force\-colorization\fR
.IP
Alias for '--decorations=always --color=always'. This is useful \
@ -177,14 +159,14 @@ export the \fBBAT_THEME\fP environment variable (e.g.: \fBexport BAT_THEME="..."
\fB\-\-theme\-dark\fR <theme>
.IP
Sets the theme name for syntax highlighting used when the terminal uses a dark background.
To set a default theme, add the \fB\-\-theme-dark="..."\fP option to the configuration file or
To set a default theme, add the \fB\-\-theme-dark="..."\fP option to the configuration file or
export the \fBBAT_THEME_DARK\fP environment variable (e.g. \fBexport BAT_THEME_DARK="..."\fP).
This option is ignored if \fB\-\-theme\fP option is set.
.HP
\fB\-\-theme\-light\fR <theme>
.IP
Sets the theme name for syntax highlighting used when the terminal uses a dark background.
To set a default theme, add the \fB\-\-theme-dark="..."\fP option to the configuration file or
To set a default theme, add the \fB\-\-theme-dark="..."\fP option to the configuration file or
export the \fBBAT_THEME_LIGHT\fP environment variable (e.g. \fBexport BAT_THEME_LIGHT="..."\fP).
This option is ignored if \fB\-\-theme\fP option is set.
.HP
@ -339,7 +321,7 @@ To use the preprocessor, call:
\fB{{PROJECT_EXECUTABLE}} --lessopen\fR
Alternatively, the preprocessor may be enabled by default by adding the '\-\-lessopen' option to the configuration file.
Alternatively, the preprocessor may be enabled by default by adding the '\-\-lessopen' option to the configuration file.
To temporarily disable the preprocessor if it is enabled by default, call:
@ -355,7 +337,7 @@ Enable the $LESSOPEN preprocessor.
.IP
Disable the $LESSOPEN preprocessor if enabled (overrides --lessopen)
.PP
For more information, see the "INPUT PREPROCESSOR" section of less(1).
For more information, see the "INPUT PREPROCESSOR" section of less(1).
.SH "MORE INFORMATION"

View File

@ -114,23 +114,6 @@ Options:
add the '--theme="..."' option to the configuration file or export the BAT_THEME
environment variable (e.g.: export BAT_THEME="...").
--color-scheme <scheme>
Specify whether to choose a dark or light syntax highlighting theme. Use '--theme-light'
and '--theme-dark' (or the environment variables BAT_THEME_LIGHT and BAT_THEME_DARK) to
configure which themes are picked. You may also use '--theme' to set a theme that is used
regardless of this choice.
Possible values:
* auto (default):
Query the terminals for its color scheme if the output is not redirected. This is to
prevent race conditions with pagers such as less.
* 'auto:always':
Always query the terminal for its color scheme, regardless of whether or not the
output is redirected.
* dark: Use a dark syntax highlighting theme.
* light: Use a light syntax highlighting theme.
* system: Query the OS for its color scheme. Only works on macOS.
--theme-light <theme>
Sets the theme name for syntax highlighting used when the terminal uses a light
background. Use '--list-themes' to see all available themes. To set a default theme, add

View File

@ -41,8 +41,6 @@ Options:
Use the specified syntax for files matching the glob pattern ('*.cpp:C++').
--theme <theme>
Set the color theme for syntax highlighting.
--color-scheme <scheme>
Specify whether to choose a dark or light theme.
--theme-light <theme>
Sets the color theme for syntax highlighting used for light backgrounds.
--theme-dark <theme>

View File

@ -9,7 +9,7 @@ use crate::{
config::{get_args_from_config_file, get_args_from_env_opts_var, get_args_from_env_vars},
};
use bat::style::StyleComponentList;
use bat::theme::{theme, ColorSchemePreference, DetectColorScheme, ThemeOptions, ThemeRequest};
use bat::theme::{theme, ThemeName, ThemeOptions, ThemePreference};
use bat::StripAnsiMode;
use clap::ArgMatches;
@ -418,35 +418,20 @@ impl App {
let theme = self
.matches
.get_one::<String>("theme")
.map(|t| ThemeRequest::from_str(t).unwrap());
.map(|t| ThemePreference::from_str(t).unwrap())
.unwrap_or_default();
let theme_dark = self
.matches
.get_one::<String>("theme-dark")
.map(|t| ThemeRequest::from_str(t).unwrap());
.map(|t| ThemeName::from_str(t).unwrap());
let theme_light = self
.matches
.get_one::<String>("theme-light")
.map(|t| ThemeRequest::from_str(t).unwrap());
.map(|t| ThemeName::from_str(t).unwrap());
ThemeOptions {
theme,
theme_dark,
theme_light,
color_scheme: self.color_scheme_preference(),
}
}
pub(crate) fn color_scheme_preference(&self) -> ColorSchemePreference {
match self
.matches
.get_one::<String>("color-scheme")
.map(|s| s.as_str())
{
Some("auto") => ColorSchemePreference::Auto(DetectColorScheme::Auto),
Some("auto:always") => ColorSchemePreference::Auto(DetectColorScheme::Always),
Some("dark") => ColorSchemePreference::Dark,
Some("light") => ColorSchemePreference::Light,
Some("system") => ColorSchemePreference::System,
_ => unreachable!("other values for --color-scheme are not allowed"),
}
}
}

View File

@ -383,32 +383,6 @@ pub fn build_app(interactive_output: bool) -> Command {
BAT_THEME=\"...\").",
),
)
.arg(
Arg::new("color-scheme")
.long("color-scheme")
.overrides_with("color-scheme")
.value_name("scheme")
.value_parser(["auto", "auto:always", "dark", "light", "system"])
.default_value("auto")
.hide_default_value(true)
.help("Specify whether to choose a dark or light theme.")
.long_help(
"Specify whether to choose a dark or light syntax highlighting theme. \
Use '--theme-light' and '--theme-dark' (or the environment variables \
BAT_THEME_LIGHT and BAT_THEME_DARK) to configure which themes are picked. \
You may also use '--theme' to set a theme that is used regardless of this choice.\n\n\
Possible values:\n\
* auto (default):\n \
Query the terminals for its color scheme if the output is not redirected. \
This is to prevent race conditions with pagers such as less.\n\
* 'auto:always':\n \
Always query the terminal for its color scheme, \
regardless of whether or not the output is redirected.\n\
* dark: Use a dark syntax highlighting theme.\n\
* light: Use a light syntax highlighting theme.\n\
* system: Query the OS for its color scheme. Only works on macOS.\n\
"),
)
.arg(
Arg::new("theme-light")
.long("theme-light")

View File

@ -384,7 +384,7 @@ fn run() -> Result<bool> {
&config,
config_dir,
cache_dir,
app.color_scheme_preference(),
ColorSchemePreference::default(),
)?;
Ok(true)
} else if app.matches.get_flag("config-file") {

View File

@ -29,46 +29,79 @@ pub fn color_scheme(preference: ColorSchemePreference) -> ColorScheme {
#[derive(Debug, Default, PartialEq, Eq)]
pub struct ThemeOptions {
/// Always use this theme regardless of the terminal's background color.
pub theme: Option<ThemeRequest>,
/// This corresponds with the `BAT_THEME` environment variable and the `--theme` option.
pub theme: ThemePreference,
/// The theme to use in case the terminal uses a dark background with light text.
pub theme_dark: Option<ThemeRequest>,
/// This corresponds with the `BAT_THEME_DARK` environment variable and the `--theme-dark` option.
pub theme_dark: Option<ThemeName>,
/// The theme to use in case the terminal uses a light background with dark text.
pub theme_light: Option<ThemeRequest>,
/// How to choose between dark and light.
pub color_scheme: ColorSchemePreference,
/// This corresponds with the `BAT_THEME_LIGHT` environment variable and the `--theme-light` option.
pub theme_light: Option<ThemeName>,
}
/// What theme should `bat` use?
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum ThemePreference {
/// Choose between [`ThemeOptions::theme_dark`] and [`ThemeOptions::theme_light`]
/// based on the terminal's (or the OS') color scheme.
Auto(ColorSchemePreference),
/// Always use the same theme regardless of the terminal's color scheme.
Fixed(ThemeName),
}
impl Default for ThemePreference {
fn default() -> Self {
ThemePreference::Auto(ColorSchemePreference::default())
}
}
impl FromStr for ThemePreference {
type Err = Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
use ThemePreference::*;
match s {
"auto" => Ok(Auto(ColorSchemePreference::default())),
"auto:always" => Ok(Auto(ColorSchemePreference::Auto(DetectColorScheme::Always))),
"auto:system" => Ok(Auto(ColorSchemePreference::System)),
"dark" => Ok(Auto(ColorSchemePreference::Dark)),
"light" => Ok(Auto(ColorSchemePreference::Light)),
_ => ThemeName::from_str(s).map(Fixed),
}
}
}
/// The name of a theme or the default theme.
///
/// ```
/// # use bat::theme::ThemeRequest;
/// # use bat::theme::ThemeName;
/// # use std::str::FromStr as _;
/// assert_eq!(ThemeRequest::Default, ThemeRequest::from_str("default").unwrap());
/// assert_eq!(ThemeRequest::Named("example".to_string()), ThemeRequest::from_str("example").unwrap());
/// assert_eq!(ThemeName::Default, ThemeName::from_str("default").unwrap());
/// assert_eq!(ThemeName::Named("example".to_string()), ThemeName::from_str("example").unwrap());
/// ```
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum ThemeRequest {
pub enum ThemeName {
Named(String),
Default,
}
impl FromStr for ThemeRequest {
impl FromStr for ThemeName {
type Err = Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s == "default" {
Ok(ThemeRequest::Default)
Ok(ThemeName::Default)
} else {
Ok(ThemeRequest::Named(s.to_owned()))
Ok(ThemeName::Named(s.to_owned()))
}
}
}
impl ThemeRequest {
impl ThemeName {
fn into_theme(self, color_scheme: ColorScheme) -> String {
match self {
ThemeRequest::Named(t) => t,
ThemeRequest::Default => default_theme(color_scheme).to_owned(),
ThemeName::Named(t) => t,
ThemeName::Default => default_theme(color_scheme).to_owned(),
}
}
}
@ -124,17 +157,18 @@ fn color_scheme_impl(
fn theme_from_detector(options: ThemeOptions, detector: &dyn ColorSchemeDetector) -> String {
// Implementation note: This function is mostly pure (i.e. it has no side effects) for the sake of testing.
// All the side effects (e.g. querying the terminal for its colors) are performed in the detector.
if let Some(theme) = options.theme {
theme.into_theme(ColorScheme::default())
} else {
let color_scheme = color_scheme_impl(options.color_scheme, detector);
choose_theme(options, color_scheme)
.map(|t| t.into_theme(color_scheme))
.unwrap_or_else(|| default_theme(color_scheme).to_owned())
match options.theme {
ThemePreference::Fixed(theme_name) => theme_name.into_theme(ColorScheme::default()),
ThemePreference::Auto(color_scheme_preference) => {
let color_scheme = color_scheme_impl(color_scheme_preference, detector);
choose_theme(options, color_scheme)
.map(|t| t.into_theme(color_scheme))
.unwrap_or_else(|| default_theme(color_scheme).to_owned())
}
}
}
fn choose_theme(options: ThemeOptions, color_scheme: ColorScheme) -> Option<ThemeRequest> {
fn choose_theme(options: ThemeOptions, color_scheme: ColorScheme) -> Option<ThemeName> {
match color_scheme {
ColorScheme::Dark => options.theme_dark,
ColorScheme::Light => options.theme_light,
@ -220,7 +254,6 @@ impl ColorSchemeDetector for Option<ColorScheme> {
mod tests {
use super::ColorScheme::*;
use super::ColorSchemePreference as Pref;
use super::DetectColorScheme::*;
use super::*;
use std::cell::Cell;
use std::iter;
@ -233,7 +266,7 @@ mod tests {
for pref in [Pref::Dark, Pref::Light] {
let detector = DetectorStub::should_detect(Some(Dark));
let options = ThemeOptions {
color_scheme: pref,
theme: ThemePreference::Auto(pref),
..Default::default()
};
_ = theme_from_detector(options, &detector);
@ -249,7 +282,9 @@ mod tests {
];
for detector in detectors {
let options = ThemeOptions {
color_scheme: Pref::Auto(Always),
theme: ThemePreference::Auto(ColorSchemePreference::Auto(
DetectColorScheme::Always,
)),
..Default::default()
};
_ = theme_from_detector(options, &detector);
@ -280,13 +315,13 @@ mod tests {
for color_scheme in optional(color_schemes()) {
for options in [
ThemeOptions {
theme: Some(ThemeRequest::Named("Theme".to_string())),
theme: ThemePreference::Fixed(ThemeName::Named("Theme".to_string())),
..Default::default()
},
ThemeOptions {
theme: Some(ThemeRequest::Named("Theme".to_string())),
theme_dark: Some(ThemeRequest::Named("Dark Theme".to_string())),
theme_light: Some(ThemeRequest::Named("Light Theme".to_string())),
theme: ThemePreference::Fixed(ThemeName::Named("Theme".to_string())),
theme_dark: Some(ThemeName::Named("Dark Theme".to_string())),
theme_light: Some(ThemeName::Named("Light Theme".to_string())),
..Default::default()
},
] {
@ -299,7 +334,7 @@ mod tests {
#[test]
fn detector_is_not_called_if_theme_is_present() {
let options = ThemeOptions {
theme: Some(ThemeRequest::Named("Theme".to_string())),
theme: ThemePreference::Fixed(ThemeName::Named("Theme".to_string())),
..Default::default()
};
let detector = DetectorStub::should_detect(Some(Dark));
@ -326,7 +361,7 @@ mod tests {
fn dark_if_requested_explicitly_through_theme() {
for color_scheme in optional(color_schemes()) {
let options = ThemeOptions {
theme: Some(ThemeRequest::Default),
theme: ThemePreference::Fixed(ThemeName::Default),
..Default::default()
};
let detector = ConstantDetector(color_scheme);
@ -343,8 +378,8 @@ mod tests {
for options in [
ThemeOptions::default(),
ThemeOptions {
theme_dark: Some(ThemeRequest::Default),
theme_light: Some(ThemeRequest::Default),
theme_dark: Some(ThemeName::Default),
theme_light: Some(ThemeName::Default),
..Default::default()
},
] {
@ -365,8 +400,8 @@ mod tests {
fn chooses_dark_theme_if_dark_or_unknown() {
for color_scheme in [Some(Dark), None] {
let options = ThemeOptions {
theme_dark: Some(ThemeRequest::Named("Dark".to_string())),
theme_light: Some(ThemeRequest::Named("Light".to_string())),
theme_dark: Some(ThemeName::Named("Dark".to_string())),
theme_light: Some(ThemeName::Named("Light".to_string())),
..Default::default()
};
let detector = ConstantDetector(color_scheme);
@ -377,8 +412,8 @@ mod tests {
#[test]
fn chooses_light_theme_if_light() {
let options = ThemeOptions {
theme_dark: Some(ThemeRequest::Named("Dark".to_string())),
theme_light: Some(ThemeRequest::Named("Light".to_string())),
theme_dark: Some(ThemeName::Named("Dark".to_string())),
theme_light: Some(ThemeName::Named("Light".to_string())),
..Default::default()
};
let detector = ConstantDetector(Some(ColorScheme::Light));

View File

@ -279,7 +279,6 @@ fn list_themes_with_colors() {
bat()
.arg("--color=always")
.arg("--color-scheme=dark")
.arg("--list-themes")
.assert()
.success()
@ -296,7 +295,6 @@ fn list_themes_without_colors() {
bat()
.arg("--color=never")
.arg("--color-scheme=dark")
.arg("--list-themes")
.assert()
.success()