From 3a9d574770301f874af55b19b39d2c618966f135 Mon Sep 17 00:00:00 2001 From: cyqsimon <28627918+cyqsimon@users.noreply.github.com> Date: Wed, 15 May 2024 14:31:25 +0800 Subject: [PATCH 01/53] Add syntax mapping for `/etc/pacman.conf` --- src/syntax_mapping/builtins/linux/50-pacman.toml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/syntax_mapping/builtins/linux/50-pacman.toml b/src/syntax_mapping/builtins/linux/50-pacman.toml index 655118c5..2f4ee71f 100644 --- a/src/syntax_mapping/builtins/linux/50-pacman.toml +++ b/src/syntax_mapping/builtins/linux/50-pacman.toml @@ -1,3 +1,8 @@ [mappings] -# pacman hooks -"INI" = ["/usr/share/libalpm/hooks/*.hook", "/etc/pacman.d/hooks/*.hook"] +"INI" = [ + # config + "/etc/pacman.conf", + # hooks + "/usr/share/libalpm/hooks/*.hook", + "/etc/pacman.d/hooks/*.hook", +] From f82487daf8d24285c6206af49809992a7371ff18 Mon Sep 17 00:00:00 2001 From: cyqsimon <28627918+cyqsimon@users.noreply.github.com> Date: Wed, 15 May 2024 14:35:47 +0800 Subject: [PATCH 02/53] Write changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28e56e34..5a7177c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ - Added auto detect syntax for `.jsonc` #2795 (@mxaddict) - Added auto detect syntax for `.aws/{config,credentials}` #2795 (@mxaddict) - Add syntax mapping for Wireguard config #2874 (@cyqsimon) +- Add syntax mapping for `/etc/pacman.conf` #2961 (@cyqsimon) ## Themes From 7bd6cdbebc232585e09bea563c5ee0cdaa50f0f9 Mon Sep 17 00:00:00 2001 From: cyqsimon <28627918+cyqsimon@users.noreply.github.com> Date: Fri, 26 Jul 2024 15:37:48 +0800 Subject: [PATCH 03/53] Add syntax mapping for kubernetes config files --- src/syntax_mapping/builtins/linux/50-kubernetes.toml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/syntax_mapping/builtins/linux/50-kubernetes.toml diff --git a/src/syntax_mapping/builtins/linux/50-kubernetes.toml b/src/syntax_mapping/builtins/linux/50-kubernetes.toml new file mode 100644 index 00000000..6a81a35a --- /dev/null +++ b/src/syntax_mapping/builtins/linux/50-kubernetes.toml @@ -0,0 +1,2 @@ +[mappings] +"YAML" = ["/etc/kubernetes/*.conf"] From 319b8868fc93c1fd026a67b58c4192fa535e015c Mon Sep 17 00:00:00 2001 From: cyqsimon <28627918+cyqsimon@users.noreply.github.com> Date: Fri, 26 Jul 2024 23:39:27 +0800 Subject: [PATCH 04/53] Write changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27a2d806..a4a6ed16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,7 @@ - Added auto detect syntax for `.aws/{config,credentials}` #2795 (@mxaddict) - Add syntax mapping for Wireguard config #2874 (@cyqsimon) - Associate `.textproto` files with `ProtoBuf` syntax, see #3038 (@vorburger). +- Add syntax mapping for kubernetes config files #3049 (@cyqsimon) ## Themes From 1423dd944066f060aa814817b2867097f2bac4d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Tue, 16 Apr 2024 14:43:16 +0200 Subject: [PATCH 05/53] Choose theme based on the terminal's color scheme --- src/lib.rs | 1 + src/theme.rs | 334 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 335 insertions(+) create mode 100644 src/theme.rs diff --git a/src/lib.rs b/src/lib.rs index 23c4a800..5699d87a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,6 +49,7 @@ pub(crate) mod printer; pub mod style; pub(crate) mod syntax_mapping; mod terminal; +pub mod theme; mod vscreen; pub(crate) mod wrapping; diff --git a/src/theme.rs b/src/theme.rs new file mode 100644 index 00000000..b1607140 --- /dev/null +++ b/src/theme.rs @@ -0,0 +1,334 @@ +use std::convert::Infallible; +use std::str::FromStr; + +/// Chooses an appropriate theme or falls back to a default theme +/// based on the user-provided options and the color scheme of the terminal. +pub fn theme(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 = detect(options.detect_color_scheme, detector).unwrap_or_default(); + 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 { + match color_scheme { + ColorScheme::Dark => options.dark_theme, + ColorScheme::Light => options.light_theme, + } +} + +fn detect(when: DetectColorScheme, detector: &dyn ColorSchemeDetector) -> Option { + let should_detect = match when { + DetectColorScheme::Auto => detector.should_detect(), + DetectColorScheme::Always => true, + DetectColorScheme::Never => false, + }; + should_detect.then(|| detector.detect()).flatten() +} + +const fn default_theme(color_scheme: ColorScheme) -> &'static str { + match color_scheme { + ColorScheme::Dark => "Monokai Extended", + ColorScheme::Light => "Monokai Extended Light", + } +} + +/// Options for configuring the theme used for syntax highlighting. +#[derive(Debug, Default)] +pub struct ThemeOptions { + /// Always use this theme regardless of the terminal's background color. + pub theme: Option, + /// The theme to use in case the terminal uses a dark background with light text. + pub dark_theme: Option, + /// The theme to use in case the terminal uses a light background with dark text. + pub light_theme: Option, + /// Detect whether or not the terminal is dark or light by querying for its colors. + pub detect_color_scheme: DetectColorScheme, +} + +/// The name of a theme or the default theme. +#[derive(Debug)] +pub enum ThemeRequest { + Named(String), + Default, +} + +impl FromStr for ThemeRequest { + type Err = Infallible; + + fn from_str(s: &str) -> Result { + if s == "default" { + Ok(ThemeRequest::Default) + } else { + Ok(ThemeRequest::Named(s.to_owned())) + } + } +} + +impl ThemeRequest { + fn into_theme(self, color_scheme: ColorScheme) -> String { + match self { + ThemeRequest::Named(t) => t, + ThemeRequest::Default => default_theme(color_scheme).to_owned(), + } + } +} + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub enum DetectColorScheme { + /// Only query the terminal for its colors when appropriate (e.g. when the the output is not redirected). + #[default] + Auto, + /// Always query the terminal for its colors. + Always, + /// Never query the terminal for its colors. + Never, +} + +/// The color scheme used to pick a fitting theme. Defaults to [`ColorScheme::Dark`]. +#[derive(Default, Copy, Clone)] +pub enum ColorScheme { + #[default] + Dark, + Light, +} + +pub trait ColorSchemeDetector { + fn should_detect(&self) -> bool; + + fn detect(&self) -> Option; +} + +#[cfg(test)] +impl ColorSchemeDetector for Option { + fn should_detect(&self) -> bool { + true + } + + fn detect(&self) -> Option { + *self + } +} + +#[cfg(test)] +mod tests { + use super::ColorScheme::*; + use super::DetectColorScheme::*; + use super::*; + use std::cell::Cell; + use std::iter; + + mod color_scheme_detection { + use super::*; + + #[test] + fn not_called_for_never() { + let detector = DetectorStub::should_detect(Some(Dark)); + let options = ThemeOptions { + detect_color_scheme: Never, + ..Default::default() + }; + _ = theme(options, &detector); + assert!(!detector.was_called.get()); + } + + #[test] + fn called_for_always() { + let detectors = [ + DetectorStub::should_detect(Some(Dark)), + DetectorStub::should_not_detect(), + ]; + for detector in detectors { + let options = ThemeOptions { + detect_color_scheme: Always, + ..Default::default() + }; + _ = theme(options, &detector); + assert!(detector.was_called.get()); + } + } + + #[test] + fn called_for_auto_if_should_detect() { + let detector = DetectorStub::should_detect(Some(Dark)); + _ = theme(ThemeOptions::default(), &detector); + assert!(detector.was_called.get()); + } + + #[test] + fn not_called_for_auto_if_not_should_detect() { + let detector = DetectorStub::should_not_detect(); + _ = theme(ThemeOptions::default(), &detector); + assert!(!detector.was_called.get()); + } + } + + mod precedence { + use super::*; + + #[test] + fn theme_is_preferred_over_light_or_dark_themes() { + for color_scheme in optional(color_schemes()) { + for options in [ + ThemeOptions { + theme: Some(ThemeRequest::Named("Theme".to_string())), + ..Default::default() + }, + ThemeOptions { + theme: Some(ThemeRequest::Named("Theme".to_string())), + dark_theme: Some(ThemeRequest::Named("Dark Theme".to_string())), + light_theme: Some(ThemeRequest::Named("Light Theme".to_string())), + ..Default::default() + }, + ] { + let detector = ConstantDetector(color_scheme); + assert_eq!("Theme", theme(options, &detector)); + } + } + } + + #[test] + fn detector_is_not_called_if_theme_is_present() { + let options = ThemeOptions { + theme: Some(ThemeRequest::Named("Theme".to_string())), + ..Default::default() + }; + let detector = DetectorStub::should_detect(Some(Dark)); + _ = theme(options, &detector); + assert!(!detector.was_called.get()); + } + } + + mod default_theme { + use super::*; + + #[test] + fn dark_if_unable_to_detect_color_scheme() { + let detector = ConstantDetector(None); + assert_eq!( + default_theme(ColorScheme::Dark), + theme(ThemeOptions::default(), &detector) + ); + } + + // For backwards compatibility, if the default theme is requested + // explicitly through BAT_THEME, we always pick the default dark theme. + #[test] + fn dark_if_requested_explicitly_through_theme() { + for color_scheme in optional(color_schemes()) { + let options = ThemeOptions { + theme: Some(ThemeRequest::Default), + ..Default::default() + }; + let detector = ConstantDetector(color_scheme); + assert_eq!(default_theme(ColorScheme::Dark), theme(options, &detector)); + } + } + + #[test] + fn varies_depending_on_color_scheme() { + for color_scheme in color_schemes() { + for options in [ + ThemeOptions::default(), + ThemeOptions { + dark_theme: Some(ThemeRequest::Default), + light_theme: Some(ThemeRequest::Default), + ..Default::default() + }, + ] { + let detector = ConstantDetector(Some(color_scheme)); + assert_eq!(default_theme(color_scheme), theme(options, &detector)); + } + } + } + } + + mod choosing { + use super::*; + + #[test] + fn chooses_dark_theme_if_dark_or_unknown() { + for color_scheme in [Some(Dark), None] { + let options = ThemeOptions { + dark_theme: Some(ThemeRequest::Named("Dark".to_string())), + light_theme: Some(ThemeRequest::Named("Light".to_string())), + ..Default::default() + }; + let detector = ConstantDetector(color_scheme); + assert_eq!("Dark", theme(options, &detector)); + } + } + + #[test] + fn chooses_light_theme_if_light() { + let options = ThemeOptions { + dark_theme: Some(ThemeRequest::Named("Dark".to_string())), + light_theme: Some(ThemeRequest::Named("Light".to_string())), + ..Default::default() + }; + let detector = ConstantDetector(Some(ColorScheme::Light)); + assert_eq!("Light", theme(options, &detector)); + } + } + + struct DetectorStub { + should_detect: bool, + color_scheme: Option, + was_called: Cell, + } + + impl DetectorStub { + fn should_detect(color_scheme: Option) -> Self { + DetectorStub { + should_detect: true, + color_scheme, + was_called: Cell::default(), + } + } + + fn should_not_detect() -> Self { + DetectorStub { + should_detect: false, + color_scheme: None, + was_called: Cell::default(), + } + } + } + + impl ColorSchemeDetector for DetectorStub { + fn should_detect(&self) -> bool { + self.should_detect + } + + fn detect(&self) -> Option { + self.was_called.set(true); + self.color_scheme + } + } + + struct ConstantDetector(Option); + + impl ColorSchemeDetector for ConstantDetector { + fn should_detect(&self) -> bool { + true + } + + fn detect(&self) -> Option { + self.0 + } + } + + fn optional(value: impl Iterator) -> impl Iterator> { + value.map(Some).chain(iter::once(None)) + } + + fn color_schemes() -> impl Iterator { + [Dark, Light].into_iter() + } +} From de796392cfba07a86d48ca9099e053b176ac916b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Tue, 16 Apr 2024 14:43:18 +0200 Subject: [PATCH 06/53] Deprecate old `default_theme` function --- src/assets.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/assets.rs b/src/assets.rs index 9655553d..53414366 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -90,6 +90,7 @@ impl HighlightingAssets { /// /// See and /// for more context. + #[deprecated(note = "use bat::theme::theme instead")] pub fn default_theme() -> &'static str { #[cfg(not(target_os = "macos"))] { From cda363a3f742fe4ef112ffcd4a61bb756332c16c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Tue, 16 Apr 2024 14:43:20 +0200 Subject: [PATCH 07/53] Use `default_theme()` function from theme module --- src/assets.rs | 27 ++++++++------------------- src/theme.rs | 2 +- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/src/assets.rs b/src/assets.rs index 53414366..857f416b 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -13,6 +13,7 @@ use crate::error::*; use crate::input::{InputReader, OpenedInput}; use crate::syntax_mapping::ignored_suffixes::IgnoredSuffixes; use crate::syntax_mapping::MappingTarget; +use crate::theme::{default_theme, ColorScheme}; use crate::{bat_warning, SyntaxMapping}; use lazy_theme_set::LazyThemeSet; @@ -94,33 +95,18 @@ impl HighlightingAssets { pub fn default_theme() -> &'static str { #[cfg(not(target_os = "macos"))] { - Self::default_dark_theme() + default_theme(ColorScheme::Dark) } #[cfg(target_os = "macos")] { if macos_dark_mode_active() { - Self::default_dark_theme() + default_theme(ColorScheme::Dark) } else { - Self::default_light_theme() + default_theme(ColorScheme::Light) } } } - /** - * The default theme that looks good on a dark background. - */ - fn default_dark_theme() -> &'static str { - "Monokai Extended" - } - - /** - * The default theme that looks good on a light background. - */ - #[cfg(target_os = "macos")] - fn default_light_theme() -> &'static str { - "Monokai Extended Light" - } - pub fn from_cache(cache_path: &Path) -> Result { Ok(HighlightingAssets::new( SerializedSyntaxSet::FromFile(cache_path.join("syntaxes.bin")), @@ -249,7 +235,10 @@ impl HighlightingAssets { bat_warning!("Unknown theme '{}', using default.", theme) } self.get_theme_set() - .get(self.fallback_theme.unwrap_or_else(Self::default_theme)) + .get( + self.fallback_theme + .unwrap_or_else(|| default_theme(ColorScheme::Dark)), + ) .expect("something is very wrong if the default theme is missing") } } diff --git a/src/theme.rs b/src/theme.rs index b1607140..8ce75e1f 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -32,7 +32,7 @@ fn detect(when: DetectColorScheme, detector: &dyn ColorSchemeDetector) -> Option should_detect.then(|| detector.detect()).flatten() } -const fn default_theme(color_scheme: ColorScheme) -> &'static str { +pub(crate) const fn default_theme(color_scheme: ColorScheme) -> &'static str { match color_scheme { ColorScheme::Dark => "Monokai Extended", ColorScheme::Light => "Monokai Extended Light", From cea45e05f3e3f2fea3eed6cbd8e2ac4bd1036fe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Thu, 18 Jul 2024 15:38:28 +0200 Subject: [PATCH 08/53] Expose new theme selection in CLI --- Cargo.lock | 51 +++++++++++++++++++++++-- Cargo.toml | 3 ++ doc/long-help.txt | 36 +++++++++++++++-- doc/short-help.txt | 6 +++ src/bin/bat/app.rs | 85 ++++++++++++++++++++++++++++++++++------- src/bin/bat/clap_app.rs | 53 ++++++++++++++++++++++++- src/bin/bat/config.rs | 2 + src/theme.rs | 24 ++++++------ 8 files changed, 227 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1168501a..6d413de6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -149,6 +149,7 @@ dependencies = [ "shell-words", "syntect", "tempfile", + "terminal-colorsaurus", "thiserror", "toml", "unicode-width", @@ -620,6 +621,12 @@ version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "home" version = "0.5.9" @@ -688,9 +695,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.149" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libgit2-sys" @@ -755,9 +762,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" @@ -768,6 +775,18 @@ dependencies = [ "adler", ] +[[package]] +name = "mio" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4929e1f84c5e54c3ec6141cd5d8b5a5c055f031f80cf78f2072920173cb4d880" +dependencies = [ + "hermit-abi", + "libc", + "wasi", + "windows-sys 0.52.0", +] + [[package]] name = "nix" version = "0.26.4" @@ -1309,6 +1328,30 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal-colorsaurus" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f99bb1dc5cde9eada5a8f466641240f9d5b9f55291d675df4160b097fbfa42e" +dependencies = [ + "cfg-if", + "libc", + "memchr", + "mio", + "terminal-trx", +] + +[[package]] +name = "terminal-trx" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d4c86910e10c782a02d3b7606de43cf7ebd80e1fafdca8e49a0db2b0d4611f0" +dependencies = [ + "cfg-if", + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "terminal_size" version = "0.3.0" diff --git a/Cargo.toml b/Cargo.toml index 720e629b..affce17f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ application = [ "bugreport", "build-assets", "git", + "detect-color-scheme", "minimal-application", ] # Mainly for developers that want to iterate quickly @@ -35,6 +36,7 @@ git = ["git2"] # Support indicating git modifications paging = ["shell-words", "grep-cli"] # Support applying a pager on the output lessopen = ["run_script", "os_str_bytes"] # Support $LESSOPEN preprocessor build-assets = ["syntect/yaml-load", "syntect/plist-load", "regex", "walkdir"] +detect-color-scheme = ["dep:terminal-colorsaurus"] # You need to use one of these if you depend on bat as a library: regex-onig = ["syntect/regex-onig"] # Use the "oniguruma" regex engine @@ -68,6 +70,7 @@ bytesize = { version = "1.3.0" } encoding_rs = "0.8.34" os_str_bytes = { version = "~7.0", optional = true } run_script = { version = "^0.10.1", optional = true} +terminal-colorsaurus = { version = "0.4", optional = true } [dependencies.git2] version = "0.18" diff --git a/doc/long-help.txt b/doc/long-help.txt index 2b03490f..86e9a532 100644 --- a/doc/long-help.txt +++ b/doc/long-help.txt @@ -109,9 +109,39 @@ Options: 'bat --ignored-suffix ".dev" my_file.json.dev' will use JSON syntax, and ignore '.dev' --theme - Set the theme for syntax highlighting. Use '--list-themes' to see all available themes. To - set a default theme, add the '--theme="..."' option to the configuration file or export - the BAT_THEME environment variable (e.g.: export BAT_THEME="..."). + Set the theme for syntax highlighting. Note that this option overrides '--theme-dark' and + '--theme-light'. Use '--list-themes' to see all available themes. To set a default theme, + add the '--theme="..."' option to the configuration file or export the BAT_THEME + environment variable (e.g.: export BAT_THEME="..."). + + --detect-color-scheme + Specify when to query the terminal for its colors in order to pick an appropriate 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 the terminal's colors. + + Possible values: + * auto (default): + Only query the terminals colors if the output is not redirected. This is to prevent + race conditions with pagers such as less. + * never + Never query the terminal for its colors and assume that the terminal has a dark + background. + * always + Always query the terminal for its colors, regardless of whether or not the output is + redirected. + + --theme-light + 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 + the '--theme-light="..." option to the configuration file or export the BAT_THEME_LIGHT + environment variable (e.g. export BAT_THEME_LIGHT="..."). + + --theme-dark + Sets the theme name for syntax highlighting used when the terminal uses a dark background. + Use '--list-themes' to see all available themes. To set a default theme, add the + '--theme-dark="..." option to the configuration file or export the BAT_THEME_DARK + environment variable (e.g. export BAT_THEME_DARK="..."). --list-themes Display a list of supported themes for syntax highlighting. diff --git a/doc/short-help.txt b/doc/short-help.txt index 305bbf3d..3e369229 100644 --- a/doc/short-help.txt +++ b/doc/short-help.txt @@ -41,6 +41,12 @@ Options: Use the specified syntax for files matching the glob pattern ('*.cpp:C++'). --theme Set the color theme for syntax highlighting. + --detect-color-scheme + Specify when to query the terminal for its colors. + --theme-light + Sets the color theme for syntax highlighting used for light backgrounds. + --theme-dark + Sets the color theme for syntax highlighting used for dark backgrounds. --list-themes Display all supported highlighting themes. -s, --squeeze-blank diff --git a/src/bin/bat/app.rs b/src/bin/bat/app.rs index d6628668..d9e1662b 100644 --- a/src/bin/bat/app.rs +++ b/src/bin/bat/app.rs @@ -9,6 +9,9 @@ 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, ColorScheme, ColorSchemeDetector, DetectColorScheme, ThemeOptions, ThemeRequest, +}; use bat::StripAnsiMode; use clap::ArgMatches; @@ -16,7 +19,6 @@ use console::Term; use crate::input::{new_file_input, new_stdin_input}; use bat::{ - assets::HighlightingAssets, bat_warning, config::{Config, VisibleLines}, error::*, @@ -254,18 +256,7 @@ impl App { Some("auto") => StripAnsiMode::Auto, _ => unreachable!("other values for --strip-ansi are not allowed"), }, - theme: self - .matches - .get_one::("theme") - .map(String::from) - .map(|s| { - if s == "default" { - String::from(HighlightingAssets::default_theme()) - } else { - s - } - }) - .unwrap_or_else(|| String::from(HighlightingAssets::default_theme())), + theme: theme(self.theme_options(), &TerminalColorSchemeDetector), visible_lines: match self.matches.try_contains_id("diff").unwrap_or_default() && self.matches.get_flag("diff") { @@ -424,4 +415,72 @@ impl App { Ok(styled_components) } + + fn theme_options(&self) -> ThemeOptions { + let theme = self + .matches + .get_one::("theme") + .map(|t| ThemeRequest::from_str(t).unwrap()); + let theme_dark = self + .matches + .get_one::("theme-dark") + .map(|t| ThemeRequest::from_str(t).unwrap()); + let theme_light = self + .matches + .get_one::("theme-light") + .map(|t| ThemeRequest::from_str(t).unwrap()); + let detect_color_scheme = match self + .matches + .get_one::("detect-color-scheme") + .map(|s| s.as_str()) + { + Some("auto") => DetectColorScheme::Auto, + Some("never") => DetectColorScheme::Never, + Some("always") => DetectColorScheme::Always, + _ => unreachable!("other values for --detect-color-scheme are not allowed"), + }; + ThemeOptions { + theme, + theme_dark, + theme_light, + detect_color_scheme, + } + } +} + +struct TerminalColorSchemeDetector; + +#[cfg(feature = "detect-color-scheme")] +impl ColorSchemeDetector for TerminalColorSchemeDetector { + fn should_detect(&self) -> bool { + // Querying the terminal for its colors via OSC 10 / OSC 11 requires "exclusive" access + // since we read/write from the terminal and enable/disable raw mode. + // This causes race conditions with pagers such as less when they are attached to the + // same terminal as us. + // + // This is usually only an issue when the output is manually piped to a pager. + // For example: `bat Cargo.toml | less`. + // Otherwise, if we start the pager ourselves, then there's no race condition + // since the pager is started *after* the color is detected. + std::io::stdout().is_terminal() + } + + fn detect(&self) -> Option { + use terminal_colorsaurus::{color_scheme, ColorScheme as ColorsaurusScheme, QueryOptions}; + match color_scheme(QueryOptions::default()).ok()? { + ColorsaurusScheme::Dark => Some(ColorScheme::Dark), + ColorsaurusScheme::Light => Some(ColorScheme::Light), + } + } +} + +#[cfg(not(feature = "detect-color-scheme"))] +impl ColorSchemeDetector for TerminalColorSchemeDetector { + fn should_detect(&self) -> bool { + false + } + + fn detect(&self) -> Option { + None + } } diff --git a/src/bin/bat/clap_app.rs b/src/bin/bat/clap_app.rs index 33dde980..6abdab9c 100644 --- a/src/bin/bat/clap_app.rs +++ b/src/bin/bat/clap_app.rs @@ -375,13 +375,64 @@ pub fn build_app(interactive_output: bool) -> Command { .overrides_with("theme") .help("Set the color theme for syntax highlighting.") .long_help( - "Set the theme for syntax highlighting. Use '--list-themes' to \ + "Set the theme for syntax highlighting. Note that this option overrides \ + '--theme-dark' and '--theme-light'. Use '--list-themes' to \ see all available themes. To set a default theme, add the \ '--theme=\"...\"' option to the configuration file or export the \ BAT_THEME environment variable (e.g.: export \ BAT_THEME=\"...\").", ), ) + .arg( + Arg::new("detect-color-scheme") + .long("detect-color-scheme") + .overrides_with("detect-color-scheme") + .value_name("when") + .value_parser(["auto", "never", "always"]) + .default_value("auto") + .hide_default_value(true) + .help("Specify when to query the terminal for its colors.") + .long_help( + "Specify when to query the terminal for its colors \ + in order to pick an appropriate 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 the terminal's colors.\n\n\ + Possible values:\n\ + * auto (default):\n \ + Only query the terminals colors if the output is not redirected. \ + This is to prevent race conditions with pagers such as less.\n\ + * never\n \ + Never query the terminal for its colors \ + and assume that the terminal has a dark background.\n\ + * always\n \ + Always query the terminal for its colors, \ + regardless of whether or not the output is redirected."), + ) + .arg( + Arg::new("theme-light") + .long("theme-light") + .overrides_with("theme-light") + .value_name("theme") + .help("Sets the color theme for syntax highlighting used for light backgrounds.") + .long_help( + "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 the \ + '--theme-light=\"...\" option to the configuration file or export the BAT_THEME_LIGHT \ + environment variable (e.g. export BAT_THEME_LIGHT=\"...\")."), + ) + .arg( + Arg::new("theme-dark") + .long("theme-dark") + .overrides_with("theme-dark") + .value_name("theme") + .help("Sets the color theme for syntax highlighting used for dark backgrounds.") + .long_help( + "Sets the theme name for syntax highlighting used when the terminal uses a dark background. \ + Use '--list-themes' to see all available themes. To set a default theme, add the \ + '--theme-dark=\"...\" option to the configuration file or export the BAT_THEME_DARK \ + environment variable (e.g. export BAT_THEME_DARK=\"...\")."), + ) .arg( Arg::new("list-themes") .long("list-themes") diff --git a/src/bin/bat/config.rs b/src/bin/bat/config.rs index 6fa18f09..f1ec3d53 100644 --- a/src/bin/bat/config.rs +++ b/src/bin/bat/config.rs @@ -141,6 +141,8 @@ pub fn get_args_from_env_vars() -> Vec { [ ("--tabs", "BAT_TABS"), ("--theme", "BAT_THEME"), + ("--theme-dark", "BAT_THEME_DARK"), + ("--theme-light", "BAT_THEME_LIGHT"), ("--pager", "BAT_PAGER"), ("--paging", "BAT_PAGING"), ("--style", "BAT_STYLE"), diff --git a/src/theme.rs b/src/theme.rs index 8ce75e1f..ec3e3d34 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -18,8 +18,8 @@ pub fn theme(options: ThemeOptions, detector: &dyn ColorSchemeDetector) -> Strin fn choose_theme(options: ThemeOptions, color_scheme: ColorScheme) -> Option { match color_scheme { - ColorScheme::Dark => options.dark_theme, - ColorScheme::Light => options.light_theme, + ColorScheme::Dark => options.theme_dark, + ColorScheme::Light => options.theme_light, } } @@ -45,9 +45,9 @@ pub struct ThemeOptions { /// Always use this theme regardless of the terminal's background color. pub theme: Option, /// The theme to use in case the terminal uses a dark background with light text. - pub dark_theme: Option, + pub theme_dark: Option, /// The theme to use in case the terminal uses a light background with dark text. - pub light_theme: Option, + pub theme_light: Option, /// Detect whether or not the terminal is dark or light by querying for its colors. pub detect_color_scheme: DetectColorScheme, } @@ -182,8 +182,8 @@ mod tests { }, ThemeOptions { theme: Some(ThemeRequest::Named("Theme".to_string())), - dark_theme: Some(ThemeRequest::Named("Dark Theme".to_string())), - light_theme: Some(ThemeRequest::Named("Light Theme".to_string())), + theme_dark: Some(ThemeRequest::Named("Dark Theme".to_string())), + theme_light: Some(ThemeRequest::Named("Light Theme".to_string())), ..Default::default() }, ] { @@ -237,8 +237,8 @@ mod tests { for options in [ ThemeOptions::default(), ThemeOptions { - dark_theme: Some(ThemeRequest::Default), - light_theme: Some(ThemeRequest::Default), + theme_dark: Some(ThemeRequest::Default), + theme_light: Some(ThemeRequest::Default), ..Default::default() }, ] { @@ -256,8 +256,8 @@ mod tests { fn chooses_dark_theme_if_dark_or_unknown() { for color_scheme in [Some(Dark), None] { let options = ThemeOptions { - dark_theme: Some(ThemeRequest::Named("Dark".to_string())), - light_theme: Some(ThemeRequest::Named("Light".to_string())), + theme_dark: Some(ThemeRequest::Named("Dark".to_string())), + theme_light: Some(ThemeRequest::Named("Light".to_string())), ..Default::default() }; let detector = ConstantDetector(color_scheme); @@ -268,8 +268,8 @@ mod tests { #[test] fn chooses_light_theme_if_light() { let options = ThemeOptions { - dark_theme: Some(ThemeRequest::Named("Dark".to_string())), - light_theme: Some(ThemeRequest::Named("Light".to_string())), + theme_dark: Some(ThemeRequest::Named("Dark".to_string())), + theme_light: Some(ThemeRequest::Named("Light".to_string())), ..Default::default() }; let detector = ConstantDetector(Some(ColorScheme::Light)); From 9a1bfe946dafcd095895737b7b395dd636114737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Tue, 16 Apr 2024 14:43:24 +0200 Subject: [PATCH 09/53] Update completions and man page --- assets/completions/_bat.ps1.in | 3 +++ assets/completions/bat.bash.in | 9 ++++++-- assets/completions/bat.fish.in | 7 +++++++ assets/completions/bat.zsh.in | 3 +++ assets/manual/bat.1.in | 38 +++++++++++++++++++++++++++++++--- 5 files changed, 55 insertions(+), 5 deletions(-) diff --git a/assets/completions/_bat.ps1.in b/assets/completions/_bat.ps1.in index c0c151e1..5635dea2 100644 --- a/assets/completions/_bat.ps1.in +++ b/assets/completions/_bat.ps1.in @@ -32,11 +32,14 @@ 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('--detect-color-scheme', 'detect-color-scheme', [CompletionResultType]::ParameterName, 'When to detect the terminal''s color scheme (*auto*, never, always).') [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++'').') [CompletionResult]::new('--map-syntax', 'map-syntax', [CompletionResultType]::ParameterName, 'Use the specified syntax for files matching the glob pattern (''*.cpp:C++'').') [CompletionResult]::new('--theme', 'theme', [CompletionResultType]::ParameterName, 'Set the color theme for syntax highlighting.') + [CompletionResult]::new('--theme-dark', 'theme', [CompletionResultType]::ParameterName, 'Set the color theme for syntax highlighting for dark backgrounds.') + [CompletionResult]::new('--theme-light', 'theme', [CompletionResultType]::ParameterName, 'Set the color theme for syntax highlighting for light backgrounds.') [CompletionResult]::new('--style', 'style', [CompletionResultType]::ParameterName, 'Comma-separated list of style elements to display (*default*, auto, full, plain, changes, header, header-filename, header-filesize, grid, rule, numbers, snip).') [CompletionResult]::new('-r', 'r', [CompletionResultType]::ParameterName, 'Only print the lines from N to M.') [CompletionResult]::new('--line-range', 'line-range', [CompletionResultType]::ParameterName, 'Only print the lines from N to M.') diff --git a/assets/completions/bat.bash.in b/assets/completions/bat.bash.in index f314bb25..a02c5a04 100644 --- a/assets/completions/bat.bash.in +++ b/assets/completions/bat.bash.in @@ -100,7 +100,7 @@ _bat() { COMPREPLY=($(compgen -W "auto never character" -- "$cur")) return 0 ;; - --color | --decorations | --paging) + --color | --decorations | --paging | --detect-color-scheme) COMPREPLY=($(compgen -W "auto never always" -- "$cur")) return 0 ;; @@ -112,7 +112,9 @@ _bat() { COMPREPLY=($(compgen -c -- "$cur")) return 0 ;; - --theme) + --theme | \ + --theme-dark | \ + --theme-light) local IFS=$'\n' COMPREPLY=($(compgen -W "$("$1" --list-themes)" -- "$cur")) __bat_escape_completions @@ -164,12 +166,15 @@ _bat() { --color --italic-text --decorations + --detect-color-scheme --force-colorization --paging --pager --map-syntax --ignored-suffix --theme + --theme-dark + --theme-light --list-themes --squeeze-blank --squeeze-limit diff --git a/assets/completions/bat.fish.in b/assets/completions/bat.fish.in index 788f71b0..7bd0ebca 100644 --- a/assets/completions/bat.fish.in +++ b/assets/completions/bat.fish.in @@ -99,6 +99,7 @@ set -l color_opts ' ' set -l decorations_opts $color_opts set -l paging_opts $color_opts +set -l detect_color_scheme_opts $color_opts # Include some examples so we can indicate the default. set -l pager_opts ' @@ -143,6 +144,8 @@ 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 detect-color-scheme -x -a "$detect_color_scheme_opts" -d "When to detect the terminal's color scheme" -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 @@ -205,6 +208,10 @@ complete -c $bat -l terminal-width -x -d "Set terminal , +, or -< complete -c $bat -l theme -x -a "(command $bat --list-themes | command cat)" -d "Set the syntax highlighting theme" -n __bat_no_excl_args +complete -c $bat -l theme-dark -x -a "(command $bat --list-themes | command cat)" -d "Set the syntax highlighting theme for dark backgrounds" -n __bat_no_excl_args + +complete -c $bat -l theme-light -x -a "(command $bat --list-themes | command cat)" -d "Set the syntax highlighting theme for light backgrounds" -n __bat_no_excl_args + complete -c $bat -s V -l version -f -d "Show version information" -n __fish_is_first_arg complete -c $bat -l wrap -x -a "$wrap_opts" -d "Text-wrapping mode" -n __bat_no_excl_args diff --git a/assets/completions/bat.zsh.in b/assets/completions/bat.zsh.in index 7d03abb3..4a598437 100644 --- a/assets/completions/bat.zsh.in +++ b/assets/completions/bat.zsh.in @@ -40,9 +40,12 @@ _{{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)' + --detect-color-scheme="[specify when to detect the terminal's color scheme]:when:(auto never always)" --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' + '(--theme-dark)'--theme-dark='[set the color theme for syntax highlighting for dark backgrounds]:theme:->themes' + '(--theme-light)'--theme-light='[set the color theme for syntax highlighting for light backgrounds]:theme:->themes' '(: --list-themes --list-languages -L)'--list-themes'[show all supported highlighting themes]' --style='[comma-separated list of style elements to display]: : _values "style [default]" default auto full plain changes header header-filename header-filesize grid rule numbers snip' diff --git a/assets/manual/bat.1.in b/assets/manual/bat.1.in index 2bc0a3a5..5dcabe2d 100644 --- a/assets/manual/bat.1.in +++ b/assets/manual/bat.1.in @@ -117,6 +117,24 @@ 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 +.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\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 \ @@ -152,9 +170,23 @@ will use JSON syntax, and ignore '.dev' .HP \fB\-\-theme\fR .IP -Set the theme for syntax highlighting. Use '\-\-list\-themes' to see all available themes. -To set a default theme, add the '\-\-theme="..."' option to the configuration file or -export the BAT_THEME environment variable (e.g.: export BAT_THEME="..."). +Set the theme for syntax highlighting. Use \fB\-\-list\-themes\fP to see all available themes. +To set a default theme, add the \fB\-\-theme="..."\fP option to the configuration file or +export the \fBBAT_THEME\fP environment variable (e.g.: \fBexport BAT_THEME="..."\fP). +.HP +\fB\-\-theme\-dark\fR +.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 +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 +.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 +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 \fB\-\-list\-themes\fR .IP From 14ce668a1d043b9ecdbdf99e6832923ba3576031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Tue, 16 Apr 2024 14:43:27 +0200 Subject: [PATCH 10/53] Add generated powershell completion to ignore list --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a3ea8cff..fbfe6ac6 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ **/*.rs.bk # Generated files +/assets/completions/_bat.ps1 /assets/completions/bat.bash /assets/completions/bat.fish /assets/completions/bat.zsh From ff81cfd584ca873fcad186193247af51c4f71627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Tue, 16 Apr 2024 14:43:31 +0200 Subject: [PATCH 11/53] Move actual detection into library --- Cargo.toml | 3 +- src/bin/bat/app.rs | 43 +-------------- src/theme.rs | 133 +++++++++++++++++++++++++++++++-------------- 3 files changed, 95 insertions(+), 84 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index affce17f..62ae693c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,14 +13,13 @@ edition = '2021' rust-version = "1.70" [features] -default = ["application"] +default = ["application", "detect-color-scheme"] # Feature required for bat the application. Should be disabled when depending on # bat as a library. application = [ "bugreport", "build-assets", "git", - "detect-color-scheme", "minimal-application", ] # Mainly for developers that want to iterate quickly diff --git a/src/bin/bat/app.rs b/src/bin/bat/app.rs index d9e1662b..711ab1c6 100644 --- a/src/bin/bat/app.rs +++ b/src/bin/bat/app.rs @@ -9,9 +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, ColorScheme, ColorSchemeDetector, DetectColorScheme, ThemeOptions, ThemeRequest, -}; +use bat::theme::{theme, DetectColorScheme, ThemeOptions, ThemeRequest}; use bat::StripAnsiMode; use clap::ArgMatches; @@ -256,7 +254,7 @@ impl App { Some("auto") => StripAnsiMode::Auto, _ => unreachable!("other values for --strip-ansi are not allowed"), }, - theme: theme(self.theme_options(), &TerminalColorSchemeDetector), + theme: theme(self.theme_options()), visible_lines: match self.matches.try_contains_id("diff").unwrap_or_default() && self.matches.get_flag("diff") { @@ -447,40 +445,3 @@ impl App { } } } - -struct TerminalColorSchemeDetector; - -#[cfg(feature = "detect-color-scheme")] -impl ColorSchemeDetector for TerminalColorSchemeDetector { - fn should_detect(&self) -> bool { - // Querying the terminal for its colors via OSC 10 / OSC 11 requires "exclusive" access - // since we read/write from the terminal and enable/disable raw mode. - // This causes race conditions with pagers such as less when they are attached to the - // same terminal as us. - // - // This is usually only an issue when the output is manually piped to a pager. - // For example: `bat Cargo.toml | less`. - // Otherwise, if we start the pager ourselves, then there's no race condition - // since the pager is started *after* the color is detected. - std::io::stdout().is_terminal() - } - - fn detect(&self) -> Option { - use terminal_colorsaurus::{color_scheme, ColorScheme as ColorsaurusScheme, QueryOptions}; - match color_scheme(QueryOptions::default()).ok()? { - ColorsaurusScheme::Dark => Some(ColorScheme::Dark), - ColorsaurusScheme::Light => Some(ColorScheme::Light), - } - } -} - -#[cfg(not(feature = "detect-color-scheme"))] -impl ColorSchemeDetector for TerminalColorSchemeDetector { - fn should_detect(&self) -> bool { - false - } - - fn detect(&self) -> Option { - None - } -} diff --git a/src/theme.rs b/src/theme.rs index ec3e3d34..2491f9bd 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -1,35 +1,13 @@ +//! Utilities for choosing an appropriate theme for syntax highlighting. + use std::convert::Infallible; +use std::io::IsTerminal as _; use std::str::FromStr; /// Chooses an appropriate theme or falls back to a default theme /// based on the user-provided options and the color scheme of the terminal. -pub fn theme(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 = detect(options.detect_color_scheme, detector).unwrap_or_default(); - 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 { - match color_scheme { - ColorScheme::Dark => options.theme_dark, - ColorScheme::Light => options.theme_light, - } -} - -fn detect(when: DetectColorScheme, detector: &dyn ColorSchemeDetector) -> Option { - let should_detect = match when { - DetectColorScheme::Auto => detector.should_detect(), - DetectColorScheme::Always => true, - DetectColorScheme::Never => false, - }; - should_detect.then(|| detector.detect()).flatten() +pub fn theme(options: ThemeOptions) -> String { + theme_from_detector(options, &TerminalColorSchemeDetector) } pub(crate) const fn default_theme(color_scheme: ColorScheme) -> &'static str { @@ -40,6 +18,7 @@ pub(crate) const fn default_theme(color_scheme: ColorScheme) -> &'static str { } /// Options for configuring the theme used for syntax highlighting. +/// Used together with [`theme`]. #[derive(Debug, Default)] pub struct ThemeOptions { /// Always use this theme regardless of the terminal's background color. @@ -48,7 +27,7 @@ pub struct ThemeOptions { pub theme_dark: Option, /// The theme to use in case the terminal uses a light background with dark text. pub theme_light: Option, - /// Detect whether or not the terminal is dark or light by querying for its colors. + /// Whether or not to test if the terminal is dark or light by querying for its colors. pub detect_color_scheme: DetectColorScheme, } @@ -82,7 +61,7 @@ impl ThemeRequest { #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] pub enum DetectColorScheme { - /// Only query the terminal for its colors when appropriate (e.g. when the the output is not redirected). + /// Only query the terminal for its colors when appropriate (i.e. when the the output is not redirected). #[default] Auto, /// Always query the terminal for its colors. @@ -99,12 +78,78 @@ pub enum ColorScheme { Light, } -pub trait ColorSchemeDetector { +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 = detect(options.detect_color_scheme, detector).unwrap_or_default(); + 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 { + match color_scheme { + ColorScheme::Dark => options.theme_dark, + ColorScheme::Light => options.theme_light, + } +} + +fn detect(when: DetectColorScheme, detector: &dyn ColorSchemeDetector) -> Option { + let should_detect = match when { + DetectColorScheme::Auto => detector.should_detect(), + DetectColorScheme::Always => true, + DetectColorScheme::Never => false, + }; + should_detect.then(|| detector.detect()).flatten() +} + +trait ColorSchemeDetector { fn should_detect(&self) -> bool; fn detect(&self) -> Option; } +struct TerminalColorSchemeDetector; + +#[cfg(feature = "detect-color-scheme")] +impl ColorSchemeDetector for TerminalColorSchemeDetector { + fn should_detect(&self) -> bool { + // Querying the terminal for its colors via OSC 10 / OSC 11 requires "exclusive" access + // since we read/write from the terminal and enable/disable raw mode. + // This causes race conditions with pagers such as less when they are attached to the + // same terminal as us. + // + // This is usually only an issue when the output is manually piped to a pager. + // For example: `bat Cargo.toml | less`. + // Otherwise, if we start the pager ourselves, then there's no race condition + // since the pager is started *after* the color is detected. + std::io::stdout().is_terminal() + } + + fn detect(&self) -> Option { + use terminal_colorsaurus::{color_scheme, ColorScheme as ColorsaurusScheme, QueryOptions}; + match color_scheme(QueryOptions::default()).ok()? { + ColorsaurusScheme::Dark => Some(ColorScheme::Dark), + ColorsaurusScheme::Light => Some(ColorScheme::Light), + } + } +} + +#[cfg(not(feature = "detect-color-scheme"))] +impl ColorSchemeDetector for TerminalColorSchemeDetector { + fn should_detect(&self) -> bool { + false + } + + fn detect(&self) -> Option { + None + } +} + #[cfg(test)] impl ColorSchemeDetector for Option { fn should_detect(&self) -> bool { @@ -134,7 +179,7 @@ mod tests { detect_color_scheme: Never, ..Default::default() }; - _ = theme(options, &detector); + _ = theme_from_detector(options, &detector); assert!(!detector.was_called.get()); } @@ -149,7 +194,7 @@ mod tests { detect_color_scheme: Always, ..Default::default() }; - _ = theme(options, &detector); + _ = theme_from_detector(options, &detector); assert!(detector.was_called.get()); } } @@ -157,14 +202,14 @@ mod tests { #[test] fn called_for_auto_if_should_detect() { let detector = DetectorStub::should_detect(Some(Dark)); - _ = theme(ThemeOptions::default(), &detector); + _ = theme_from_detector(ThemeOptions::default(), &detector); assert!(detector.was_called.get()); } #[test] fn not_called_for_auto_if_not_should_detect() { let detector = DetectorStub::should_not_detect(); - _ = theme(ThemeOptions::default(), &detector); + _ = theme_from_detector(ThemeOptions::default(), &detector); assert!(!detector.was_called.get()); } } @@ -188,7 +233,7 @@ mod tests { }, ] { let detector = ConstantDetector(color_scheme); - assert_eq!("Theme", theme(options, &detector)); + assert_eq!("Theme", theme_from_detector(options, &detector)); } } } @@ -200,7 +245,7 @@ mod tests { ..Default::default() }; let detector = DetectorStub::should_detect(Some(Dark)); - _ = theme(options, &detector); + _ = theme_from_detector(options, &detector); assert!(!detector.was_called.get()); } } @@ -213,7 +258,7 @@ mod tests { let detector = ConstantDetector(None); assert_eq!( default_theme(ColorScheme::Dark), - theme(ThemeOptions::default(), &detector) + theme_from_detector(ThemeOptions::default(), &detector) ); } @@ -227,7 +272,10 @@ mod tests { ..Default::default() }; let detector = ConstantDetector(color_scheme); - assert_eq!(default_theme(ColorScheme::Dark), theme(options, &detector)); + assert_eq!( + default_theme(ColorScheme::Dark), + theme_from_detector(options, &detector) + ); } } @@ -243,7 +291,10 @@ mod tests { }, ] { let detector = ConstantDetector(Some(color_scheme)); - assert_eq!(default_theme(color_scheme), theme(options, &detector)); + assert_eq!( + default_theme(color_scheme), + theme_from_detector(options, &detector) + ); } } } @@ -261,7 +312,7 @@ mod tests { ..Default::default() }; let detector = ConstantDetector(color_scheme); - assert_eq!("Dark", theme(options, &detector)); + assert_eq!("Dark", theme_from_detector(options, &detector)); } } @@ -273,7 +324,7 @@ mod tests { ..Default::default() }; let detector = ConstantDetector(Some(ColorScheme::Light)); - assert_eq!("Light", theme(options, &detector)); + assert_eq!("Light", theme_from_detector(options, &detector)); } } From 30b0143ccf93edac1310fca522a89550d5566676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Thu, 18 Jul 2024 15:44:33 +0200 Subject: [PATCH 12/53] Make default_theme pub --- src/theme.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/theme.rs b/src/theme.rs index 2491f9bd..b60184fb 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -10,7 +10,9 @@ pub fn theme(options: ThemeOptions) -> String { theme_from_detector(options, &TerminalColorSchemeDetector) } -pub(crate) const fn default_theme(color_scheme: ColorScheme) -> &'static str { +/// The default theme, suitable for the given color scheme. +/// Use [`theme`], if you want to automatically detect the color scheme from the terminal. +pub const fn default_theme(color_scheme: ColorScheme) -> &'static str { match color_scheme { ColorScheme::Dark => "Monokai Extended", ColorScheme::Light => "Monokai Extended Light", From 6498615f5fb047bef7d84072747676a74fa89c4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Tue, 16 Apr 2024 14:43:33 +0200 Subject: [PATCH 13/53] Improve upon the documentation --- src/pretty_printer.rs | 4 +++- src/theme.rs | 17 ++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/pretty_printer.rs b/src/pretty_printer.rs index eb123ea3..51c9af80 100644 --- a/src/pretty_printer.rs +++ b/src/pretty_printer.rs @@ -245,7 +245,9 @@ impl<'a> PrettyPrinter<'a> { self } - /// Specify the highlighting theme + /// Specify the highlighting theme. + /// You can use [`crate::theme::theme`] to pick a theme based on user preferences + /// and the terminal's background color. pub fn theme(&mut self, theme: impl AsRef) -> &mut Self { self.config.theme = theme.as_ref().to_owned(); self diff --git a/src/theme.rs b/src/theme.rs index b60184fb..54db307b 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -11,7 +11,7 @@ pub fn theme(options: ThemeOptions) -> String { } /// The default theme, suitable for the given color scheme. -/// Use [`theme`], if you want to automatically detect the color scheme from the terminal. +/// Use [`theme`] if you want to automatically detect the color scheme from the terminal. pub const fn default_theme(color_scheme: ColorScheme) -> &'static str { match color_scheme { ColorScheme::Dark => "Monokai Extended", @@ -21,7 +21,7 @@ pub const fn default_theme(color_scheme: ColorScheme) -> &'static str { /// Options for configuring the theme used for syntax highlighting. /// Used together with [`theme`]. -#[derive(Debug, Default)] +#[derive(Debug, Default, PartialEq, Eq)] pub struct ThemeOptions { /// Always use this theme regardless of the terminal's background color. pub theme: Option, @@ -34,7 +34,14 @@ pub struct ThemeOptions { } /// The name of a theme or the default theme. -#[derive(Debug)] +/// +/// ``` +/// # use bat::theme::ThemeRequest; +/// # 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()); +/// ``` +#[derive(Debug, PartialEq, Eq, Hash)] pub enum ThemeRequest { Named(String), Default, @@ -61,7 +68,7 @@ impl ThemeRequest { } } -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] pub enum DetectColorScheme { /// Only query the terminal for its colors when appropriate (i.e. when the the output is not redirected). #[default] @@ -73,7 +80,7 @@ pub enum DetectColorScheme { } /// The color scheme used to pick a fitting theme. Defaults to [`ColorScheme::Dark`]. -#[derive(Default, Copy, Clone)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] pub enum ColorScheme { #[default] Dark, From e8ca6ec7c31d5cbb07334fc6a814d5df442bbe91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Tue, 16 Apr 2024 14:43:35 +0200 Subject: [PATCH 14/53] Remove cargo feature --- Cargo.toml | 5 ++--- src/theme.rs | 12 ------------ 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 62ae693c..47600d0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ edition = '2021' rust-version = "1.70" [features] -default = ["application", "detect-color-scheme"] +default = ["application"] # Feature required for bat the application. Should be disabled when depending on # bat as a library. application = [ @@ -35,7 +35,6 @@ git = ["git2"] # Support indicating git modifications paging = ["shell-words", "grep-cli"] # Support applying a pager on the output lessopen = ["run_script", "os_str_bytes"] # Support $LESSOPEN preprocessor build-assets = ["syntect/yaml-load", "syntect/plist-load", "regex", "walkdir"] -detect-color-scheme = ["dep:terminal-colorsaurus"] # You need to use one of these if you depend on bat as a library: regex-onig = ["syntect/regex-onig"] # Use the "oniguruma" regex engine @@ -69,7 +68,7 @@ bytesize = { version = "1.3.0" } encoding_rs = "0.8.34" os_str_bytes = { version = "~7.0", optional = true } run_script = { version = "^0.10.1", optional = true} -terminal-colorsaurus = { version = "0.4", optional = true } +terminal-colorsaurus = "0.4" [dependencies.git2] version = "0.18" diff --git a/src/theme.rs b/src/theme.rs index 54db307b..d518e0b2 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -124,7 +124,6 @@ trait ColorSchemeDetector { struct TerminalColorSchemeDetector; -#[cfg(feature = "detect-color-scheme")] impl ColorSchemeDetector for TerminalColorSchemeDetector { fn should_detect(&self) -> bool { // Querying the terminal for its colors via OSC 10 / OSC 11 requires "exclusive" access @@ -148,17 +147,6 @@ impl ColorSchemeDetector for TerminalColorSchemeDetector { } } -#[cfg(not(feature = "detect-color-scheme"))] -impl ColorSchemeDetector for TerminalColorSchemeDetector { - fn should_detect(&self) -> bool { - false - } - - fn detect(&self) -> Option { - None - } -} - #[cfg(test)] impl ColorSchemeDetector for Option { fn should_detect(&self) -> bool { From 594b1417f1854fbb5c1bdb9cdd27d880b0ca38f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Tue, 16 Apr 2024 14:43:39 +0200 Subject: [PATCH 15/53] Update readme --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 016fe834..81ce2202 100644 --- a/README.md +++ b/README.md @@ -482,8 +482,10 @@ the following command (you need [`fzf`](https://github.com/junegunn/fzf) for thi bat --list-themes | fzf --preview="bat --theme={} --color=always /path/to/file" ``` -`bat` looks good on a dark background by default. However, if your terminal uses a -light background, some themes like `GitHub` or `OneHalfLight` will work better for you. +`bat` automatically picks a fitting theme depending on your terminal's background color. +You can use the `--theme-light` / `--theme-light` options or the `BAT_THEME_DARK` / `BAT_THEME_LIGHT` environment variables +to customize the themes used. This is especially useful if you frequently switch between dark and light mode. + You can also use a custom theme by following the ['Adding new themes' section below](https://github.com/sharkdp/bat#adding-new-themes). From c3b190d45b50a4ab05663de1680dba3cd74d7ecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Tue, 16 Apr 2024 14:43:42 +0200 Subject: [PATCH 16/53] Disable color detection in test --- tests/integration_tests.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 8df4327c..0381f48c 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -405,6 +405,7 @@ fn no_args_doesnt_break() { // as the slave end of a pseudo terminal. Although both point to the same "file", bat should // not exit, because in this case it is safe to read and write to the same fd, which is why // this test exists. + let OpenptyResult { master, slave } = openpty(None, None).expect("Couldn't open pty."); let mut master = unsafe { File::from_raw_fd(master) }; let stdin_file = unsafe { File::from_raw_fd(slave) }; @@ -415,6 +416,7 @@ fn no_args_doesnt_break() { let mut child = bat_raw_command() .stdin(stdin) .stdout(stdout) + .env("TERM", "dumb") // Suppresses color detection .spawn() .expect("Failed to start."); From 06b645435a497e77e28ad6d7d3531b5a5415c695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Tue, 16 Apr 2024 14:43:44 +0200 Subject: [PATCH 17/53] Add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea47b58f..0aa1112a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - Syntax highlighting for JavaScript files that start with `#!/usr/bin/env bun` #2913 (@sharunkumar) - `bat --strip-ansi={never,always,auto}` to remove ANSI escape sequences from bat's input, see #2999 (@eth-p) - Add or remove individual style components without replacing all styles #2929 (@eth-p) +- Automatically choose theme based on the terminal's color scheme, see #2896 (@bash) ## Bugfixes From 1b0a6da4be97c7ab2b0e9b53db5a14ac4b1fad44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Tue, 16 Apr 2024 14:43:50 +0200 Subject: [PATCH 18/53] Use new `default_theme` fn for --list-themes --- src/bin/bat/main.rs | 10 +++++++--- src/theme.rs | 5 +++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/bin/bat/main.rs b/src/bin/bat/main.rs index 4528a60b..4dfb8124 100644 --- a/src/bin/bat/main.rs +++ b/src/bin/bat/main.rs @@ -30,12 +30,12 @@ use directories::PROJECT_DIRS; use globset::GlobMatcher; use bat::{ - assets::HighlightingAssets, config::Config, controller::Controller, error::*, input::Input, style::{StyleComponent, StyleComponents}, + theme::{color_scheme, default_theme, ColorScheme, DetectColorScheme}, MappingTarget, PagingMode, }; @@ -200,10 +200,14 @@ pub fn list_themes(cfg: &Config, config_dir: &Path, cache_dir: &Path) -> Result< let stdout = io::stdout(); let mut stdout = stdout.lock(); - let default_theme = HighlightingAssets::default_theme(); + let default_theme_name = default_theme(color_scheme(DetectColorScheme::Auto)); for theme in assets.themes() { - let default_theme_info = if default_theme == theme { + let default_theme_info = if default_theme_name == theme { " (default)" + } else if default_theme(ColorScheme::Dark) == theme { + " (default dark)" + } else if default_theme(ColorScheme::Light) == theme { + " (default light)" } else { "" }; diff --git a/src/theme.rs b/src/theme.rs index d518e0b2..ef5a8ae2 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -19,6 +19,11 @@ pub const fn default_theme(color_scheme: ColorScheme) -> &'static str { } } +/// Detects the color scheme from the terminal. +pub fn color_scheme(when: DetectColorScheme) -> ColorScheme { + detect(when, &TerminalColorSchemeDetector).unwrap_or_default() +} + /// Options for configuring the theme used for syntax highlighting. /// Used together with [`theme`]. #[derive(Debug, Default, PartialEq, Eq)] From 5c6974703e7db3a432be64f301cd08bd35135ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Wed, 1 May 2024 08:27:31 +0200 Subject: [PATCH 19/53] Respect --detect-color-scheme flag when listing themes --- src/bin/bat/app.rs | 17 ++++++++++------- src/bin/bat/main.rs | 11 ++++++++--- tests/integration_tests.rs | 16 +++++++--------- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/bin/bat/app.rs b/src/bin/bat/app.rs index 711ab1c6..606132f7 100644 --- a/src/bin/bat/app.rs +++ b/src/bin/bat/app.rs @@ -427,7 +427,16 @@ impl App { .matches .get_one::("theme-light") .map(|t| ThemeRequest::from_str(t).unwrap()); - let detect_color_scheme = match self + ThemeOptions { + theme, + theme_dark, + theme_light, + detect_color_scheme: self.detect_color_scheme(), + } + } + + pub(crate) fn detect_color_scheme(&self) -> DetectColorScheme { + match self .matches .get_one::("detect-color-scheme") .map(|s| s.as_str()) @@ -436,12 +445,6 @@ impl App { Some("never") => DetectColorScheme::Never, Some("always") => DetectColorScheme::Always, _ => unreachable!("other values for --detect-color-scheme are not allowed"), - }; - ThemeOptions { - theme, - theme_dark, - theme_light, - detect_color_scheme, } } } diff --git a/src/bin/bat/main.rs b/src/bin/bat/main.rs index 4dfb8124..95493a6d 100644 --- a/src/bin/bat/main.rs +++ b/src/bin/bat/main.rs @@ -189,7 +189,12 @@ fn theme_preview_file<'a>() -> Input<'a> { Input::from_reader(Box::new(BufReader::new(THEME_PREVIEW_DATA))) } -pub fn list_themes(cfg: &Config, config_dir: &Path, cache_dir: &Path) -> Result<()> { +pub fn list_themes( + cfg: &Config, + config_dir: &Path, + cache_dir: &Path, + detect_color_scheme: DetectColorScheme, +) -> Result<()> { let assets = assets_from_cache_or_binary(cfg.use_custom_assets, cache_dir)?; let mut config = cfg.clone(); let mut style = HashSet::new(); @@ -200,7 +205,7 @@ pub fn list_themes(cfg: &Config, config_dir: &Path, cache_dir: &Path) -> Result< let stdout = io::stdout(); let mut stdout = stdout.lock(); - let default_theme_name = default_theme(color_scheme(DetectColorScheme::Auto)); + let default_theme_name = default_theme(color_scheme(detect_color_scheme)); for theme in assets.themes() { let default_theme_info = if default_theme_name == theme { " (default)" @@ -375,7 +380,7 @@ fn run() -> Result { }; run_controller(inputs, &plain_config, cache_dir) } else if app.matches.get_flag("list-themes") { - list_themes(&config, config_dir, cache_dir)?; + list_themes(&config, config_dir, cache_dir, app.detect_color_scheme())?; Ok(true) } else if app.matches.get_flag("config-file") { println!("{}", config_file().to_string_lossy()); diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 0381f48c..23aed5bc 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -274,37 +274,35 @@ fn squeeze_limit_line_numbers() { #[test] fn list_themes_with_colors() { - #[cfg(target_os = "macos")] - let default_theme_chunk = "Monokai Extended Light\x1B[0m (default)"; - - #[cfg(not(target_os = "macos"))] let default_theme_chunk = "Monokai Extended\x1B[0m (default)"; + let default_light_theme_chunk = "Monokai Extended Light\x1B[0m (default light)"; bat() .arg("--color=always") + .arg("--detect-color-scheme=never") .arg("--list-themes") .assert() .success() .stdout(predicate::str::contains("DarkNeon").normalize()) .stdout(predicate::str::contains(default_theme_chunk).normalize()) + .stdout(predicate::str::contains(default_light_theme_chunk).normalize()) .stdout(predicate::str::contains("Output the square of a number.").normalize()); } #[test] fn list_themes_without_colors() { - #[cfg(target_os = "macos")] - let default_theme_chunk = "Monokai Extended Light (default)"; - - #[cfg(not(target_os = "macos"))] let default_theme_chunk = "Monokai Extended (default)"; + let default_light_theme_chunk = "Monokai Extended Light (default light)"; bat() .arg("--color=never") + .arg("--detect-color-scheme=never") .arg("--list-themes") .assert() .success() .stdout(predicate::str::contains("DarkNeon").normalize()) - .stdout(predicate::str::contains(default_theme_chunk).normalize()); + .stdout(predicate::str::contains(default_theme_chunk).normalize()) + .stdout(predicate::str::contains(default_light_theme_chunk).normalize()); } #[test] From abf9dada04b715494ae323ffdc51e1bb39854221 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Thu, 18 Jul 2024 15:49:25 +0200 Subject: [PATCH 20/53] Remove `HighlightingAssets::default_theme()` --- CHANGELOG.md | 3 +++ src/assets.rs | 57 --------------------------------------------------- 2 files changed, 3 insertions(+), 57 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0aa1112a..0cd76031 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,6 +70,9 @@ - [BREAKING] `SyntaxMapping::mappings` is replaced by `SyntaxMapping::{builtin,custom,all}_mappings` - Make `Controller::run_with_error_handler`'s error handler `FnMut`, see #2831 (@rhysd) - Improve compile time by 20%, see #2815 (@dtolnay) +- Add `theme::theme` for choosing an appropriate theme based on the + terminal's color scheme, see #2896 (@bash) + - [BREAKING] Remove `HighlightingAssets::default_theme`. Use `theme::default_theme` instead. # v0.24.0 diff --git a/src/assets.rs b/src/assets.rs index 857f416b..d32ccbd4 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -70,43 +70,6 @@ impl HighlightingAssets { } } - /// The default theme. - /// - /// ### Windows and Linux - /// - /// Windows and most Linux distributions has a dark terminal theme by - /// default. On these platforms, this function always returns a theme that - /// looks good on a dark background. - /// - /// ### macOS - /// - /// On macOS the default terminal background is light, but it is common that - /// Dark Mode is active, which makes the terminal background dark. On this - /// platform, the default theme depends on - /// ```bash - /// defaults read -globalDomain AppleInterfaceStyle - /// ``` - /// To avoid the overhead of the check on macOS, simply specify a theme - /// explicitly via `--theme`, `BAT_THEME`, or `~/.config/bat`. - /// - /// See and - /// for more context. - #[deprecated(note = "use bat::theme::theme instead")] - pub fn default_theme() -> &'static str { - #[cfg(not(target_os = "macos"))] - { - default_theme(ColorScheme::Dark) - } - #[cfg(target_os = "macos")] - { - if macos_dark_mode_active() { - default_theme(ColorScheme::Dark) - } else { - default_theme(ColorScheme::Light) - } - } - } - pub fn from_cache(cache_path: &Path) -> Result { Ok(HighlightingAssets::new( SerializedSyntaxSet::FromFile(cache_path.join("syntaxes.bin")), @@ -389,26 +352,6 @@ fn asset_from_cache( .map_err(|_| format!("Could not parse cached {description}").into()) } -#[cfg(target_os = "macos")] -fn macos_dark_mode_active() -> bool { - const PREFERENCES_FILE: &str = "Library/Preferences/.GlobalPreferences.plist"; - const STYLE_KEY: &str = "AppleInterfaceStyle"; - - let preferences_file = home::home_dir() - .map(|home| home.join(PREFERENCES_FILE)) - .expect("Could not get home directory"); - - match plist::Value::from_file(preferences_file).map(|file| file.into_dictionary()) { - Ok(Some(preferences)) => match preferences.get(STYLE_KEY).and_then(|val| val.as_string()) { - Some(value) => value == "Dark", - // If the key does not exist, then light theme is currently in use. - None => false, - }, - // Unreachable, in theory. All macOS users have a home directory and preferences file setup. - Ok(None) | Err(_) => true, - } -} - #[cfg(test)] mod tests { use super::*; From b9b981f6572c612cce443a8fff0b5fb9c24d3868 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Thu, 18 Jul 2024 17:36:57 +0200 Subject: [PATCH 21/53] Generalize --detect-color-scheme to --color-scheme --- assets/completions/_bat.ps1.in | 2 +- assets/completions/bat.bash.in | 6 ++- assets/completions/bat.fish.in | 10 +++- assets/completions/bat.zsh.in | 2 +- doc/long-help.txt | 26 +++++----- doc/short-help.txt | 4 +- src/bin/bat/app.rs | 18 ++++--- src/bin/bat/clap_app.rs | 34 ++++++------- src/bin/bat/main.rs | 13 +++-- src/theme.rs | 90 +++++++++++++++++++++++++++------- tests/integration_tests.rs | 4 +- 11 files changed, 140 insertions(+), 69 deletions(-) diff --git a/assets/completions/_bat.ps1.in b/assets/completions/_bat.ps1.in index 5635dea2..ac66ccc8 100644 --- a/assets/completions/_bat.ps1.in +++ b/assets/completions/_bat.ps1.in @@ -32,7 +32,7 @@ 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('--detect-color-scheme', 'detect-color-scheme', [CompletionResultType]::ParameterName, 'When to detect the terminal''s color scheme (*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++'').') diff --git a/assets/completions/bat.bash.in b/assets/completions/bat.bash.in index a02c5a04..0a01a054 100644 --- a/assets/completions/bat.bash.in +++ b/assets/completions/bat.bash.in @@ -100,10 +100,12 @@ _bat() { COMPREPLY=($(compgen -W "auto never character" -- "$cur")) return 0 ;; - --color | --decorations | --paging | --detect-color-scheme) + --color | --decorations | --paging) 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 @@ -166,7 +168,6 @@ _bat() { --color --italic-text --decorations - --detect-color-scheme --force-colorization --paging --pager @@ -175,6 +176,7 @@ _bat() { --theme --theme-dark --theme-light + --color-scheme --list-themes --squeeze-blank --squeeze-limit diff --git a/assets/completions/bat.fish.in b/assets/completions/bat.fish.in index 7bd0ebca..33cf8264 100644 --- a/assets/completions/bat.fish.in +++ b/assets/completions/bat.fish.in @@ -99,7 +99,13 @@ set -l color_opts ' ' set -l decorations_opts $color_opts set -l paging_opts $color_opts -set -l detect_color_scheme_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 ' @@ -144,7 +150,7 @@ 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 detect-color-scheme -x -a "$detect_color_scheme_opts" -d "When to detect the terminal's color scheme" -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 diff --git a/assets/completions/bat.zsh.in b/assets/completions/bat.zsh.in index 4a598437..4bcae11c 100644 --- a/assets/completions/bat.zsh.in +++ b/assets/completions/bat.zsh.in @@ -40,7 +40,7 @@ _{{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)' - --detect-color-scheme="[specify when to detect the terminal's color scheme]: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' diff --git a/doc/long-help.txt b/doc/long-help.txt index 86e9a532..c374a039 100644 --- a/doc/long-help.txt +++ b/doc/long-help.txt @@ -114,22 +114,22 @@ Options: add the '--theme="..."' option to the configuration file or export the BAT_THEME environment variable (e.g.: export BAT_THEME="..."). - --detect-color-scheme - Specify when to query the terminal for its colors in order to pick an appropriate 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 the terminal's colors. + --color-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): - Only query the terminals colors if the output is not redirected. This is to prevent - race conditions with pagers such as less. - * never - Never query the terminal for its colors and assume that the terminal has a dark - background. - * always - Always query the terminal for its colors, regardless of whether or not the output is - redirected. + 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 Sets the theme name for syntax highlighting used when the terminal uses a light diff --git a/doc/short-help.txt b/doc/short-help.txt index 3e369229..f17a6d9d 100644 --- a/doc/short-help.txt +++ b/doc/short-help.txt @@ -41,8 +41,8 @@ Options: Use the specified syntax for files matching the glob pattern ('*.cpp:C++'). --theme Set the color theme for syntax highlighting. - --detect-color-scheme - Specify when to query the terminal for its colors. + --color-scheme + Specify whether to choose a dark or light theme. --theme-light Sets the color theme for syntax highlighting used for light backgrounds. --theme-dark diff --git a/src/bin/bat/app.rs b/src/bin/bat/app.rs index 606132f7..d2e5b4db 100644 --- a/src/bin/bat/app.rs +++ b/src/bin/bat/app.rs @@ -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, DetectColorScheme, ThemeOptions, ThemeRequest}; +use bat::theme::{theme, ColorSchemePreference, DetectColorScheme, ThemeOptions, ThemeRequest}; use bat::StripAnsiMode; use clap::ArgMatches; @@ -431,20 +431,22 @@ impl App { theme, theme_dark, theme_light, - detect_color_scheme: self.detect_color_scheme(), + color_scheme: self.color_scheme_preference(), } } - pub(crate) fn detect_color_scheme(&self) -> DetectColorScheme { + pub(crate) fn color_scheme_preference(&self) -> ColorSchemePreference { match self .matches - .get_one::("detect-color-scheme") + .get_one::("color-scheme") .map(|s| s.as_str()) { - Some("auto") => DetectColorScheme::Auto, - Some("never") => DetectColorScheme::Never, - Some("always") => DetectColorScheme::Always, - _ => unreachable!("other values for --detect-color-scheme are not allowed"), + 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"), } } } diff --git a/src/bin/bat/clap_app.rs b/src/bin/bat/clap_app.rs index 6abdab9c..0857dba4 100644 --- a/src/bin/bat/clap_app.rs +++ b/src/bin/bat/clap_app.rs @@ -384,30 +384,30 @@ pub fn build_app(interactive_output: bool) -> Command { ), ) .arg( - Arg::new("detect-color-scheme") - .long("detect-color-scheme") - .overrides_with("detect-color-scheme") - .value_name("when") - .value_parser(["auto", "never", "always"]) + 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 when to query the terminal for its colors.") + .help("Specify whether to choose a dark or light theme.") .long_help( - "Specify when to query the terminal for its colors \ - in order to pick an appropriate syntax highlighting theme. \ + "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 the terminal's colors.\n\n\ + You may also use '--theme' to set a theme that is used regardless of this choice.\n\n\ Possible values:\n\ - * auto (default):\n \ - Only query the terminals colors if the output is not redirected. \ + * 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\ - * never\n \ - Never query the terminal for its colors \ - and assume that the terminal has a dark background.\n\ - * always\n \ - Always query the terminal for its colors, \ - regardless of whether or not the output is redirected."), + * '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") diff --git a/src/bin/bat/main.rs b/src/bin/bat/main.rs index 95493a6d..891390c1 100644 --- a/src/bin/bat/main.rs +++ b/src/bin/bat/main.rs @@ -35,7 +35,7 @@ use bat::{ error::*, input::Input, style::{StyleComponent, StyleComponents}, - theme::{color_scheme, default_theme, ColorScheme, DetectColorScheme}, + theme::{color_scheme, default_theme, ColorScheme, ColorSchemePreference}, MappingTarget, PagingMode, }; @@ -193,7 +193,7 @@ pub fn list_themes( cfg: &Config, config_dir: &Path, cache_dir: &Path, - detect_color_scheme: DetectColorScheme, + color_scheme_pref: ColorSchemePreference, ) -> Result<()> { let assets = assets_from_cache_or_binary(cfg.use_custom_assets, cache_dir)?; let mut config = cfg.clone(); @@ -205,7 +205,7 @@ pub fn list_themes( let stdout = io::stdout(); let mut stdout = stdout.lock(); - let default_theme_name = default_theme(color_scheme(detect_color_scheme)); + let default_theme_name = default_theme(color_scheme(color_scheme_pref)); for theme in assets.themes() { let default_theme_info = if default_theme_name == theme { " (default)" @@ -380,7 +380,12 @@ fn run() -> Result { }; run_controller(inputs, &plain_config, cache_dir) } else if app.matches.get_flag("list-themes") { - list_themes(&config, config_dir, cache_dir, app.detect_color_scheme())?; + list_themes( + &config, + config_dir, + cache_dir, + app.color_scheme_preference(), + )?; Ok(true) } else if app.matches.get_flag("config-file") { println!("{}", config_file().to_string_lossy()); diff --git a/src/theme.rs b/src/theme.rs index ef5a8ae2..1c6d7e55 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -20,8 +20,8 @@ pub const fn default_theme(color_scheme: ColorScheme) -> &'static str { } /// Detects the color scheme from the terminal. -pub fn color_scheme(when: DetectColorScheme) -> ColorScheme { - detect(when, &TerminalColorSchemeDetector).unwrap_or_default() +pub fn color_scheme(preference: ColorSchemePreference) -> ColorScheme { + color_scheme_impl(preference, &TerminalColorSchemeDetector) } /// Options for configuring the theme used for syntax highlighting. @@ -34,8 +34,8 @@ pub struct ThemeOptions { pub theme_dark: Option, /// The theme to use in case the terminal uses a light background with dark text. pub theme_light: Option, - /// Whether or not to test if the terminal is dark or light by querying for its colors. - pub detect_color_scheme: DetectColorScheme, + /// How to choose between dark and light. + pub color_scheme: ColorSchemePreference, } /// The name of a theme or the default theme. @@ -73,6 +73,25 @@ impl ThemeRequest { } } +/// How to choose between dark and light. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ColorSchemePreference { + /// Detect the color scheme from the terminal. + Auto(DetectColorScheme), + /// Use a dark theme. + Dark, + /// Use a light theme. + Light, + /// Detect the color scheme from the OS instead (macOS only). + System, +} + +impl Default for ColorSchemePreference { + fn default() -> Self { + Self::Auto(DetectColorScheme::default()) + } +} + #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] pub enum DetectColorScheme { /// Only query the terminal for its colors when appropriate (i.e. when the the output is not redirected). @@ -80,8 +99,6 @@ pub enum DetectColorScheme { Auto, /// Always query the terminal for its colors. Always, - /// Never query the terminal for its colors. - Never, } /// The color scheme used to pick a fitting theme. Defaults to [`ColorScheme::Dark`]. @@ -92,13 +109,25 @@ pub enum ColorScheme { Light, } +fn color_scheme_impl( + pref: ColorSchemePreference, + detector: &dyn ColorSchemeDetector, +) -> ColorScheme { + match pref { + ColorSchemePreference::Auto(when) => detect(when, detector).unwrap_or_default(), + ColorSchemePreference::Dark => ColorScheme::Dark, + ColorSchemePreference::Light => ColorScheme::Light, + ColorSchemePreference::System => color_scheme_from_system().unwrap_or_default(), + } +} + 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 = detect(options.detect_color_scheme, detector).unwrap_or_default(); + 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()) @@ -116,7 +145,6 @@ fn detect(when: DetectColorScheme, detector: &dyn ColorSchemeDetector) -> Option let should_detect = match when { DetectColorScheme::Auto => detector.should_detect(), DetectColorScheme::Always => true, - DetectColorScheme::Never => false, }; should_detect.then(|| detector.detect()).flatten() } @@ -152,6 +180,31 @@ impl ColorSchemeDetector for TerminalColorSchemeDetector { } } +#[cfg(not(target_os = "macos"))] +fn color_scheme_from_system() -> Option { + None +} + +#[cfg(target_os = "macos")] +fn color_scheme_from_system() -> Option { + const PREFERENCES_FILE: &str = "Library/Preferences/.GlobalPreferences.plist"; + const STYLE_KEY: &str = "AppleInterfaceStyle"; + + let preferences_file = home::home_dir() + .map(|home| home.join(PREFERENCES_FILE)) + .expect("Could not get home directory"); + + match plist::Value::from_file(preferences_file).map(|file| file.into_dictionary()) { + Ok(Some(preferences)) => match preferences.get(STYLE_KEY).and_then(|val| val.as_string()) { + Some(value) if value == "Dark" => Some(ColorScheme::Dark), + // If the key does not exist, then light theme is currently in use. + Some(_) | None => Some(ColorScheme::Light), + }, + // Unreachable, in theory. All macOS users have a home directory and preferences file setup. + Ok(None) | Err(_) => None, + } +} + #[cfg(test)] impl ColorSchemeDetector for Option { fn should_detect(&self) -> bool { @@ -166,6 +219,7 @@ impl ColorSchemeDetector for Option { #[cfg(test)] mod tests { use super::ColorScheme::*; + use super::ColorSchemePreference as Pref; use super::DetectColorScheme::*; use super::*; use std::cell::Cell; @@ -175,14 +229,16 @@ mod tests { use super::*; #[test] - fn not_called_for_never() { - let detector = DetectorStub::should_detect(Some(Dark)); - let options = ThemeOptions { - detect_color_scheme: Never, - ..Default::default() - }; - _ = theme_from_detector(options, &detector); - assert!(!detector.was_called.get()); + fn not_called_for_dark_or_light() { + for pref in [Pref::Dark, Pref::Light] { + let detector = DetectorStub::should_detect(Some(Dark)); + let options = ThemeOptions { + color_scheme: pref, + ..Default::default() + }; + _ = theme_from_detector(options, &detector); + assert!(!detector.was_called.get()); + } } #[test] @@ -193,7 +249,7 @@ mod tests { ]; for detector in detectors { let options = ThemeOptions { - detect_color_scheme: Always, + color_scheme: Pref::Auto(Always), ..Default::default() }; _ = theme_from_detector(options, &detector); diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 23aed5bc..e4b73c59 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -279,7 +279,7 @@ fn list_themes_with_colors() { bat() .arg("--color=always") - .arg("--detect-color-scheme=never") + .arg("--color-scheme=dark") .arg("--list-themes") .assert() .success() @@ -296,7 +296,7 @@ fn list_themes_without_colors() { bat() .arg("--color=never") - .arg("--detect-color-scheme=never") + .arg("--color-scheme=dark") .arg("--list-themes") .assert() .success() From 7f089ead62508675749fe3da5f9d009ba38224cd Mon Sep 17 00:00:00 2001 From: einfachIrgendwer0815 <85333734+einfachIrgendwer0815@users.noreply.github.com> Date: Fri, 31 May 2024 18:20:16 +0200 Subject: [PATCH 22/53] Add option `--binary` `--binary` allows to specify how to deal with binary content. Current options are not printing anything or treating the binary data as text. --- doc/long-help.txt | 7 +++++++ doc/short-help.txt | 2 ++ src/bin/bat/app.rs | 6 ++++++ src/bin/bat/clap_app.rs | 16 ++++++++++++++++ src/config.rs | 5 ++++- src/lib.rs | 2 +- src/nonprintable_notation.rs | 12 ++++++++++++ src/printer.rs | 19 +++++++++++++++---- 8 files changed, 63 insertions(+), 6 deletions(-) diff --git a/doc/long-help.txt b/doc/long-help.txt index 2b03490f..87fb5d96 100644 --- a/doc/long-help.txt +++ b/doc/long-help.txt @@ -20,6 +20,13 @@ Options: * unicode (␇, ␊, ␀, ..) * caret (^G, ^J, ^@, ..) + --binary + How to treat binary content. (default: no-printing) + + Possible values: + * no-printing: do not print any binary content + * as-text: treat binary content as normal text + -p, --plain... Only show plain style, no decorations. This is an alias for '--style=plain'. When '-p' is used twice ('-pp'), it also disables automatic paging (alias for '--style=plain diff --git a/doc/short-help.txt b/doc/short-help.txt index 305bbf3d..16b9eb05 100644 --- a/doc/short-help.txt +++ b/doc/short-help.txt @@ -11,6 +11,8 @@ Options: Show non-printable characters (space, tab, newline, ..). --nonprintable-notation Set notation for non-printable characters. + --binary + How to treat binary content. (default: no-printing) -p, --plain... Show plain style (alias for '--style=plain'). -l, --language diff --git a/src/bin/bat/app.rs b/src/bin/bat/app.rs index d6628668..4d52c73d 100644 --- a/src/bin/bat/app.rs +++ b/src/bin/bat/app.rs @@ -9,6 +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::BinaryBehavior; use bat::StripAnsiMode; use clap::ArgMatches; @@ -193,6 +194,11 @@ impl App { Some("caret") => NonprintableNotation::Caret, _ => unreachable!("other values for --nonprintable-notation are not allowed"), }, + binary: match self.matches.get_one::("binary").map(|s| s.as_str()) { + Some("as-text") => BinaryBehavior::AsText, + Some("no-printing") => BinaryBehavior::NoPrinting, + _ => unreachable!("other values for --binary are not allowed"), + }, wrapping_mode: if self.interactive_output || maybe_term_width.is_some() { if !self.matches.get_flag("chop-long-lines") { match self.matches.get_one::("wrap").map(|s| s.as_str()) { diff --git a/src/bin/bat/clap_app.rs b/src/bin/bat/clap_app.rs index 33dde980..4327fa15 100644 --- a/src/bin/bat/clap_app.rs +++ b/src/bin/bat/clap_app.rs @@ -77,6 +77,22 @@ pub fn build_app(interactive_output: bool) -> Command { * caret (^G, ^J, ^@, ..)", ), ) + .arg( + Arg::new("binary") + .long("binary") + .action(ArgAction::Set) + .default_value("no-printing") + .value_parser(["no-printing", "as-text"]) + .value_name("behavior") + .hide_default_value(true) + .help("How to treat binary content. (default: no-printing)") + .long_help( + "How to treat binary content. (default: no-printing)\n\n\ + Possible values:\n \ + * no-printing: do not print any binary content\n \ + * as-text: treat binary content as normal text", + ), + ) .arg( Arg::new("plain") .overrides_with("plain") diff --git a/src/config.rs b/src/config.rs index eb7df8ee..eb44281c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,5 @@ use crate::line_range::{HighlightedLineRanges, LineRanges}; -use crate::nonprintable_notation::NonprintableNotation; +use crate::nonprintable_notation::{BinaryBehavior, NonprintableNotation}; #[cfg(feature = "paging")] use crate::paging::PagingMode; use crate::style::StyleComponents; @@ -44,6 +44,9 @@ pub struct Config<'a> { /// The configured notation for non-printable characters pub nonprintable_notation: NonprintableNotation, + /// How to treat binary content + pub binary: BinaryBehavior, + /// The character width of the terminal pub term_width: usize, diff --git a/src/lib.rs b/src/lib.rs index 23c4a800..a015913e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,7 +52,7 @@ mod terminal; mod vscreen; pub(crate) mod wrapping; -pub use nonprintable_notation::NonprintableNotation; +pub use nonprintable_notation::{BinaryBehavior, NonprintableNotation}; pub use preprocessor::StripAnsiMode; pub use pretty_printer::{Input, PrettyPrinter, Syntax}; pub use syntax_mapping::{MappingTarget, SyntaxMapping}; diff --git a/src/nonprintable_notation.rs b/src/nonprintable_notation.rs index ff09aca6..9f8d7cb8 100644 --- a/src/nonprintable_notation.rs +++ b/src/nonprintable_notation.rs @@ -10,3 +10,15 @@ pub enum NonprintableNotation { #[default] Unicode, } + +/// How to treat binary content +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +pub enum BinaryBehavior { + /// Do not print any binary content + #[default] + NoPrinting, + + /// Treat binary content as normal text + AsText, +} diff --git a/src/printer.rs b/src/printer.rs index e9bea3fd..3398b217 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -35,6 +35,7 @@ use crate::style::StyleComponent; use crate::terminal::{as_terminal_escaped, to_ansi_color}; use crate::vscreen::{AnsiStyle, EscapeSequence, EscapeSequenceIterator}; use crate::wrapping::WrappingMode; +use crate::BinaryBehavior; use crate::StripAnsiMode; const ANSI_UNDERLINE_ENABLE: EscapeSequence = EscapeSequence::CSI { @@ -458,7 +459,10 @@ impl<'a> Printer for InteractivePrinter<'a> { } if !self.config.style_components.header() { - if Some(ContentType::BINARY) == self.content_type && !self.config.show_nonprintable { + if Some(ContentType::BINARY) == self.content_type + && !self.config.show_nonprintable + && !matches!(self.config.binary, BinaryBehavior::AsText) + { writeln!( handle, "{}: Binary content from {} will not be printed to the terminal \ @@ -539,7 +543,10 @@ impl<'a> Printer for InteractivePrinter<'a> { })?; if self.config.style_components.grid() { - if self.content_type.map_or(false, |c| c.is_text()) || self.config.show_nonprintable { + if self.content_type.map_or(false, |c| c.is_text()) + || self.config.show_nonprintable + || matches!(self.config.binary, BinaryBehavior::AsText) + { self.print_horizontal_line(handle, '┼')?; } else { self.print_horizontal_line(handle, '┴')?; @@ -551,7 +558,9 @@ impl<'a> Printer for InteractivePrinter<'a> { fn print_footer(&mut self, handle: &mut OutputHandle, _input: &OpenedInput) -> Result<()> { if self.config.style_components.grid() - && (self.content_type.map_or(false, |c| c.is_text()) || self.config.show_nonprintable) + && (self.content_type.map_or(false, |c| c.is_text()) + || self.config.show_nonprintable + || matches!(self.config.binary, BinaryBehavior::AsText)) { self.print_horizontal_line(handle, '┴') } else { @@ -599,7 +608,9 @@ impl<'a> Printer for InteractivePrinter<'a> { .into() } else { let mut line = match self.content_type { - Some(ContentType::BINARY) | None => { + Some(ContentType::BINARY) | None + if !matches!(self.config.binary, BinaryBehavior::AsText) => + { return Ok(()); } Some(ContentType::UTF_16LE) => UTF_16LE.decode_with_bom_removal(line_buffer).0, From 7cc231b82b7f3ddd8395a783a0bf59e35a6b5b44 Mon Sep 17 00:00:00 2001 From: einfachIrgendwer0815 <85333734+einfachIrgendwer0815@users.noreply.github.com> Date: Fri, 31 May 2024 18:32:28 +0200 Subject: [PATCH 23/53] Test `--binary=as-text` --- tests/integration_tests.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 8df4327c..2cc4eb8b 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -1929,6 +1929,16 @@ fn show_all_with_unicode() { .stderr(""); } +#[test] +fn binary_as_text() { + bat() + .arg("--binary=as-text") + .arg("control_characters.txt") + .assert() + .stdout("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x7F") + .stderr(""); +} + #[test] fn no_paging_arg() { bat() From a769a3d8137f863634a14ae5741d7ee98299367f Mon Sep 17 00:00:00 2001 From: einfachIrgendwer0815 <85333734+einfachIrgendwer0815@users.noreply.github.com> Date: Fri, 31 May 2024 20:58:25 +0200 Subject: [PATCH 24/53] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea47b58f..ec662247 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - Syntax highlighting for JavaScript files that start with `#!/usr/bin/env bun` #2913 (@sharunkumar) - `bat --strip-ansi={never,always,auto}` to remove ANSI escape sequences from bat's input, see #2999 (@eth-p) - Add or remove individual style components without replacing all styles #2929 (@eth-p) +- Add option `--binary=as-text` for printing binary content, see issue #2974 and PR #2976 (@einfachIrgendwer0815) ## Bugfixes From 0c3b22e0f0ed1a371923b2e4df130f646c564772 Mon Sep 17 00:00:00 2001 From: einfachIrgendwer0815 <85333734+einfachIrgendwer0815@users.noreply.github.com> Date: Sat, 1 Jun 2024 00:13:03 +0200 Subject: [PATCH 25/53] Run syntax highlighting when `--binary=as-text` --- src/printer.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/printer.rs b/src/printer.rs index 3398b217..95017188 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -269,7 +269,8 @@ impl<'a> InteractivePrinter<'a> { .content_type .map_or(false, |c| c.is_binary() && !config.show_nonprintable); - let needs_to_match_syntax = !is_printing_binary + let needs_to_match_syntax = (!is_printing_binary + || matches!(config.binary, BinaryBehavior::AsText)) && (config.colored_output || config.strip_ansi == StripAnsiMode::Auto); let (is_plain_text, highlighter_from_set) = if needs_to_match_syntax { From bc42149a726b73e5e4cd6b8afdeb340a3ae23c9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Sun, 18 Aug 2024 14:59:14 +0200 Subject: [PATCH 26/53] Merge color scheme options into theme / BAT_THEME --- assets/completions/_bat.ps1.in | 1 - assets/completions/bat.bash.in | 3 - assets/completions/bat.fish.in | 9 --- assets/completions/bat.zsh.in | 1 - assets/manual/bat.1.in | 26 ++------ doc/long-help.txt | 17 ----- doc/short-help.txt | 2 - src/bin/bat/app.rs | 25 ++------ src/bin/bat/clap_app.rs | 26 -------- src/bin/bat/main.rs | 2 +- src/theme.rs | 111 ++++++++++++++++++++++----------- tests/integration_tests.rs | 2 - 12 files changed, 83 insertions(+), 142 deletions(-) diff --git a/assets/completions/_bat.ps1.in b/assets/completions/_bat.ps1.in index ac66ccc8..b6f62aae 100644 --- a/assets/completions/_bat.ps1.in +++ b/assets/completions/_bat.ps1.in @@ -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++'').') diff --git a/assets/completions/bat.bash.in b/assets/completions/bat.bash.in index 0a01a054..162d1c53 100644 --- a/assets/completions/bat.bash.in +++ b/assets/completions/bat.bash.in @@ -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 diff --git a/assets/completions/bat.fish.in b/assets/completions/bat.fish.in index 33cf8264..9907718f 100644 --- a/assets/completions/bat.fish.in +++ b/assets/completions/bat.fish.in @@ -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 diff --git a/assets/completions/bat.zsh.in b/assets/completions/bat.zsh.in index 4bcae11c..bec0d3c9 100644 --- a/assets/completions/bat.zsh.in +++ b/assets/completions/bat.zsh.in @@ -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' diff --git a/assets/manual/bat.1.in b/assets/manual/bat.1.in index 5dcabe2d..05239d50 100644 --- a/assets/manual/bat.1.in +++ b/assets/manual/bat.1.in @@ -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 -.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\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 .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 .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" diff --git a/doc/long-help.txt b/doc/long-help.txt index c374a039..8d5a3a5e 100644 --- a/doc/long-help.txt +++ b/doc/long-help.txt @@ -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 - 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 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 diff --git a/doc/short-help.txt b/doc/short-help.txt index f17a6d9d..d5c35059 100644 --- a/doc/short-help.txt +++ b/doc/short-help.txt @@ -41,8 +41,6 @@ Options: Use the specified syntax for files matching the glob pattern ('*.cpp:C++'). --theme Set the color theme for syntax highlighting. - --color-scheme - Specify whether to choose a dark or light theme. --theme-light Sets the color theme for syntax highlighting used for light backgrounds. --theme-dark diff --git a/src/bin/bat/app.rs b/src/bin/bat/app.rs index d2e5b4db..6d83c9c9 100644 --- a/src/bin/bat/app.rs +++ b/src/bin/bat/app.rs @@ -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::("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::("theme-dark") - .map(|t| ThemeRequest::from_str(t).unwrap()); + .map(|t| ThemeName::from_str(t).unwrap()); let theme_light = self .matches .get_one::("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::("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"), } } } diff --git a/src/bin/bat/clap_app.rs b/src/bin/bat/clap_app.rs index 0857dba4..e8056f3a 100644 --- a/src/bin/bat/clap_app.rs +++ b/src/bin/bat/clap_app.rs @@ -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") diff --git a/src/bin/bat/main.rs b/src/bin/bat/main.rs index 891390c1..09470504 100644 --- a/src/bin/bat/main.rs +++ b/src/bin/bat/main.rs @@ -384,7 +384,7 @@ fn run() -> Result { &config, config_dir, cache_dir, - app.color_scheme_preference(), + ColorSchemePreference::default(), )?; Ok(true) } else if app.matches.get_flag("config-file") { diff --git a/src/theme.rs b/src/theme.rs index 1c6d7e55..5f6460cc 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -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, + /// 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, + /// This corresponds with the `BAT_THEME_DARK` environment variable and the `--theme-dark` option. + pub theme_dark: Option, /// The theme to use in case the terminal uses a light background with dark text. - pub theme_light: Option, - /// 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, +} + +/// 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 { + 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 { 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 { +fn choose_theme(options: ThemeOptions, color_scheme: ColorScheme) -> Option { match color_scheme { ColorScheme::Dark => options.theme_dark, ColorScheme::Light => options.theme_light, @@ -220,7 +254,6 @@ impl ColorSchemeDetector for Option { 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)); diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index e4b73c59..582b255d 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -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() From 89ce06018340fda343072022000891e03a3b372b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Sun, 18 Aug 2024 20:32:23 +0200 Subject: [PATCH 27/53] Update help, man page and completions --- assets/completions/bat.bash.in | 7 ++++++- assets/completions/bat.fish.in | 10 +++++++++- assets/completions/bat.zsh.in | 10 ++++++++-- assets/manual/bat.1.in | 19 +++++++++++++++++-- doc/long-help.txt | 16 ++++++++++++---- src/bin/bat/clap_app.rs | 12 +++++++++--- src/theme.rs | 4 ++++ 7 files changed, 65 insertions(+), 13 deletions(-) diff --git a/assets/completions/bat.bash.in b/assets/completions/bat.bash.in index 162d1c53..90931f24 100644 --- a/assets/completions/bat.bash.in +++ b/assets/completions/bat.bash.in @@ -112,7 +112,12 @@ _bat() { COMPREPLY=($(compgen -c -- "$cur")) return 0 ;; - --theme | \ + --theme) + local IFS=$'\n' + COMPREPLY=($(compgen -W "auto${IFS}auto:always${IFS}auto:system${IFS}dark${IFS}light${IFS}$("$1" --list-themes)" -- "$cur")) + __bat_escape_completions + return 0 + ;; --theme-dark | \ --theme-light) local IFS=$'\n' diff --git a/assets/completions/bat.fish.in b/assets/completions/bat.fish.in index 9907718f..e2712706 100644 --- a/assets/completions/bat.fish.in +++ b/assets/completions/bat.fish.in @@ -129,6 +129,14 @@ set -l tabs_opts ' 8\t ' +set -l special_themes ' + auto\tdefault,\ Choose\ a\ theme\ based\ on\ dark\ or\ light\ mode + auto:always\tChoose\ a\ theme\ based\ on\ dark\ or\ light\ mode + auto:system\tChoose\ a\ theme\ based\ on\ dark\ or\ light\ mode + dark\tUse\ the\ theme\ specified\ by\ --theme-dark + light\tUse\ the\ theme\ specified\ by\ --theme-light +' + # Completions: complete -c $bat -l acknowledgements -d "Print acknowledgements" -n __fish_is_first_arg @@ -203,7 +211,7 @@ complete -c $bat -l tabs -x -a "$tabs_opts" -d "Set tab width" -n __bat_no_excl_ complete -c $bat -l terminal-width -x -d "Set terminal , +, or -" -n __bat_no_excl_args -complete -c $bat -l theme -x -a "(command $bat --list-themes | command cat)" -d "Set the syntax highlighting theme" -n __bat_no_excl_args +complete -c $bat -l theme -x -a "$special_themes(command $bat --list-themes | command cat)" -d "Set the syntax highlighting theme" -n __bat_no_excl_args complete -c $bat -l theme-dark -x -a "(command $bat --list-themes | command cat)" -d "Set the syntax highlighting theme for dark backgrounds" -n __bat_no_excl_args diff --git a/assets/completions/bat.zsh.in b/assets/completions/bat.zsh.in index bec0d3c9..76b981b6 100644 --- a/assets/completions/bat.zsh.in +++ b/assets/completions/bat.zsh.in @@ -42,7 +42,7 @@ _{{PROJECT_EXECUTABLE}}_main() { --decorations='[specify when to show the decorations]:when:(auto never always)' --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' + '(--theme)'--theme='[set the color theme for syntax highlighting]:theme:->theme_preferences' '(--theme-dark)'--theme-dark='[set the color theme for syntax highlighting for dark backgrounds]:theme:->themes' '(--theme-light)'--theme-light='[set the color theme for syntax highlighting for light backgrounds]:theme:->themes' '(: --list-themes --list-languages -L)'--list-themes'[show all supported highlighting themes]' @@ -84,7 +84,13 @@ _{{PROJECT_EXECUTABLE}}_main() { themes) local -a themes expl - themes=( ${(f)"$(_call_program themes {{PROJECT_EXECUTABLE}} --list-themes)"} ) + themes=(${(f)"$(_call_program themes {{PROJECT_EXECUTABLE}} --list-themes)"} ) + + _wanted themes expl 'theme' compadd -a themes && ret=0 + ;; + theme_preferences) + local -a themes expl + themes=(auto dark light auto:always auto:system ${(f)"$(_call_program themes {{PROJECT_EXECUTABLE}} --list-themes)"} ) _wanted themes expl 'theme' compadd -a themes && ret=0 ;; diff --git a/assets/manual/bat.1.in b/assets/manual/bat.1.in index 05239d50..ccc70629 100644 --- a/assets/manual/bat.1.in +++ b/assets/manual/bat.1.in @@ -155,20 +155,35 @@ will use JSON syntax, and ignore '.dev' Set the theme for syntax highlighting. Use \fB\-\-list\-themes\fP to see all available themes. To set a default theme, add the \fB\-\-theme="..."\fP option to the configuration file or export the \fBBAT_THEME\fP environment variable (e.g.: \fBexport BAT_THEME="..."\fP). + +Special values: +.RS +.IP "auto (\fIdefault\fR)" +Picks a dark or light theme depending on the terminal's colors. +Use \fB-\-theme\-light\fR and \fB-\-theme\-dark\fR to customize the selected theme. +.IP "auto:always" +Variation of \fBauto\fR where where the terminal's colors are detected even when the output is redirected. +.IP "auto:system (macOS only)" +Variation of \fBauto\fR where the color scheme is detected from the system-wide preference instead. +.IP "dark" +Use the dark theme specified by \fB-\-theme-dark\fR. +.IP "light" +Use the light theme specified by \fB-\-theme-light\fR. +.RE .HP \fB\-\-theme\-dark\fR .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 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. +This option only has an effect when \fB\-\-theme\fP option is set to \fBauto\fR or \fBdark\fR. .HP \fB\-\-theme\-light\fR .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 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. +This option only has an effect when \fB\-\-theme\fP option is set to \fBauto\fR or \fBlight\fR. .HP \fB\-\-list\-themes\fR .IP diff --git a/doc/long-help.txt b/doc/long-help.txt index 8d5a3a5e..e93c8a2d 100644 --- a/doc/long-help.txt +++ b/doc/long-help.txt @@ -109,10 +109,18 @@ Options: 'bat --ignored-suffix ".dev" my_file.json.dev' will use JSON syntax, and ignore '.dev' --theme - Set the theme for syntax highlighting. Note that this option overrides '--theme-dark' and - '--theme-light'. Use '--list-themes' to see all available themes. To set a default theme, - add the '--theme="..."' option to the configuration file or export the BAT_THEME - environment variable (e.g.: export BAT_THEME="..."). + Set the theme for syntax highlighting. Use '--list-themes' to see all available themes. To + set a default theme, add the '--theme="..."' option to the configuration file or export + the BAT_THEME environment variable (e.g.: export BAT_THEME="..."). + + Special values: + + * auto: Picks a dark or light theme depending on the terminal's colors (default). + Use '--theme-light' and '--theme-dark' to customize the selected theme. + * auto:always: Detect the terminal's colors even when the output is redirected. + * auto:system: Detect the color scheme from the system-wide preference (macOS only). + * dark: Use the dark theme specified by '--theme-dark'. + * light: Use the light theme specified by '--theme-light'. --theme-light Sets the theme name for syntax highlighting used when the terminal uses a light diff --git a/src/bin/bat/clap_app.rs b/src/bin/bat/clap_app.rs index e8056f3a..0fb34748 100644 --- a/src/bin/bat/clap_app.rs +++ b/src/bin/bat/clap_app.rs @@ -375,12 +375,18 @@ pub fn build_app(interactive_output: bool) -> Command { .overrides_with("theme") .help("Set the color theme for syntax highlighting.") .long_help( - "Set the theme for syntax highlighting. Note that this option overrides \ - '--theme-dark' and '--theme-light'. Use '--list-themes' to \ + "Set the theme for syntax highlighting. Use '--list-themes' to \ see all available themes. To set a default theme, add the \ '--theme=\"...\"' option to the configuration file or export the \ BAT_THEME environment variable (e.g.: export \ - BAT_THEME=\"...\").", + BAT_THEME=\"...\").\n\n\ + Special values:\n\n \ + * auto: Picks a dark or light theme depending on the terminal's colors (default).\n \ + Use '--theme-light' and '--theme-dark' to customize the selected theme.\n \ + * auto:always: Detect the terminal's colors even when the output is redirected.\n \ + * auto:system: Detect the color scheme from the system-wide preference (macOS only).\n \ + * dark: Use the dark theme specified by '--theme-dark'.\n \ + * light: Use the light theme specified by '--theme-light'.", ), ) .arg( diff --git a/src/theme.rs b/src/theme.rs index 5f6460cc..dcac4e6c 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -216,6 +216,10 @@ impl ColorSchemeDetector for TerminalColorSchemeDetector { #[cfg(not(target_os = "macos"))] fn color_scheme_from_system() -> Option { + crate::bat_warning!( + "Theme 'auto:system' is only supported on macOS, \ + using default." + ); None } From 50958472e5b4bdc7451a609b877dc8d5f6a4860e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Fri, 23 Aug 2024 18:03:07 +0200 Subject: [PATCH 28/53] Return theme alongside detected color scheme --- src/bin/bat/app.rs | 2 +- src/theme.rs | 92 ++++++++++++++++++++++++++++++---------------- 2 files changed, 61 insertions(+), 33 deletions(-) diff --git a/src/bin/bat/app.rs b/src/bin/bat/app.rs index 6d83c9c9..f58d4965 100644 --- a/src/bin/bat/app.rs +++ b/src/bin/bat/app.rs @@ -254,7 +254,7 @@ impl App { Some("auto") => StripAnsiMode::Auto, _ => unreachable!("other values for --strip-ansi are not allowed"), }, - theme: theme(self.theme_options()), + theme: theme(self.theme_options()).to_string(), visible_lines: match self.matches.try_contains_id("diff").unwrap_or_default() && self.matches.get_flag("diff") { diff --git a/src/theme.rs b/src/theme.rs index dcac4e6c..ae36b6f9 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -1,13 +1,18 @@ //! Utilities for choosing an appropriate theme for syntax highlighting. use std::convert::Infallible; +use std::fmt; use std::io::IsTerminal as _; use std::str::FromStr; /// Chooses an appropriate theme or falls back to a default theme /// based on the user-provided options and the color scheme of the terminal. -pub fn theme(options: ThemeOptions) -> String { - theme_from_detector(options, &TerminalColorSchemeDetector) +/// +/// Intentionally returns a [`ThemeResult`] instead of a simple string so +/// that downstream consumers such as `delta` can easily apply their own +/// default theme and can use the detected color scheme elsewhere. +pub fn theme(options: ThemeOptions) -> ThemeResult { + theme_impl(options, &TerminalColorSchemeDetector) } /// The default theme, suitable for the given color scheme. @@ -26,7 +31,7 @@ pub fn color_scheme(preference: ColorSchemePreference) -> ColorScheme { /// Options for configuring the theme used for syntax highlighting. /// Used together with [`theme`]. -#[derive(Debug, Default, PartialEq, Eq)] +#[derive(Debug, Clone, Default, PartialEq, Eq)] pub struct ThemeOptions { /// Always use this theme regardless of the terminal's background color. /// This corresponds with the `BAT_THEME` environment variable and the `--theme` option. @@ -40,7 +45,14 @@ pub struct ThemeOptions { } /// What theme should `bat` use? -#[derive(Debug, PartialEq, Eq, Hash)] +/// +/// The easiest way to construct this is from a string: +/// ``` +/// # use bat::theme::ThemePreference; +/// # use std::str::FromStr as _; +/// let preference = ThemePreference::from_str("auto:system").unwrap(); +/// ``` +#[derive(Debug, Clone, 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. @@ -79,7 +91,7 @@ impl FromStr for ThemePreference { /// 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)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ThemeName { Named(String), Default, @@ -97,15 +109,6 @@ impl FromStr for ThemeName { } } -impl ThemeName { - fn into_theme(self, color_scheme: ColorScheme) -> String { - match self { - ThemeName::Named(t) => t, - ThemeName::Default => default_theme(color_scheme).to_owned(), - } - } -} - /// How to choose between dark and light. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ColorSchemePreference { @@ -142,6 +145,26 @@ pub enum ColorScheme { Light, } +/// The resolved theme and the color scheme as determined from +/// the terminal, OS or fallback. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ThemeResult { + /// The theme selected according to the [`ThemeOptions`]. + pub theme: ThemeName, + /// Either the user's chosen color scheme, the terminal's color scheme, the OS's + /// color scheme or `None` if the color scheme was not detected because the user chose a fixed theme. + pub color_scheme: Option, +} + +impl fmt::Display for ThemeResult { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.theme { + ThemeName::Named(name) => f.write_str(name), + ThemeName::Default => f.write_str(default_theme(self.color_scheme.unwrap_or_default())), + } + } +} + fn color_scheme_impl( pref: ColorSchemePreference, detector: &dyn ColorSchemeDetector, @@ -154,16 +177,21 @@ fn color_scheme_impl( } } -fn theme_from_detector(options: ThemeOptions, detector: &dyn ColorSchemeDetector) -> String { +fn theme_impl(options: ThemeOptions, detector: &dyn ColorSchemeDetector) -> ThemeResult { // 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. 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()) + ThemePreference::Fixed(theme) => ThemeResult { + theme, + color_scheme: None, + }, + ThemePreference::Auto(pref) => { + let color_scheme = color_scheme_impl(pref, detector); + let theme = choose_theme(options, color_scheme).unwrap_or(ThemeName::Default); + ThemeResult { + theme, + color_scheme: Some(color_scheme), + } } } } @@ -273,7 +301,7 @@ mod tests { theme: ThemePreference::Auto(pref), ..Default::default() }; - _ = theme_from_detector(options, &detector); + _ = theme_impl(options, &detector); assert!(!detector.was_called.get()); } } @@ -291,7 +319,7 @@ mod tests { )), ..Default::default() }; - _ = theme_from_detector(options, &detector); + _ = theme_impl(options, &detector); assert!(detector.was_called.get()); } } @@ -299,14 +327,14 @@ mod tests { #[test] fn called_for_auto_if_should_detect() { let detector = DetectorStub::should_detect(Some(Dark)); - _ = theme_from_detector(ThemeOptions::default(), &detector); + _ = theme_impl(ThemeOptions::default(), &detector); assert!(detector.was_called.get()); } #[test] fn not_called_for_auto_if_not_should_detect() { let detector = DetectorStub::should_not_detect(); - _ = theme_from_detector(ThemeOptions::default(), &detector); + _ = theme_impl(ThemeOptions::default(), &detector); assert!(!detector.was_called.get()); } } @@ -330,7 +358,7 @@ mod tests { }, ] { let detector = ConstantDetector(color_scheme); - assert_eq!("Theme", theme_from_detector(options, &detector)); + assert_eq!("Theme", theme_impl(options, &detector).to_string()); } } } @@ -342,7 +370,7 @@ mod tests { ..Default::default() }; let detector = DetectorStub::should_detect(Some(Dark)); - _ = theme_from_detector(options, &detector); + _ = theme_impl(options, &detector); assert!(!detector.was_called.get()); } } @@ -355,7 +383,7 @@ mod tests { let detector = ConstantDetector(None); assert_eq!( default_theme(ColorScheme::Dark), - theme_from_detector(ThemeOptions::default(), &detector) + theme_impl(ThemeOptions::default(), &detector).to_string() ); } @@ -371,7 +399,7 @@ mod tests { let detector = ConstantDetector(color_scheme); assert_eq!( default_theme(ColorScheme::Dark), - theme_from_detector(options, &detector) + theme_impl(options, &detector).to_string() ); } } @@ -390,7 +418,7 @@ mod tests { let detector = ConstantDetector(Some(color_scheme)); assert_eq!( default_theme(color_scheme), - theme_from_detector(options, &detector) + theme_impl(options, &detector).to_string() ); } } @@ -409,7 +437,7 @@ mod tests { ..Default::default() }; let detector = ConstantDetector(color_scheme); - assert_eq!("Dark", theme_from_detector(options, &detector)); + assert_eq!("Dark", theme_impl(options, &detector).to_string()); } } @@ -421,7 +449,7 @@ mod tests { ..Default::default() }; let detector = ConstantDetector(Some(ColorScheme::Light)); - assert_eq!("Light", theme_from_detector(options, &detector)); + assert_eq!("Light", theme_impl(options, &detector).to_string()); } } From 16d9b99f6cbdf4529f8e638f22cd1561ee95160e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Wed, 4 Sep 2024 21:18:29 +0200 Subject: [PATCH 29/53] Flatten preference enum --- src/bin/bat/main.rs | 14 ++--- src/theme.rs | 121 ++++++++++++++++++++------------------------ 2 files changed, 60 insertions(+), 75 deletions(-) diff --git a/src/bin/bat/main.rs b/src/bin/bat/main.rs index 09470504..2b27eff4 100644 --- a/src/bin/bat/main.rs +++ b/src/bin/bat/main.rs @@ -14,6 +14,7 @@ use std::io::{BufReader, Write}; use std::path::Path; use std::process; +use bat::theme::DetectColorScheme; use nu_ansi_term::Color::Green; use nu_ansi_term::Style; @@ -35,7 +36,7 @@ use bat::{ error::*, input::Input, style::{StyleComponent, StyleComponents}, - theme::{color_scheme, default_theme, ColorScheme, ColorSchemePreference}, + theme::{color_scheme, default_theme, ColorScheme}, MappingTarget, PagingMode, }; @@ -193,7 +194,7 @@ pub fn list_themes( cfg: &Config, config_dir: &Path, cache_dir: &Path, - color_scheme_pref: ColorSchemePreference, + detect_color_scheme: DetectColorScheme, ) -> Result<()> { let assets = assets_from_cache_or_binary(cfg.use_custom_assets, cache_dir)?; let mut config = cfg.clone(); @@ -205,7 +206,7 @@ pub fn list_themes( let stdout = io::stdout(); let mut stdout = stdout.lock(); - let default_theme_name = default_theme(color_scheme(color_scheme_pref)); + let default_theme_name = default_theme(color_scheme(detect_color_scheme).unwrap_or_default()); for theme in assets.themes() { let default_theme_info = if default_theme_name == theme { " (default)" @@ -380,12 +381,7 @@ fn run() -> Result { }; run_controller(inputs, &plain_config, cache_dir) } else if app.matches.get_flag("list-themes") { - list_themes( - &config, - config_dir, - cache_dir, - ColorSchemePreference::default(), - )?; + list_themes(&config, config_dir, cache_dir, DetectColorScheme::default())?; Ok(true) } else if app.matches.get_flag("config-file") { println!("{}", config_file().to_string_lossy()); diff --git a/src/theme.rs b/src/theme.rs index ae36b6f9..7b41ff4a 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -25,8 +25,8 @@ pub const fn default_theme(color_scheme: ColorScheme) -> &'static str { } /// Detects the color scheme from the terminal. -pub fn color_scheme(preference: ColorSchemePreference) -> ColorScheme { - color_scheme_impl(preference, &TerminalColorSchemeDetector) +pub fn color_scheme(when: DetectColorScheme) -> Option { + detect(when, &TerminalColorSchemeDetector) } /// Options for configuring the theme used for syntax highlighting. @@ -55,15 +55,19 @@ pub struct ThemeOptions { #[derive(Debug, Clone, 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), + /// based on the terminal's color scheme. + Auto(DetectColorScheme), /// Always use the same theme regardless of the terminal's color scheme. Fixed(ThemeName), + /// Use a dark theme. + Dark, + /// Use a light theme. + Light, } impl Default for ThemePreference { fn default() -> Self { - ThemePreference::Auto(ColorSchemePreference::default()) + ThemePreference::Auto(Default::default()) } } @@ -73,11 +77,11 @@ impl FromStr for ThemePreference { fn from_str(s: &str) -> Result { 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)), + "auto" => Ok(Auto(Default::default())), + "auto:always" => Ok(Auto(DetectColorScheme::Always)), + "auto:system" => Ok(Auto(DetectColorScheme::System)), + "dark" => Ok(Dark), + "light" => Ok(Light), _ => ThemeName::from_str(s).map(Fixed), } } @@ -109,25 +113,6 @@ impl FromStr for ThemeName { } } -/// How to choose between dark and light. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum ColorSchemePreference { - /// Detect the color scheme from the terminal. - Auto(DetectColorScheme), - /// Use a dark theme. - Dark, - /// Use a light theme. - Light, - /// Detect the color scheme from the OS instead (macOS only). - System, -} - -impl Default for ColorSchemePreference { - fn default() -> Self { - Self::Auto(DetectColorScheme::default()) - } -} - #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] pub enum DetectColorScheme { /// Only query the terminal for its colors when appropriate (i.e. when the the output is not redirected). @@ -135,6 +120,8 @@ pub enum DetectColorScheme { Auto, /// Always query the terminal for its colors. Always, + /// Detect the system-wide dark/light preference (macOS only). + System, } /// The color scheme used to pick a fitting theme. Defaults to [`ColorScheme::Dark`]. @@ -165,18 +152,6 @@ impl fmt::Display for ThemeResult { } } -fn color_scheme_impl( - pref: ColorSchemePreference, - detector: &dyn ColorSchemeDetector, -) -> ColorScheme { - match pref { - ColorSchemePreference::Auto(when) => detect(when, detector).unwrap_or_default(), - ColorSchemePreference::Dark => ColorScheme::Dark, - ColorSchemePreference::Light => ColorScheme::Light, - ColorSchemePreference::System => color_scheme_from_system().unwrap_or_default(), - } -} - fn theme_impl(options: ThemeOptions, detector: &dyn ColorSchemeDetector) -> ThemeResult { // 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. @@ -185,14 +160,18 @@ fn theme_impl(options: ThemeOptions, detector: &dyn ColorSchemeDetector) -> Them theme, color_scheme: None, }, - ThemePreference::Auto(pref) => { - let color_scheme = color_scheme_impl(pref, detector); - let theme = choose_theme(options, color_scheme).unwrap_or(ThemeName::Default); - ThemeResult { - theme, - color_scheme: Some(color_scheme), - } - } + ThemePreference::Dark => choose_theme_opt(Some(ColorScheme::Dark), options), + ThemePreference::Light => choose_theme_opt(Some(ColorScheme::Light), options), + ThemePreference::Auto(when) => choose_theme_opt(detect(when, detector), options), + } +} + +fn choose_theme_opt(color_scheme: Option, options: ThemeOptions) -> ThemeResult { + ThemeResult { + color_scheme, + theme: color_scheme + .and_then(|c| choose_theme(options, c)) + .unwrap_or(ThemeName::Default), } } @@ -207,6 +186,7 @@ fn detect(when: DetectColorScheme, detector: &dyn ColorSchemeDetector) -> Option let should_detect = match when { DetectColorScheme::Auto => detector.should_detect(), DetectColorScheme::Always => true, + DetectColorScheme::System => return color_scheme_from_system(), }; should_detect.then(|| detector.detect()).flatten() } @@ -285,7 +265,6 @@ impl ColorSchemeDetector for Option { #[cfg(test)] mod tests { use super::ColorScheme::*; - use super::ColorSchemePreference as Pref; use super::*; use std::cell::Cell; use std::iter; @@ -295,10 +274,10 @@ mod tests { #[test] fn not_called_for_dark_or_light() { - for pref in [Pref::Dark, Pref::Light] { + for theme in [ThemePreference::Dark, ThemePreference::Light] { let detector = DetectorStub::should_detect(Some(Dark)); let options = ThemeOptions { - theme: ThemePreference::Auto(pref), + theme, ..Default::default() }; _ = theme_impl(options, &detector); @@ -314,9 +293,7 @@ mod tests { ]; for detector in detectors { let options = ThemeOptions { - theme: ThemePreference::Auto(ColorSchemePreference::Auto( - DetectColorScheme::Always, - )), + theme: ThemePreference::Auto(DetectColorScheme::Always), ..Default::default() }; _ = theme_impl(options, &detector); @@ -379,7 +356,7 @@ mod tests { use super::*; #[test] - fn dark_if_unable_to_detect_color_scheme() { + fn default_dark_if_unable_to_detect_color_scheme() { let detector = ConstantDetector(None); assert_eq!( default_theme(ColorScheme::Dark), @@ -390,7 +367,7 @@ mod tests { // For backwards compatibility, if the default theme is requested // explicitly through BAT_THEME, we always pick the default dark theme. #[test] - fn dark_if_requested_explicitly_through_theme() { + fn default_dark_if_requested_explicitly_through_theme() { for color_scheme in optional(color_schemes()) { let options = ThemeOptions { theme: ThemePreference::Fixed(ThemeName::Default), @@ -428,17 +405,29 @@ mod tests { mod choosing { use super::*; + #[test] + fn chooses_default_theme_if_unknown() { + let options = ThemeOptions { + theme_dark: Some(ThemeName::Named("Dark".to_string())), + theme_light: Some(ThemeName::Named("Light".to_string())), + ..Default::default() + }; + let detector = ConstantDetector(None); + assert_eq!( + default_theme(ColorScheme::default()), + theme_impl(options, &detector).to_string() + ); + } + #[test] fn chooses_dark_theme_if_dark_or_unknown() { - for color_scheme in [Some(Dark), None] { - let options = ThemeOptions { - theme_dark: Some(ThemeName::Named("Dark".to_string())), - theme_light: Some(ThemeName::Named("Light".to_string())), - ..Default::default() - }; - let detector = ConstantDetector(color_scheme); - assert_eq!("Dark", theme_impl(options, &detector).to_string()); - } + let options = ThemeOptions { + theme_dark: Some(ThemeName::Named("Dark".to_string())), + theme_light: Some(ThemeName::Named("Light".to_string())), + ..Default::default() + }; + let detector = ConstantDetector(Some(ColorScheme::Dark)); + assert_eq!("Dark", theme_impl(options, &detector).to_string()); } #[test] From e075fee5bf2fe6b40e16bb4ac02f88bcfe1fe782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Sat, 7 Sep 2024 20:24:57 +0200 Subject: [PATCH 30/53] Add infallible constructor --- src/theme.rs | 60 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/src/theme.rs b/src/theme.rs index 7b41ff4a..41ce84e1 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -48,9 +48,9 @@ pub struct ThemeOptions { /// /// The easiest way to construct this is from a string: /// ``` -/// # use bat::theme::ThemePreference; -/// # use std::str::FromStr as _; -/// let preference = ThemePreference::from_str("auto:system").unwrap(); +/// # use bat::theme::{ThemePreference, DetectColorScheme}; +/// let preference = ThemePreference::new("auto:system"); +/// assert_eq!(ThemePreference::Auto(DetectColorScheme::System), preference); /// ``` #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ThemePreference { @@ -71,19 +71,26 @@ impl Default for ThemePreference { } } +impl ThemePreference { + /// Creates a theme preference from a string. + pub fn new(s: &str) -> Self { + use ThemePreference::*; + match s { + "auto" => Auto(Default::default()), + "auto:always" => Auto(DetectColorScheme::Always), + "auto:system" => Auto(DetectColorScheme::System), + "dark" => Dark, + "light" => Light, + _ => Fixed(ThemeName::new(s)), + } + } +} + impl FromStr for ThemePreference { type Err = Infallible; fn from_str(s: &str) -> Result { - use ThemePreference::*; - match s { - "auto" => Ok(Auto(Default::default())), - "auto:always" => Ok(Auto(DetectColorScheme::Always)), - "auto:system" => Ok(Auto(DetectColorScheme::System)), - "dark" => Ok(Dark), - "light" => Ok(Light), - _ => ThemeName::from_str(s).map(Fixed), - } + Ok(ThemePreference::new(s)) } } @@ -91,9 +98,8 @@ impl FromStr for ThemePreference { /// /// ``` /// # use bat::theme::ThemeName; -/// # use std::str::FromStr as _; -/// assert_eq!(ThemeName::Default, ThemeName::from_str("default").unwrap()); -/// assert_eq!(ThemeName::Named("example".to_string()), ThemeName::from_str("example").unwrap()); +/// assert_eq!(ThemeName::Default, ThemeName::new("default")); +/// assert_eq!(ThemeName::Named("example".to_string()), ThemeName::new("example")); /// ``` #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ThemeName { @@ -101,14 +107,30 @@ pub enum ThemeName { Default, } +impl ThemeName { + /// Creates a theme name from a string. + pub fn new(s: &str) -> Self { + if s == "default" { + ThemeName::Default + } else { + ThemeName::Named(s.to_owned()) + } + } +} + impl FromStr for ThemeName { type Err = Infallible; fn from_str(s: &str) -> Result { - if s == "default" { - Ok(ThemeName::Default) - } else { - Ok(ThemeName::Named(s.to_owned())) + Ok(ThemeName::new(s)) + } +} + +impl fmt::Display for ThemeName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ThemeName::Named(t) => f.write_str(t), + ThemeName::Default => f.write_str("default"), } } } From 60e402733241f2154688722fbe75225fc4c06c6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Sat, 7 Sep 2024 21:34:05 +0200 Subject: [PATCH 31/53] Expose theme env vars --- src/bin/bat/config.rs | 6 +++--- src/theme.rs | 10 ++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/bin/bat/config.rs b/src/bin/bat/config.rs index f1ec3d53..a0ee7ba3 100644 --- a/src/bin/bat/config.rs +++ b/src/bin/bat/config.rs @@ -140,9 +140,9 @@ fn get_args_from_str(content: &str) -> Result, shell_words::ParseE pub fn get_args_from_env_vars() -> Vec { [ ("--tabs", "BAT_TABS"), - ("--theme", "BAT_THEME"), - ("--theme-dark", "BAT_THEME_DARK"), - ("--theme-light", "BAT_THEME_LIGHT"), + ("--theme", bat::theme::env::BAT_THEME), + ("--theme-dark", bat::theme::env::BAT_THEME_DARK), + ("--theme-light", bat::theme::env::BAT_THEME_LIGHT), ("--pager", "BAT_PAGER"), ("--paging", "BAT_PAGING"), ("--style", "BAT_STYLE"), diff --git a/src/theme.rs b/src/theme.rs index 41ce84e1..0276e5e0 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -5,6 +5,16 @@ use std::fmt; use std::io::IsTerminal as _; use std::str::FromStr; +/// Environment variable names. +pub mod env { + /// See [`crate::theme::ThemeOptions::theme`]. + pub const BAT_THEME: &str = "BAT_THEME"; + /// See [`crate::theme::ThemeOptions::theme_dark`]. + pub const BAT_THEME_DARK: &str = "BAT_THEME"; + /// See [`crate::theme::ThemeOptions::theme_light`]. + pub const BAT_THEME_LIGHT: &str = "BAT_THEME"; +} + /// Chooses an appropriate theme or falls back to a default theme /// based on the user-provided options and the color scheme of the terminal. /// From 10e823c4b760870eac4569e42d07704cffd3e79e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Sat, 7 Sep 2024 21:34:44 +0200 Subject: [PATCH 32/53] Rename internal function --- src/theme.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/theme.rs b/src/theme.rs index 0276e5e0..71c09e98 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -36,7 +36,7 @@ pub const fn default_theme(color_scheme: ColorScheme) -> &'static str { /// Detects the color scheme from the terminal. pub fn color_scheme(when: DetectColorScheme) -> Option { - detect(when, &TerminalColorSchemeDetector) + color_scheme_impl(when, &TerminalColorSchemeDetector) } /// Options for configuring the theme used for syntax highlighting. @@ -194,7 +194,7 @@ fn theme_impl(options: ThemeOptions, detector: &dyn ColorSchemeDetector) -> Them }, ThemePreference::Dark => choose_theme_opt(Some(ColorScheme::Dark), options), ThemePreference::Light => choose_theme_opt(Some(ColorScheme::Light), options), - ThemePreference::Auto(when) => choose_theme_opt(detect(when, detector), options), + ThemePreference::Auto(when) => choose_theme_opt(color_scheme_impl(when, detector), options), } } @@ -214,7 +214,10 @@ fn choose_theme(options: ThemeOptions, color_scheme: ColorScheme) -> Option Option { +fn color_scheme_impl( + when: DetectColorScheme, + detector: &dyn ColorSchemeDetector, +) -> Option { let should_detect = match when { DetectColorScheme::Auto => detector.should_detect(), DetectColorScheme::Always => true, From f6cbee9e270b18681c2b39ad507bb128b98a35a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Sat, 7 Sep 2024 21:35:37 +0200 Subject: [PATCH 33/53] Update docs --- src/theme.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/theme.rs b/src/theme.rs index 71c09e98..b8c4c67b 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -43,7 +43,8 @@ pub fn color_scheme(when: DetectColorScheme) -> Option { /// Used together with [`theme`]. #[derive(Debug, Clone, Default, PartialEq, Eq)] pub struct ThemeOptions { - /// Always use this theme regardless of the terminal's background color. + /// Configures how the theme is chosen. If set to a [`ThemePreference::Fixed`] value, + /// then the given theme is used regardless of the terminal's background color. /// 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. From 0ebb9cbfe2651127d22cea12ca359db5e26c8595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Sat, 7 Sep 2024 21:57:27 +0200 Subject: [PATCH 34/53] Add Display impl --- src/theme.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/theme.rs b/src/theme.rs index b8c4c67b..5fed4faa 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -105,6 +105,20 @@ impl FromStr for ThemePreference { } } +impl fmt::Display for ThemePreference { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use ThemePreference::*; + match self { + Auto(DetectColorScheme::Auto) => f.write_str("auto"), + Auto(DetectColorScheme::Always) => f.write_str("auto:always"), + Auto(DetectColorScheme::System) => f.write_str("auto:system"), + Fixed(theme) => theme.fmt(f), + Dark => f.write_str("dark"), + Light => f.write_str("light"), + } + } +} + /// The name of a theme or the default theme. /// /// ``` @@ -478,6 +492,26 @@ mod tests { } } + mod theme_preference { + use super::*; + + #[test] + fn values_roundtrip_via_display() { + let prefs = [ + ThemePreference::Auto(DetectColorScheme::Auto), + ThemePreference::Auto(DetectColorScheme::Always), + ThemePreference::Auto(DetectColorScheme::System), + ThemePreference::Fixed(ThemeName::Default), + ThemePreference::Fixed(ThemeName::new("foo")), + ThemePreference::Dark, + ThemePreference::Light, + ]; + for pref in prefs { + assert_eq!(pref, ThemePreference::new(&pref.to_string())); + } + } + } + struct DetectorStub { should_detect: bool, color_scheme: Option, From 02ae6ef348d19dd5c117c0d53733c4df076ec87b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Sat, 7 Sep 2024 22:59:27 +0200 Subject: [PATCH 35/53] Remove redundant guard --- src/theme.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/theme.rs b/src/theme.rs index 5fed4faa..dcc6ee42 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -292,7 +292,7 @@ fn color_scheme_from_system() -> Option { match plist::Value::from_file(preferences_file).map(|file| file.into_dictionary()) { Ok(Some(preferences)) => match preferences.get(STYLE_KEY).and_then(|val| val.as_string()) { - Some(value) if value == "Dark" => Some(ColorScheme::Dark), + Some("Dark") => Some(ColorScheme::Dark), // If the key does not exist, then light theme is currently in use. Some(_) | None => Some(ColorScheme::Light), }, From b7471847889ee2f0faab7e9f9d12df70d351edd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tau=20G=C3=A4rtli?= Date: Sun, 8 Sep 2024 17:10:46 +0200 Subject: [PATCH 36/53] Accept `impl Into` to avoid cloning strings --- src/theme.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/theme.rs b/src/theme.rs index dcc6ee42..9fbef238 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -84,9 +84,10 @@ impl Default for ThemePreference { impl ThemePreference { /// Creates a theme preference from a string. - pub fn new(s: &str) -> Self { + pub fn new(s: impl Into) -> Self { use ThemePreference::*; - match s { + let s = s.into(); + match s.as_str() { "auto" => Auto(Default::default()), "auto:always" => Auto(DetectColorScheme::Always), "auto:system" => Auto(DetectColorScheme::System), @@ -134,11 +135,12 @@ pub enum ThemeName { impl ThemeName { /// Creates a theme name from a string. - pub fn new(s: &str) -> Self { + pub fn new(s: impl Into) -> Self { + let s = s.into(); if s == "default" { ThemeName::Default } else { - ThemeName::Named(s.to_owned()) + ThemeName::Named(s) } } } From 9a816c9c68728b077f342147482fc3242bf50238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaras=C5=82a=C5=AD=20Viktor=C4=8Dyk?= Date: Sun, 13 Oct 2024 11:46:53 +0200 Subject: [PATCH 37/53] Add syntax mapping for CITATION.cff --- CHANGELOG.md | 1 + src/syntax_mapping/builtins/common/50-citation.toml | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 src/syntax_mapping/builtins/common/50-citation.toml diff --git a/CHANGELOG.md b/CHANGELOG.md index d2ec2da9..20aea9ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,7 @@ - Associate Wireguard config `/etc/wireguard/*.conf`, see #2874 (@cyqsimon) - Add support for [CFML](https://www.adobe.com/products/coldfusion-family.html), see #3031 (@brenton-at-pieces) - Map `*.mkd` files to `Markdown` syntax, see issue #3060 and PR #3061 (@einfachIrgendwer0815) +- Add syntax mapping for CITATION.cff, see #3103 (@Ugzuzg) ## Themes diff --git a/src/syntax_mapping/builtins/common/50-citation.toml b/src/syntax_mapping/builtins/common/50-citation.toml new file mode 100644 index 00000000..aa06b5b9 --- /dev/null +++ b/src/syntax_mapping/builtins/common/50-citation.toml @@ -0,0 +1,2 @@ +[mappings] +"YAML" = ["CITATION.cff"] From fd6c7637e49d6ff1f7f475943685c1b3aab5c76a Mon Sep 17 00:00:00 2001 From: einfachIrgendwer0815 <85333734+einfachIrgendwer0815@users.noreply.github.com> Date: Sat, 21 Oct 2023 21:58:57 +0200 Subject: [PATCH 38/53] Partially revert "Make -pp override --paging and vice versa when passed as a later argument. (#2660)" This partially reverts commit e2bf85e749d87459e3fced697af5cd9cc96eeb8c. --- src/bin/bat/clap_app.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/bin/bat/clap_app.rs b/src/bin/bat/clap_app.rs index 33dde980..c0669c0f 100644 --- a/src/bin/bat/clap_app.rs +++ b/src/bin/bat/clap_app.rs @@ -81,7 +81,6 @@ pub fn build_app(interactive_output: bool) -> Command { Arg::new("plain") .overrides_with("plain") .overrides_with("number") - .overrides_with("paging") .short('p') .long("plain") .action(ArgAction::Count) @@ -306,7 +305,6 @@ pub fn build_app(interactive_output: bool) -> Command { .long("paging") .overrides_with("paging") .overrides_with("no-paging") - .overrides_with("plain") .value_name("when") .value_parser(["auto", "never", "always"]) .default_value("auto") From e667415deff1a8150db6cc1fc5e8db701827261d Mon Sep 17 00:00:00 2001 From: einfachIrgendwer0815 <85333734+einfachIrgendwer0815@users.noreply.github.com> Date: Sat, 21 Oct 2023 22:16:59 +0200 Subject: [PATCH 39/53] Add tests against issue #2731 --- tests/integration_tests.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index c083a941..2a192cdb 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -1020,6 +1020,31 @@ fn enable_pager_if_pp_flag_comes_before_paging() { .stdout(predicate::eq("pager-output\n").normalize()); } +#[test] +fn paging_does_not_override_simple_plain() { + bat() + .env("PAGER", "echo pager-output") + .arg("--decorations=always") + .arg("--plain") + .arg("--paging=never") + .arg("test.txt") + .assert() + .success() + .stdout(predicate::eq("hello world\n")); +} + +#[test] +fn simple_plain_does_not_override_paging() { + bat() + .env("PAGER", "echo pager-output") + .arg("--paging=always") + .arg("--plain") + .arg("test.txt") + .assert() + .success() + .stdout(predicate::eq("pager-output\n")); +} + #[test] fn pager_failed_to_parse() { bat() From c9fd0f3cf0e042c1c070e01e06bc8249b35a644a Mon Sep 17 00:00:00 2001 From: einfachIrgendwer0815 <85333734+einfachIrgendwer0815@users.noreply.github.com> Date: Fri, 18 Oct 2024 11:43:33 +0200 Subject: [PATCH 40/53] Add partial override of -pp and --paging --- src/bin/bat/app.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/bin/bat/app.rs b/src/bin/bat/app.rs index d6628668..9a78c949 100644 --- a/src/bin/bat/app.rs +++ b/src/bin/bat/app.rs @@ -97,12 +97,30 @@ impl App { pub fn config(&self, inputs: &[Input]) -> Result { let style_components = self.style_components()?; + let extra_plain = self.matches.get_count("plain") > 1; + let plain_last_index = self + .matches + .indices_of("plain") + .and_then(Iterator::max) + .unwrap_or_default(); + let paging_last_index = self + .matches + .indices_of("paging") + .and_then(Iterator::max) + .unwrap_or_default(); + let paging_mode = match self.matches.get_one::("paging").map(|s| s.as_str()) { - Some("always") => PagingMode::Always, + Some("always") => { + // Disable paging if the second -p (or -pp) is specified after --paging=always + if extra_plain && plain_last_index > paging_last_index { + PagingMode::Never + } else { + PagingMode::Always + } + } Some("never") => PagingMode::Never, Some("auto") | None => { // If we have -pp as an option when in auto mode, the pager should be disabled. - let extra_plain = self.matches.get_count("plain") > 1; if extra_plain || self.matches.get_flag("no-paging") { PagingMode::Never } else if inputs.iter().any(Input::is_stdin) { From ac082ab64b3536d463ec922c838474f8979f1726 Mon Sep 17 00:00:00 2001 From: einfachIrgendwer0815 <85333734+einfachIrgendwer0815@users.noreply.github.com> Date: Fri, 18 Oct 2024 12:44:53 +0200 Subject: [PATCH 41/53] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2ec2da9..a0e46c13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - Fix handling of inputs with combined ANSI color and attribute sequences, see #2185 and #2856 (@eth-p) - Fix panel width when line 10000 wraps, see #2854 (@eth-p) - Fix compile issue of `time` dependency caused by standard library regression #3045 (@cyqsimon) +- Fix override behavior of --plain and --paging, see issue #2731 and PR #3108 (@einfachIrgendwer0815) ## Other From 649fb05c5859a2dca61bed165ba9965c0ac5a667 Mon Sep 17 00:00:00 2001 From: Fabio Valentini Date: Thu, 24 Oct 2024 01:17:17 +0200 Subject: [PATCH 42/53] Bump nix from 0.26.4 to 0.29 --- CHANGELOG.md | 1 + Cargo.lock | 17 ++++++++++++----- Cargo.toml | 2 +- tests/integration_tests.rs | 5 ++--- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c404042f..55879dce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ - Use bat's ANSI iterator during tab expansion, see #2998 (@eth-p) - Support 'statically linked binary' for aarch64 in 'Release' page, see #2992 (@tzq0301) - Update options in shell completions and the man page of `bat`, see #2995 (@akinomyoga) +- Update nix dev-dependency to v0.29.0, see #3112 (@decathorpe) ## Syntaxes diff --git a/Cargo.lock b/Cargo.lock index 42db6b5f..0e3b3418 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -243,6 +243,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "clap" version = "4.4.12" @@ -688,9 +694,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.149" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "libgit2-sys" @@ -761,12 +767,13 @@ dependencies = [ [[package]] name = "nix" -version = "0.26.4" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", "cfg-if", + "cfg_aliases", "libc", ] diff --git a/Cargo.toml b/Cargo.toml index f5ef6af9..b8fcbcbe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,7 +98,7 @@ tempfile = "3.8.1" serde = { version = "1.0", features = ["derive"] } [target.'cfg(unix)'.dev-dependencies] -nix = { version = "0.26.4", default-features = false, features = ["term"] } +nix = { version = "0.29", default-features = false, features = ["term"] } [build-dependencies] anyhow = "1.0.86" diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index c083a941..13b35718 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -9,7 +9,6 @@ use tempfile::tempdir; mod unix { pub use std::fs::File; pub use std::io::{self, Write}; - pub use std::os::unix::io::FromRawFd; pub use std::path::PathBuf; pub use std::process::Stdio; pub use std::thread; @@ -416,8 +415,8 @@ fn no_args_doesnt_break() { // not exit, because in this case it is safe to read and write to the same fd, which is why // this test exists. let OpenptyResult { master, slave } = openpty(None, None).expect("Couldn't open pty."); - let mut master = unsafe { File::from_raw_fd(master) }; - let stdin_file = unsafe { File::from_raw_fd(slave) }; + let mut master = File::from(master); + let stdin_file = File::from(slave); let stdout_file = stdin_file.try_clone().unwrap(); let stdin = Stdio::from(stdin_file); let stdout = Stdio::from(stdout_file); From 50428443423a22685ec9f3ba8e4586a4ab419315 Mon Sep 17 00:00:00 2001 From: Pratik Munot Date: Tue, 29 Oct 2024 21:34:47 -0700 Subject: [PATCH 43/53] Adding pipe delimeter support for csv files --- assets/syntaxes/02_Extra/CSV.sublime-syntax | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/assets/syntaxes/02_Extra/CSV.sublime-syntax b/assets/syntaxes/02_Extra/CSV.sublime-syntax index cca7cd2c..0ad17834 100644 --- a/assets/syntaxes/02_Extra/CSV.sublime-syntax +++ b/assets/syntaxes/02_Extra/CSV.sublime-syntax @@ -7,14 +7,14 @@ file_extensions: - tsv scope: text.csv variables: - field_separator: (?:[,;\t]) + field_separator: (?:[,;|\t]) record_separator: (?:$\n?) contexts: prototype: - match: (?={{record_separator}}) pop: true fields: - - match: '' + - match: "" push: - field_or_record_separator - field4 @@ -26,15 +26,15 @@ contexts: - field1 main: - meta_include_prototype: false - - match: '^' + - match: "^" set: fields field_or_record_separator: - meta_include_prototype: false - - match: '{{record_separator}}' + - match: "{{record_separator}}" scope: punctuation.terminator.record.csv pop: true - - match: '{{field_separator}}' + - match: "{{field_separator}}" scope: punctuation.separator.sequence.csv pop: true @@ -56,23 +56,22 @@ contexts: pop: true field1: - - match: '' + - match: "" set: - meta_content_scope: meta.field-1.csv support.type - include: field_contents field2: - - match: '' + - match: "" set: - meta_content_scope: meta.field-2.csv support.function - include: field_contents field3: - - match: '' + - match: "" set: - meta_content_scope: meta.field-3.csv constant.numeric - include: field_contents field4: - - match: '' + - match: "" set: - meta_content_scope: meta.field-4.csv keyword.operator - include: field_contents - From 1942d40863472ea78603cf21ffa69ef49b335ad2 Mon Sep 17 00:00:00 2001 From: Pratik Munot Date: Tue, 29 Oct 2024 22:36:43 -0700 Subject: [PATCH 44/53] changelog updates --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55879dce..633af5ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,7 @@ - Add support for [CFML](https://www.adobe.com/products/coldfusion-family.html), see #3031 (@brenton-at-pieces) - Map `*.mkd` files to `Markdown` syntax, see issue #3060 and PR #3061 (@einfachIrgendwer0815) - Add syntax mapping for kubernetes config files #3049 (@cyqsimon) +- Adds support for pipe delimiter for CSV #3115 (@pratik-m) ## Themes From 9090fb75e0ae7772aa09b698a10a4f5fb04a4143 Mon Sep 17 00:00:00 2001 From: Jacek Generowicz Date: Fri, 26 Apr 2024 16:19:07 +0200 Subject: [PATCH 45/53] Make .debdiff imply .diff using syntax_mapping toml Closes #2940 --- src/syntax_mapping/builtins/unix-family/50-diff.toml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/syntax_mapping/builtins/unix-family/50-diff.toml diff --git a/src/syntax_mapping/builtins/unix-family/50-diff.toml b/src/syntax_mapping/builtins/unix-family/50-diff.toml new file mode 100644 index 00000000..2998d9c5 --- /dev/null +++ b/src/syntax_mapping/builtins/unix-family/50-diff.toml @@ -0,0 +1,3 @@ +# .debdiff is the extension used for diffs in Debian packaging +[mappings] +"Diff" = ["*.debdiff"] From d0ae2e6826caf0e7701be7751989827b371b4bba Mon Sep 17 00:00:00 2001 From: Jacek Generowicz Date: Fri, 26 Apr 2024 16:30:39 +0200 Subject: [PATCH 46/53] Add CHANGELOG entry for .debdiff => diff --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e45f1bb1..5326de59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -114,6 +114,7 @@ - Update `Julia` syntax, see #2553 (@dependabot) - add `NSIS` support, see #2577 (@idleberg) - Update `ssh-config`, see #2697 (@mrmeszaros) +- Add syntax mapping `*.debdiff` => `diff`, see #2947 (@jacg) ## `bat` as a library From 0a8bfc52a6337828eb0d58a49006437d44ac5647 Mon Sep 17 00:00:00 2001 From: Jacek Generowicz Date: Wed, 15 May 2024 09:07:44 +0200 Subject: [PATCH 47/53] Move from unix-family to common --- src/syntax_mapping/builtins/{unix-family => common}/50-diff.toml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/syntax_mapping/builtins/{unix-family => common}/50-diff.toml (100%) diff --git a/src/syntax_mapping/builtins/unix-family/50-diff.toml b/src/syntax_mapping/builtins/common/50-diff.toml similarity index 100% rename from src/syntax_mapping/builtins/unix-family/50-diff.toml rename to src/syntax_mapping/builtins/common/50-diff.toml From c627526f8c18ba1a1e630770b7627c159b545962 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 03:57:52 +0000 Subject: [PATCH 48/53] Bump clircle from 0.5.0 to 0.6.0 (#3117) Bumps [clircle](https://github.com/niklasmohrin/clircle) from 0.5.0 to 0.6.0. - [Release notes](https://github.com/niklasmohrin/clircle/releases) - [Commits](https://github.com/niklasmohrin/clircle/compare/v0.5.0...v0.6.0) --- updated-dependencies: - dependency-name: clircle dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 5 ++--- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e3b3418..a9b6f7dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -279,12 +279,11 @@ checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "clircle" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0b92245ea62a7a751db4b0e4a583f8978e508077ef6de24fcc0d0dc5311a8d" +checksum = "e136d50bd652710f1d86259a8977263d46bef0ab782a8bfc3887e44338517015" dependencies = [ "cfg-if", - "libc", "serde", "serde_derive", "winapi", diff --git a/Cargo.toml b/Cargo.toml index b8fcbcbe..a6c410b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,7 +58,7 @@ serde_derive = "1.0" serde_yaml = "0.9.28" semver = "1.0" path_abs = { version = "0.5", default-features = false } -clircle = "0.5" +clircle = "0.6" bugreport = { version = "0.5.0", optional = true } etcetera = { version = "0.8.0", optional = true } grep-cli = { version = "0.1.10", optional = true } From e7bef716c9ade4641f2b92e992b56837bc1d019d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 04:23:23 +0000 Subject: [PATCH 49/53] Bump encoding_rs from 0.8.34 to 0.8.35 (#3119) Bumps [encoding_rs](https://github.com/hsivonen/encoding_rs) from 0.8.34 to 0.8.35. - [Commits](https://github.com/hsivonen/encoding_rs/compare/v0.8.34...v0.8.35) --- updated-dependencies: - dependency-name: encoding_rs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a9b6f7dd..f8356339 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -421,9 +421,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] diff --git a/Cargo.toml b/Cargo.toml index a6c410b9..ccc4ced7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,7 +65,7 @@ grep-cli = { version = "0.1.10", optional = true } regex = { version = "1.10.2", optional = true } walkdir = { version = "2.5", optional = true } bytesize = { version = "1.3.0" } -encoding_rs = "0.8.34" +encoding_rs = "0.8.35" os_str_bytes = { version = "~7.0", optional = true } run_script = { version = "^0.10.1", optional = true} From 6b2c5645d251d2f3c5f58f889b8a63cf4c7ffa56 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 04:46:28 +0000 Subject: [PATCH 50/53] Bump toml from 0.8.9 to 0.8.19 (#3121) Bumps [toml](https://github.com/toml-rs/toml) from 0.8.9 to 0.8.19. - [Commits](https://github.com/toml-rs/toml/compare/toml-v0.8.9...toml-v0.8.19) --- updated-dependencies: - dependency-name: toml dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 20 ++++++++++---------- Cargo.toml | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f8356339..f6fedcbf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1146,9 +1146,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.5" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -1392,9 +1392,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "toml" -version = "0.8.9" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6a4b9e8023eb94392d3dca65d717c53abc5dad49c07cb65bb8fcd87115fa325" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "indexmap", "serde", @@ -1405,18 +1405,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.21.1" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", "serde", @@ -1746,9 +1746,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176b6138793677221d420fd2f0aeeced263f197688b36484660da767bca2fa32" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index ccc4ced7..6714e6c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -109,7 +109,7 @@ regex = "1.10.2" serde = "1.0" serde_derive = "1.0" serde_with = { version = "3.8.1", default-features = false, features = ["macros"] } -toml = { version = "0.8.9", features = ["preserve_order"] } +toml = { version = "0.8.19", features = ["preserve_order"] } walkdir = "2.5" [build-dependencies.clap] From dbaa0a6d9eea7a594b56b535574be30b077a7a12 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 05:02:22 +0000 Subject: [PATCH 51/53] Bump grep-cli from 0.1.10 to 0.1.11 (#3120) Bumps [grep-cli](https://github.com/BurntSushi/ripgrep) from 0.1.10 to 0.1.11. - [Release notes](https://github.com/BurntSushi/ripgrep/releases) - [Changelog](https://github.com/BurntSushi/ripgrep/blob/master/CHANGELOG.md) - [Commits](https://github.com/BurntSushi/ripgrep/compare/grep-cli-0.1.10...0.1.11) --- updated-dependencies: - dependency-name: grep-cli dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f6fedcbf..0f242845 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -601,9 +601,9 @@ dependencies = [ [[package]] name = "grep-cli" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea40788c059ab8b622c4d074732750bfb3bd2912e2dd58eabc11798a4d5ad725" +checksum = "47f1288f0e06f279f84926fa4c17e3fcd2a22b357927a82f2777f7be26e4cec0" dependencies = [ "bstr", "globset", diff --git a/Cargo.toml b/Cargo.toml index 6714e6c4..67327460 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,7 +61,7 @@ path_abs = { version = "0.5", default-features = false } clircle = "0.6" bugreport = { version = "0.5.0", optional = true } etcetera = { version = "0.8.0", optional = true } -grep-cli = { version = "0.1.10", optional = true } +grep-cli = { version = "0.1.11", optional = true } regex = { version = "1.10.2", optional = true } walkdir = { version = "2.5", optional = true } bytesize = { version = "1.3.0" } From f8f12a7db579ede8bd4598d384fde768bf055377 Mon Sep 17 00:00:00 2001 From: David Peter Date: Sun, 10 Nov 2024 20:02:58 +0100 Subject: [PATCH 52/53] Update sponsorship information --- README.md | 6 +++--- doc/sponsors/warp-logo.png | Bin 80535 -> 132621 bytes 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 016fe834..4ffd7fe9 100644 --- a/README.md +++ b/README.md @@ -35,11 +35,11 @@ A special *thank you* goes to our biggest sponsors Warp
- Warp is a modern, Rust-based terminal with AI built in
so you and your team can build great software, faster.
+ Warp, the intelligent terminal
- Feel more productive on the command line with parameterized commands, + Run commands like a power user with AI and your dev team’s
- autosuggestions, and an IDE-like text editor. + knowledge in one fast, intuitive terminal. For MacOS or Linux.
### Syntax highlighting diff --git a/doc/sponsors/warp-logo.png b/doc/sponsors/warp-logo.png index 4795a2b97a7ece92c764e94edfcb4dc30273e5d3..f99dd38ceea805656daea5cd80c3525dbd307b71 100644 GIT binary patch literal 132621 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 k$@@B)IBe@Pl;6bAZ|msXLgl`skZAEg!r?*IS* From 2caeaef14bec10565a62451d92dd92362b483275 Mon Sep 17 00:00:00 2001 From: Adam Perkowski Date: Sun, 6 Oct 2024 18:20:43 +0200 Subject: [PATCH 53/53] =?UTF-8?q?=F0=9F=93=94=20docs:=20mention=20`BAT=5FC?= =?UTF-8?q?ONFIG=5FDIR`=20in=20the=20README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4ffd7fe9..14c264a8 100644 --- a/README.md +++ b/README.md @@ -693,10 +693,11 @@ on your operating system. To get the default path for your system, call bat --config-file ``` -Alternatively, you can use the `BAT_CONFIG_PATH` environment variable to point `bat` to a -non-default location of the configuration file: +Alternatively, you can use `BAT_CONFIG_PATH` or `BAT_CONFIG_DIR` environment variables to point `bat` +to a non-default location of the configuration file or the configuration directory respectively: ```bash -export BAT_CONFIG_PATH="/path/to/bat.conf" +export BAT_CONFIG_PATH="/path/to/bat/bat.conf" +export BAT_CONFIG_DIR="/path/to/bat" ``` A default configuration file can be created with the `--generate-config-file` option.