summaryrefslogtreecommitdiffstats
path: root/src/options
diff options
context:
space:
mode:
authorDan Davison <dandavison7@gmail.com>2020-06-29 22:34:02 -0400
committerDan Davison <dandavison7@gmail.com>2020-06-30 08:00:30 -0400
commit7d03c25266d84e64bab3bbf3c1782b980e8f5385 (patch)
treec8c9db167c5bd82666ae06fc9ad6a4a95dd77e54 /src/options
parent3b2f709bdc9058d14efacaa4bc58b994c0885aea (diff)
Rearrange: options::theme module
Diffstat (limited to 'src/options')
-rw-r--r--src/options/mod.rs2
-rw-r--r--src/options/preprocess.rs29
-rw-r--r--src/options/set.rs79
-rw-r--r--src/options/theme.rs251
4 files changed, 296 insertions, 65 deletions
diff --git a/src/options/mod.rs b/src/options/mod.rs
index 7ccd4b90..f15e5806 100644
--- a/src/options/mod.rs
+++ b/src/options/mod.rs
@@ -1,5 +1,5 @@
pub mod get;
pub mod option_value;
-pub mod preprocess;
pub mod rewrite;
pub mod set;
+pub mod theme;
diff --git a/src/options/preprocess.rs b/src/options/preprocess.rs
deleted file mode 100644
index c1951892..00000000
--- a/src/options/preprocess.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-use std::process;
-
-use crate::bat::assets::HighlightingAssets;
-use crate::cli;
-use crate::env;
-use crate::syntax_theme;
-
-#[allow(non_snake_case)]
-pub fn set__is_light_mode__syntax_theme__syntax_set(
- opt: &mut cli::Opt,
- assets: HighlightingAssets,
-) {
- let syntax_theme_name_from_bat_theme = env::get_env_var("BAT_THEME");
- let (is_light_mode, syntax_theme_name) = syntax_theme::get_is_light_mode_and_theme_name(
- opt.syntax_theme.as_ref(),
- syntax_theme_name_from_bat_theme.as_ref(),
- opt.light,
- &assets.theme_set,
- );
- opt.computed.is_light_mode = is_light_mode;
-
- opt.computed.syntax_theme =
- if syntax_theme::is_no_syntax_highlighting_theme_name(&syntax_theme_name) {
- None
- } else {
- Some(assets.theme_set.themes[&syntax_theme_name].clone())
- };
- opt.computed.syntax_set = assets.syntax_set;
-}
diff --git a/src/options/set.rs b/src/options/set.rs
index 339ceffc..7a2df4b6 100644
--- a/src/options/set.rs
+++ b/src/options/set.rs
@@ -1,4 +1,4 @@
-use std::collections::{HashSet, VecDeque};
+use std::collections::{HashMap, HashSet, VecDeque};
use std::process;
use structopt::clap;
@@ -6,10 +6,9 @@ use structopt::clap;
use crate::bat::assets::HighlightingAssets;
use crate::cli;
use crate::config;
-
use crate::features;
use crate::git_config;
-use crate::options::preprocess;
+use crate::options::theme;
macro_rules! set_options {
([$( ($option_name:expr, $field_ident:ident) ),* ],
@@ -34,8 +33,12 @@ macro_rules! set_options {
option_names.extend(&[
"diff-highlight", // Does not exist as a flag on config
"diff-so-fancy", // Does not exist as a flag on config
- "features",
+ "features", // Processes differently
+ // Set prior to the rest
"no-gitconfig",
+ "dark",
+ "light",
+ "syntax-theme",
]);
let expected_option_names = $crate::cli::Opt::get_option_or_flag_names();
if option_names != expected_option_names {
@@ -77,34 +80,8 @@ pub fn set_options(
.unwrap_or_else(|| "magenta reverse".to_string())
}
- // Set light, dark and syntax-theme
- let validate_light_and_dark = |opt: &cli::Opt| {
- if opt.light && opt.dark {
- eprintln!("--light and --dark cannot be used together.");
- process::exit(1);
- }
- };
- validate_light_and_dark(&opt);
- if !(opt.light || opt.dark) {
- set_options!(
- [("dark", dark), ("light", light)],
- opt,
- builtin_features,
- git_config,
- arg_matches,
- false
- );
- }
- validate_light_and_dark(&opt);
- set_options!(
- [("syntax-theme", syntax_theme)],
- opt,
- builtin_features,
- git_config,
- arg_matches,
- false
- );
- preprocess::set__is_light_mode__syntax_theme__syntax_set(opt, assets);
+ set__light__dark__syntax_theme__options(opt, &builtin_features, git_config, arg_matches);
+ theme::set__is_light_mode__syntax_theme__syntax_set(opt, assets);
set_options!(
[
@@ -112,7 +89,6 @@ pub fn set_options(
("color-only", color_only),
("commit-decoration-style", commit_decoration_style),
("commit-style", commit_style),
- ("dark", dark),
("file-added-label", file_added_label),
("file-decoration-style", file_decoration_style),
("file-modified-label", file_modified_label),
@@ -122,7 +98,6 @@ pub fn set_options(
("hunk-header-decoration-style", hunk_header_decoration_style),
("hunk-header-style", hunk_header_style),
("keep-plus-minus-markers", keep_plus_minus_markers),
- ("light", light),
("max-line-distance", max_line_distance),
// Hack: minus-style must come before minus-*emph-style because the latter default
// dynamically to the value of the former.
@@ -151,7 +126,6 @@ pub fn set_options(
("plus-empty-line-marker-style", plus_empty_line_marker_style),
("plus-non-emph-style", plus_non_emph_style),
("raw", raw),
- ("syntax-theme", syntax_theme),
("tabs", tab_width),
("whitespace-error-style", whitespace_error_style),
("width", width),
@@ -166,6 +140,41 @@ pub fn set_options(
);
}
+#[allow(non_snake_case)]
+fn set__light__dark__syntax_theme__options(
+ opt: &mut cli::Opt,
+ builtin_features: &HashMap<String, features::BuiltinFeature>,
+ git_config: &mut Option<git_config::GitConfig>,
+ arg_matches: &clap::ArgMatches,
+) {
+ let validate_light_and_dark = |opt: &cli::Opt| {
+ if opt.light && opt.dark {
+ eprintln!("--light and --dark cannot be used together.");
+ process::exit(1);
+ }
+ };
+ validate_light_and_dark(&opt);
+ if !(opt.light || opt.dark) {
+ set_options!(
+ [("dark", dark), ("light", light)],
+ opt,
+ builtin_features,
+ git_config,
+ arg_matches,
+ false
+ );
+ }
+ validate_light_and_dark(&opt);
+ set_options!(
+ [("syntax-theme", syntax_theme)],
+ opt,
+ builtin_features,
+ git_config,
+ arg_matches,
+ false
+ );
+}
+
/// Features are processed differently from all other options. The role of this function is to
/// collect all configuration related to features and summarize it as a single list
/// (space-separated string) of enabled features. The list is arranged in order of increasing
diff --git a/src/options/theme.rs b/src/options/theme.rs
new file mode 100644
index 00000000..fdee8b03
--- /dev/null
+++ b/src/options/theme.rs
@@ -0,0 +1,251 @@
+/// Delta doesn't have a formal concept of a "theme". What it has is
+/// (a) the choice of syntax-highlighting theme
+/// (b) the choice of light-background-mode vs dark-background-mode, which determine certain
+/// default color choices
+/// This module sets those options. If the light/dark background mode choice is not made explicitly
+/// by the user, it is determined by the classification of the syntax theme into light-background
+/// vs dark-background syntax themes. If the user didn't choose a syntax theme, a dark-background
+/// default is selected.
+use syntect::highlighting::ThemeSet;
+
+use crate::bat::assets::HighlightingAssets;
+use crate::cli;
+use crate::env;
+
+#[allow(non_snake_case)]
+pub fn set__is_light_mode__syntax_theme__syntax_set(
+ opt: &mut cli::Opt,
+ assets: HighlightingAssets,
+) {
+ let syntax_theme_name_from_bat_theme = env::get_env_var("BAT_THEME");
+ let (is_light_mode, syntax_theme_name) = get_is_light_mode_and_syntax_theme_name(
+ opt.syntax_theme.as_ref(),
+ syntax_theme_name_from_bat_theme.as_ref(),
+ opt.light,
+ &assets.theme_set,
+ );
+ opt.computed.is_light_mode = is_light_mode;
+
+ opt.computed.syntax_theme = if is_no_syntax_highlighting_syntax_theme_name(&syntax_theme_name) {
+ None
+ } else {
+ Some(assets.theme_set.themes[&syntax_theme_name].clone())
+ };
+ opt.computed.syntax_set = assets.syntax_set;
+}
+
+pub fn is_light_syntax_theme(theme: &str) -> bool {
+ LIGHT_SYNTAX_THEMES.contains(&theme)
+}
+
+const LIGHT_SYNTAX_THEMES: [&str; 5] = [
+ "GitHub",
+ "Monokai Extended Light",
+ "OneHalfLight",
+ "ansi-light",
+ "Solarized (light)",
+];
+
+const DEFAULT_LIGHT_SYNTAX_THEME: &str = "GitHub";
+const DEFAULT_DARK_SYNTAX_THEME: &str = "Monokai Extended";
+
+fn is_no_syntax_highlighting_syntax_theme_name(theme_name: &str) -> bool {
+ theme_name.to_lowercase() == "none"
+}
+
+/// Return a (theme_name, is_light_mode) tuple.
+/// theme_name == None in return value means syntax highlighting is disabled.
+///
+/// There are two types of color choices that have to be made:
+
+/// 1. The choice of "theme". This is the language syntax highlighting theme; you have to make this
+/// choice when using `bat` also.
+/// 2. The choice of "light vs dark mode". This determines whether the background colors should be
+/// chosen for a light or dark terminal background. (`bat` has no equivalent.)
+///
+/// Basically:
+/// 1. The theme is specified by the `--theme` option. If this isn't supplied then it is specified
+/// by the `BAT_PAGER` environment variable.
+/// 2. Light vs dark mode is specified by the `--light` or `--dark` options. If these aren't
+/// supplied then it is inferred from the chosen theme.
+///
+/// In the absence of other factors, the default assumes a dark terminal background.
+///
+/// Specifically, the rules are as follows:
+///
+/// | --theme | $BAT_THEME | --light/--dark | Behavior |
+/// |------------|------------|----------------|----------------------------------------------------------------------------|
+/// | - | - | - | default dark theme, dark mode |
+/// | some_theme | (IGNORED) | - | some_theme with light/dark mode inferred accordingly |
+/// | - | BAT_THEME | - | BAT_THEME, with light/dark mode inferred accordingly |
+/// | - | - | yes | default light/dark theme, light/dark mode |
+/// | some_theme | (IGNORED) | yes | some_theme, light/dark mode (even if some_theme conflicts with light/dark) |
+/// | - | BAT_THEME | yes | BAT_THEME, light/dark mode (even if BAT_THEME conflicts with light/dark) |
+fn get_is_light_mode_and_syntax_theme_name(
+ theme_arg: Option<&String>,
+ bat_theme_env_var: Option<&String>,
+ light_mode_arg: bool,
+ theme_set: &ThemeSet,
+) -> (bool, String) {
+ let theme_arg = valid_syntax_theme_name_or_none(theme_arg, theme_set);
+ let bat_theme_env_var = valid_syntax_theme_name_or_none(bat_theme_env_var, theme_set);
+ match (theme_arg, bat_theme_env_var, light_mode_arg) {
+ (None, None, false) => (false, DEFAULT_DARK_SYNTAX_THEME.to_string()),
+ (Some(theme_name), _, false) => (is_light_syntax_theme(&theme_name), theme_name),
+ (None, Some(theme_name), false) => (is_light_syntax_theme(&theme_name), theme_name),
+ (None, None, true) => (true, DEFAULT_LIGHT_SYNTAX_THEME.to_string()),
+ (Some(theme_name), _, is_light_mode) => (is_light_mode, theme_name),
+ (None, Some(theme_name), is_light_mode) => (is_light_mode, theme_name),
+ }
+}
+
+// At this stage the theme name is considered valid if it is either a real theme name or the special
+// no-syntax-highlighting name.
+fn valid_syntax_theme_name_or_none(
+ theme_name: Option<&String>,
+ theme_set: &ThemeSet,
+) -> Option<String> {
+ match theme_name {
+ Some(name)
+ if is_no_syntax_highlighting_syntax_theme_name(name)
+ || theme_set.themes.contains_key(name) =>
+ {
+ Some(name.to_string())
+ }
+ _ => None,
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use std::env;
+
+ use super::*;
+ use crate::color;
+ use crate::tests::integration_test_utils::integration_test_utils;
+
+ #[test]
+ fn test_syntax_theme_selection() {
+ #[derive(PartialEq)]
+ enum Mode {
+ Light,
+ Dark,
+ };
+ for (
+ syntax_theme,
+ bat_theme_env_var,
+ mode, // (--light, --dark)
+ expected_syntax_theme,
+ expected_mode,
+ ) in vec![
+ (None, "", None, DEFAULT_DARK_SYNTAX_THEME, Mode::Dark),
+ (Some("GitHub"), "", None, "GitHub", Mode::Light),
+ (Some("GitHub"), "1337", None, "GitHub", Mode::Light),
+ (None, "1337", None, "1337", Mode::Dark),
+ (
+ None,
+ "<not set>",
+ None,
+ DEFAULT_DARK_SYNTAX_THEME,
+ Mode::Dark,
+ ),
+ (
+ None,
+ "",
+ Some(Mode::Light),
+ DEFAULT_LIGHT_SYNTAX_THEME,
+ Mode::Light,
+ ),
+ (
+ None,
+ "",
+ Some(Mode::Dark),
+ DEFAULT_DARK_SYNTAX_THEME,
+ Mode::Dark,
+ ),
+ (
+ None,
+ "<@@@@@>",
+ Some(Mode::Light),
+ DEFAULT_LIGHT_SYNTAX_THEME,
+ Mode::Light,
+ ),
+ (None, "GitHub", Some(Mode::Light), "GitHub", Mode::Light),
+ (Some("none"), "", None, "none", Mode::Dark),
+ (Some("None"), "", Some(Mode::Light), "none", Mode::Light),
+ ] {
+ if bat_theme_env_var == "<not set>" {
+ env::remove_var("BAT_THEME")
+ } else {
+ env::set_var("BAT_THEME", bat_theme_env_var);
+ }
+ let mut args = vec![];
+ if let Some(syntax_theme) = syntax_theme {
+ args.push("--syntax-theme");
+ args.push(syntax_theme);
+ }
+ let is_true_color = true;
+ if is_true_color {
+ args.push("--24-bit-color");
+ args.push("always");
+ } else {
+ args.push("--24-bit-color");
+ args.push("never");
+ }
+ match mode {
+ Some(Mode::Light) => {
+ args.push("--light");
+ }
+ Some(Mode::Dark) => {
+ args.push("--dark");
+ }
+ None => {}
+ }
+ let config = integration_test_utils::make_config(&args);
+ assert_eq!(
+ &config
+ .syntax_theme
+ .clone()
+ .map(|t| t.name.unwrap())
+ .unwrap_or("none".to_string()),
+ expected_syntax_theme
+ );
+ if is_no_syntax_highlighting_syntax_theme_name(expected_syntax_theme) {
+ assert!(config.syntax_theme.is_none())
+ } else {
+ assert_eq!(
+ config.syntax_theme.unwrap().name.as_ref().unwrap(),
+ expected_syntax_theme
+ );
+ }
+ assert_eq!(
+ config.minus_style.ansi_term_style.background.unwrap(),
+ color::get_minus_background_color_default(
+ expected_mode == Mode::Light,
+ is_true_color
+ )
+ );
+ assert_eq!(
+ config.minus_emph_style.ansi_term_style.background.unwrap(),
+ color::get_minus_emph_background_color_default(
+ expected_mode == Mode::Light,
+ is_true_color
+ )
+ );
+ assert_eq!(
+ config.plus_style.ansi_term_style.background.unwrap(),
+ color::get_plus_background_color_default(
+ expected_mode == Mode::Light,
+ is_true_color
+ )
+ );
+ assert_eq!(
+ config.plus_emph_style.ansi_term_style.background.unwrap(),
+ color::get_plus_emph_background_color_default(
+ expected_mode == Mode::Light,
+ is_true_color
+ )
+ );
+ }
+ }
+}