diff --git a/Cargo.toml b/Cargo.toml index 5aff965b5..6d5f7511f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,3 +63,6 @@ features = [] version = "0.12.4" default-features = false features = [] + +[profile.test] +opt-level = 2 diff --git a/src/cli.rs b/src/cli.rs index cfc72a7a6..7bb414006 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -9,6 +9,7 @@ use syntect::highlighting::Theme as SyntaxTheme; use syntect::parsing::SyntaxSet; use crate::config::delta_unreachable; +use crate::env::DeltaEnv; use crate::git_config::{GitConfig, GitConfigEntry}; use crate::options; use crate::utils; @@ -1072,6 +1073,9 @@ pub struct Opt { #[clap(skip)] pub git_config_entries: HashMap, + + #[clap(skip)] + pub env: DeltaEnv, } #[derive(Default, Clone, Debug)] @@ -1120,28 +1124,40 @@ impl Default for PagingMode { impl Opt { pub fn from_args_and_git_config( + env: DeltaEnv, git_config: Option, assets: HighlightingAssets, ) -> Self { - Self::from_clap_and_git_config(Self::into_app().get_matches(), git_config, assets) + Self::from_clap_and_git_config(env, Self::into_app().get_matches(), git_config, assets) } - pub fn from_iter_and_git_config(iter: I, git_config: Option) -> Self + pub fn from_iter_and_git_config( + env: DeltaEnv, + iter: I, + git_config: Option, + ) -> Self where I: IntoIterator, I::Item: Into + Clone, { let assets = utils::bat::assets::load_highlighting_assets(); - Self::from_clap_and_git_config(Self::into_app().get_matches_from(iter), git_config, assets) + Self::from_clap_and_git_config( + env, + Self::into_app().get_matches_from(iter), + git_config, + assets, + ) } fn from_clap_and_git_config( + env: DeltaEnv, arg_matches: clap::ArgMatches, mut git_config: Option, assets: HighlightingAssets, ) -> Self { let mut opt = Opt::from_arg_matches(&arg_matches) .unwrap_or_else(|_| delta_unreachable("Opt::from_arg_matches failed")); + opt.env = env; options::set::set_options(&mut opt, &mut git_config, &arg_matches, assets); opt.git_config = git_config; opt diff --git a/src/config.rs b/src/config.rs index 24fe681df..c6d7ef518 100644 --- a/src/config.rs +++ b/src/config.rs @@ -10,7 +10,6 @@ use crate::ansi; use crate::cli; use crate::color; use crate::delta::State; -use crate::env; use crate::fatal; use crate::features::navigate; use crate::features::side_by_side::{self, ansifill, LeftRight}; @@ -151,10 +150,12 @@ impl From for Config { let wrap_config = WrapConfig::from_opt(&opt, styles["inline-hint-style"]); - let max_line_distance_for_naively_paired_lines = - env::get_env_var("DELTA_EXPERIMENTAL_MAX_LINE_DISTANCE_FOR_NAIVELY_PAIRED_LINES") - .map(|s| s.parse::().unwrap_or(0.0)) - .unwrap_or(0.0); + let max_line_distance_for_naively_paired_lines = opt + .env + .experimental_max_line_distance_for_naively_paired_lines + .as_ref() + .map(|s| s.parse::().unwrap_or(0.0)) + .unwrap_or(0.0); let commit_regex = Regex::new(&opt.commit_regex).unwrap_or_else(|_| { fatal(format!( @@ -217,11 +218,11 @@ impl From for Config { }; #[cfg(not(test))] - let cwd_of_delta_process = std::env::current_dir().ok(); + let cwd_of_delta_process = opt.env.current_dir; #[cfg(test)] let cwd_of_delta_process = Some(utils::path::fake_delta_cwd_for_tests()); - let cwd_relative_to_repo_root = std::env::var("GIT_PREFIX").ok(); + let cwd_relative_to_repo_root = opt.env.git_prefix; let cwd_of_user_shell_process = utils::path::cwd_of_user_shell_process( cwd_of_delta_process.as_ref(), diff --git a/src/env.rs b/src/env.rs index 5eb06cc1a..8735d9138 100644 --- a/src/env.rs +++ b/src/env.rs @@ -1,24 +1,73 @@ -#[cfg(not(test))] use std::env; -/// If `name` is set and, after trimming whitespace, is not empty string, then return that trimmed -/// string. Else None. -pub fn get_env_var(_name: &str) -> Option { - #[cfg(not(test))] - match env::var(_name).unwrap_or_else(|_| "".to_string()).trim() { - "" => None, - non_empty_string => Some(non_empty_string.to_string()), +const COLORTERM: &str = "COLORTERM"; +const BAT_THEME: &str = "BAT_THEME"; +const GIT_CONFIG_PARAMETERS: &str = "GIT_CONFIG_PARAMETERS"; +const GIT_PREFIX: &str = "GIT_PREFIX"; +const DELTA_FEATURES: &str = "DELTA_FEATURES"; +const DELTA_NAVIGATE: &str = "DELTA_NAVIGATE"; +const DELTA_EXPERIMENTAL_MAX_LINE_DISTANCE_FOR_NAIVELY_PAIRED_LINES: &str = + "DELTA_EXPERIMENTAL_MAX_LINE_DISTANCE_FOR_NAIVELY_PAIRED_LINES"; +const DELTA_PAGER: &str = "DELTA_PAGER"; +const BAT_PAGER: &str = "BAT_PAGER"; +const PAGER: &str = "PAGER"; + +#[derive(Default, Clone)] +pub struct DeltaEnv { + pub bat_theme: Option, + pub colorterm: Option, + pub current_dir: Option, + pub experimental_max_line_distance_for_naively_paired_lines: Option, + pub features: Option, + pub git_config_parameters: Option, + pub git_prefix: Option, + pub navigate: Option, + pub pagers: (Option, Option, Option), +} + +impl DeltaEnv { + /// Create a structure with current environment variable + pub fn init() -> Self { + let bat_theme = env::var(BAT_THEME).ok(); + let colorterm = env::var(COLORTERM).ok(); + let experimental_max_line_distance_for_naively_paired_lines = + env::var(DELTA_EXPERIMENTAL_MAX_LINE_DISTANCE_FOR_NAIVELY_PAIRED_LINES).ok(); + let features = env::var(DELTA_FEATURES).ok(); + let git_config_parameters = env::var(GIT_CONFIG_PARAMETERS).ok(); + let git_prefix = env::var(GIT_PREFIX).ok(); + let navigate = env::var(DELTA_NAVIGATE).ok(); + + let current_dir = env::current_dir().ok(); + let pagers = ( + env::var(DELTA_PAGER).ok(), + env::var(BAT_PAGER).ok(), + env::var(PAGER).ok(), + ); + + Self { + bat_theme, + colorterm, + current_dir, + experimental_max_line_distance_for_naively_paired_lines, + features, + git_config_parameters, + git_prefix, + navigate, + pagers, + } } - #[cfg(test)] - None } -/// If `name` is set to any value at all (including "") then return true; else false. -pub fn get_boolean_env_var(_name: &str) -> bool { - #[cfg(not(test))] - { - env::var(_name).ok().is_some() +#[cfg(test)] +pub mod tests { + use super::DeltaEnv; + use std::env; + + #[test] + fn test_env_parsing() { + let feature = "Awesome Feature"; + env::set_var("DELTA_FEATURES", feature); + let env = DeltaEnv::init(); + assert_eq!(env.features, Some(feature.into())); } - #[cfg(test)] - false } diff --git a/src/features/mod.rs b/src/features/mod.rs index 5be2b3dc4..8234d62eb 100644 --- a/src/features/mod.rs +++ b/src/features/mod.rs @@ -94,6 +94,7 @@ pub mod tests { use std::fs::remove_file; use crate::cli; + use crate::env::DeltaEnv; use crate::features::make_builtin_features; use crate::tests::integration_test_utils::make_options_from_args_and_git_config; @@ -102,7 +103,7 @@ pub mod tests { let builtin_features = make_builtin_features(); let mut args = vec!["delta".to_string()]; args.extend(builtin_features.keys().map(|s| format!("--{}", s))); - let opt = cli::Opt::from_iter_and_git_config(args, None); + let opt = cli::Opt::from_iter_and_git_config(DeltaEnv::default(), args, None); let features: HashSet<&str> = opt .features .as_deref() diff --git a/src/git_config/mod.rs b/src/git_config/mod.rs index 21517252c..6b87444e3 100644 --- a/src/git_config/mod.rs +++ b/src/git_config/mod.rs @@ -2,9 +2,9 @@ mod git_config_entry; pub use git_config_entry::{GitConfigEntry, GitRemoteRepo}; +use crate::env::DeltaEnv; use regex::Regex; use std::collections::HashMap; -use std::env; #[cfg(test)] use std::path::Path; @@ -37,11 +37,11 @@ impl Clone for GitConfig { impl GitConfig { #[cfg(not(test))] - pub fn try_create() -> Option { + pub fn try_create(env: &DeltaEnv) -> Option { use crate::fatal; - let repo = match std::env::current_dir() { - Ok(dir) => git2::Repository::discover(dir).ok(), + let repo = match &env.current_dir { + Some(dir) => git2::Repository::discover(dir).ok(), _ => None, }; let config = match &repo { @@ -55,7 +55,7 @@ impl GitConfig { }); Some(Self { config, - config_from_env_var: parse_config_from_env_var(), + config_from_env_var: parse_config_from_env_var(env), repo, enabled: true, }) @@ -65,16 +65,16 @@ impl GitConfig { } #[cfg(test)] - pub fn try_create() -> Option { + pub fn try_create(_env: &DeltaEnv) -> Option { unreachable!("GitConfig::try_create() is not available when testing"); } #[cfg(test)] - pub fn from_path(path: &Path, honor_env_var: bool) -> Self { + pub fn from_path(env: &DeltaEnv, path: &Path, honor_env_var: bool) -> Self { Self { config: git2::Config::open(path).unwrap(), config_from_env_var: if honor_env_var { - parse_config_from_env_var() + parse_config_from_env_var(env) } else { HashMap::new() }, @@ -96,9 +96,9 @@ impl GitConfig { } } -fn parse_config_from_env_var() -> HashMap { - if let Ok(s) = env::var("GIT_CONFIG_PARAMETERS") { - parse_config_from_env_var_value(&s) +fn parse_config_from_env_var(env: &DeltaEnv) -> HashMap { + if let Some(s) = &env.git_config_parameters { + parse_config_from_env_var_value(s) } else { HashMap::new() } diff --git a/src/main.rs b/src/main.rs index cfa076ee4..1d2b76336 100644 --- a/src/main.rs +++ b/src/main.rs @@ -86,7 +86,12 @@ fn main() -> std::io::Result<()> { // arguments and without standard input; 2 is used to report a real problem. fn run_app() -> std::io::Result { let assets = utils::bat::assets::load_highlighting_assets(); - let opt = cli::Opt::from_args_and_git_config(git_config::GitConfig::try_create(), assets); + let env = env::DeltaEnv::init(); + let opt = cli::Opt::from_args_and_git_config( + env.clone(), + git_config::GitConfig::try_create(&env), + assets, + ); let subcommand_result = if opt.list_languages { Some(list_languages()) @@ -128,7 +133,7 @@ fn run_app() -> std::io::Result { } let mut output_type = - OutputType::from_mode(config.paging_mode, config.pager.clone(), &config).unwrap(); + OutputType::from_mode(&env, config.paging_mode, config.pager.clone(), &config).unwrap(); let mut writer = output_type.handle().unwrap(); match (config.minus_file.as_ref(), config.plus_file.as_ref()) { diff --git a/src/options/get.rs b/src/options/get.rs index 0dd02b95c..a09d1668c 100644 --- a/src/options/get.rs +++ b/src/options/get.rs @@ -137,173 +137,138 @@ impl GetOptionValue for usize {} #[cfg(test)] pub mod tests { - use std::env; use std::fs::remove_file; + use crate::cli::Opt; + use crate::env::DeltaEnv; use crate::options::get::get_themes; use crate::tests::integration_test_utils; - // TODO: the followig tests are collapsed into one since they all set the same env var and thus - // could affect each other if allowed to run concurrently. - - #[test] - fn test_env_var_overrides_git_config() { - // ---------------------------------------------------------------------------------------- - // simple string - let git_config_contents = b" -[delta] - plus-style = blue -"; - let git_config_path = "delta__test_simple_string_env_var_overrides_git_config.gitconfig"; - + // fn generic(_s: SGen) {} + fn _test_env_var_overrides_git_config_generic( + git_config_contents: &[u8], + git_config_path: &str, + env_value: String, + fn_cmp_before: &dyn Fn(Opt), + fn_cmp_after: &dyn Fn(Opt), + ) { let opt = integration_test_utils::make_options_from_args_and_git_config( &[], Some(git_config_contents), Some(git_config_path), ); - assert_eq!(opt.plus_style, "blue"); + fn_cmp_before(opt); - env::set_var("GIT_CONFIG_PARAMETERS", "'delta.plus-style=green'"); - let opt = integration_test_utils::make_options_from_args_and_git_config_honoring_env_var( + let opt = integration_test_utils::make_options_from_args_and_git_config_honoring_env_var_with_custom_env( + DeltaEnv { + git_config_parameters: Some(env_value), + ..DeltaEnv::default() + }, &[], Some(git_config_contents), Some(git_config_path), ); - assert_eq!(opt.plus_style, "green"); + fn_cmp_after(opt); remove_file(git_config_path).unwrap(); + } + #[test] + fn test_env_var_overrides_git_config_simple_string() { + let git_config_contents = b" +[delta] + plus-style = blue +"; + let git_config_path = "delta__test_simple_string_env_var_overrides_git_config.gitconfig"; + _test_env_var_overrides_git_config_generic( + git_config_contents, + git_config_path, + "'delta.plus-style=green'".into(), + &|opt: Opt| assert_eq!(opt.plus_style, "blue"), + &|opt: Opt| assert_eq!(opt.plus_style, "green"), + ); + } - // ---------------------------------------------------------------------------------------- - // complex string + #[test] + fn test_env_var_overrides_git_config_complex_string() { let git_config_contents = br##" [delta] minus-style = red bold ul "#ffeeee" "##; let git_config_path = "delta__test_complex_string_env_var_overrides_git_config.gitconfig"; - - let opt = integration_test_utils::make_options_from_args_and_git_config( - &[], - Some(git_config_contents), - Some(git_config_path), - ); - assert_eq!(opt.minus_style, r##"red bold ul #ffeeee"##); - - env::set_var( - "GIT_CONFIG_PARAMETERS", - r##"'delta.minus-style=magenta italic ol "#aabbcc"'"##, - ); - let opt = integration_test_utils::make_options_from_args_and_git_config_honoring_env_var( - &[], - Some(git_config_contents), - Some(git_config_path), + _test_env_var_overrides_git_config_generic( + git_config_contents, + git_config_path, + r##"'delta.minus-style=magenta italic ol "#aabbcc"'"##.into(), + &|opt: Opt| assert_eq!(opt.minus_style, r##"red bold ul #ffeeee"##), + &|opt: Opt| assert_eq!(opt.minus_style, r##"magenta italic ol "#aabbcc""##,), ); - assert_eq!(opt.minus_style, r##"magenta italic ol "#aabbcc""##,); - - remove_file(git_config_path).unwrap(); + } - // ---------------------------------------------------------------------------------------- - // option string + #[test] + fn test_env_var_overrides_git_config_option_string() { let git_config_contents = b" [delta] plus-style = blue "; let git_config_path = "delta__test_option_string_env_var_overrides_git_config.gitconfig"; - - let opt = integration_test_utils::make_options_from_args_and_git_config( - &[], - Some(git_config_contents), - Some(git_config_path), - ); - assert_eq!(opt.plus_style, "blue"); - - env::set_var("GIT_CONFIG_PARAMETERS", "'delta.plus-style=green'"); - let opt = integration_test_utils::make_options_from_args_and_git_config_honoring_env_var( - &[], - Some(git_config_contents), - Some(git_config_path), + _test_env_var_overrides_git_config_generic( + git_config_contents, + git_config_path, + "'delta.plus-style=green'".into(), + &|opt: Opt| assert_eq!(opt.plus_style, "blue"), + &|opt: Opt| assert_eq!(opt.plus_style, "green"), ); - assert_eq!(opt.plus_style, "green"); - - remove_file(git_config_path).unwrap(); + } - // ---------------------------------------------------------------------------------------- - // bool + #[test] + fn test_env_var_overrides_git_config_bool() { let git_config_contents = b" [delta] side-by-side = true "; let git_config_path = "delta__test_bool_env_var_overrides_git_config.gitconfig"; - - let opt = integration_test_utils::make_options_from_args_and_git_config( - &[], - Some(git_config_contents), - Some(git_config_path), - ); - assert_eq!(opt.side_by_side, true); - - env::set_var("GIT_CONFIG_PARAMETERS", "'delta.side-by-side=false'"); - let opt = integration_test_utils::make_options_from_args_and_git_config_honoring_env_var( - &[], - Some(git_config_contents), - Some(git_config_path), + _test_env_var_overrides_git_config_generic( + git_config_contents, + git_config_path, + "'delta.side-by-side=false'".into(), + &|opt: Opt| assert_eq!(opt.side_by_side, true), + &|opt: Opt| assert_eq!(opt.side_by_side, false), ); - assert_eq!(opt.side_by_side, false); - - remove_file(git_config_path).unwrap(); + } - // ---------------------------------------------------------------------------------------- - // int + #[test] + fn test_env_var_overrides_git_config_int() { let git_config_contents = b" [delta] max-line-length = 1 "; let git_config_path = "delta__test_int_env_var_overrides_git_config.gitconfig"; - - let opt = integration_test_utils::make_options_from_args_and_git_config( - &[], - Some(git_config_contents), - Some(git_config_path), - ); - assert_eq!(opt.max_line_length, 1); - - env::set_var("GIT_CONFIG_PARAMETERS", "'delta.max-line-length=2'"); - let opt = integration_test_utils::make_options_from_args_and_git_config_honoring_env_var( - &[], - Some(git_config_contents), - Some(git_config_path), + _test_env_var_overrides_git_config_generic( + git_config_contents, + git_config_path, + "'delta.max-line-length=2'".into(), + &|opt: Opt| assert_eq!(opt.max_line_length, 1), + &|opt: Opt| assert_eq!(opt.max_line_length, 2), ); - assert_eq!(opt.max_line_length, 2); - - remove_file(git_config_path).unwrap(); + } - // ---------------------------------------------------------------------------------------- - // float + #[test] + fn test_env_var_overrides_git_config_float() { let git_config_contents = b" [delta] max-line-distance = 0.6 "; let git_config_path = "delta__test_float_env_var_overrides_git_config.gitconfig"; - - let opt = integration_test_utils::make_options_from_args_and_git_config_honoring_env_var( - &[], - Some(git_config_contents), - Some(git_config_path), - ); - assert_eq!(opt.max_line_distance, 0.6); - - env::set_var("GIT_CONFIG_PARAMETERS", "'delta.max-line-distance=0.7'"); - let opt = integration_test_utils::make_options_from_args_and_git_config_honoring_env_var( - &[], - Some(git_config_contents), - Some(git_config_path), + _test_env_var_overrides_git_config_generic( + git_config_contents, + git_config_path, + "'delta.max-line-distance=0.7'".into(), + &|opt: Opt| assert_eq!(opt.max_line_distance, 0.6), + &|opt: Opt| assert_eq!(opt.max_line_distance, 0.7), ); - assert_eq!(opt.max_line_distance, 0.7); - - remove_file(git_config_path).unwrap(); } #[test] - #[ignore] // FIXME fn test_delta_features_env_var() { let git_config_contents = b" [delta] @@ -319,22 +284,32 @@ pub mod tests { assert_eq!(opt.features.unwrap(), "feature-from-gitconfig"); assert_eq!(opt.side_by_side, false); - env::set_var("DELTA_FEATURES", "side-by-side"); - let opt = integration_test_utils::make_options_from_args_and_git_config( + let opt = integration_test_utils::make_options_from_args_and_git_config_with_custom_env( + DeltaEnv { + features: Some("side-by-side".into()), + ..DeltaEnv::default() + }, &[], Some(git_config_contents), Some(git_config_path), ); - assert_eq!(opt.features.unwrap(), "side-by-side"); + // `line-numbers` is a builtin feature induced by side-by-side + assert_eq!(opt.features.unwrap(), "line-numbers side-by-side"); assert_eq!(opt.side_by_side, true); - env::set_var("DELTA_FEATURES", "+side-by-side"); - let opt = integration_test_utils::make_options_from_args_and_git_config( + let opt = integration_test_utils::make_options_from_args_and_git_config_with_custom_env( + DeltaEnv { + features: Some("+side-by-side".into()), + ..DeltaEnv::default() + }, &[], Some(git_config_contents), Some(git_config_path), ); - assert_eq!(opt.features.unwrap(), "side-by-side feature-from-gitconfig"); + assert_eq!( + opt.features.unwrap(), + "feature-from-gitconfig line-numbers side-by-side" + ); assert_eq!(opt.side_by_side, true); remove_file(git_config_path).unwrap(); @@ -365,6 +340,7 @@ pub mod tests { let git_config_path = "delta__test_get_themes_git_config.gitconfig"; let git_config = Some(integration_test_utils::make_git_config( + &DeltaEnv::default(), git_config_contents.as_bytes(), git_config_path, false, diff --git a/src/options/set.rs b/src/options/set.rs index 57d95b27d..417765167 100644 --- a/src/options/set.rs +++ b/src/options/set.rs @@ -8,7 +8,7 @@ use console::Term; use crate::cli; use crate::config; -use crate::env; +use crate::env::DeltaEnv; use crate::errors::*; use crate::fatal; use crate::features; @@ -76,9 +76,9 @@ pub fn set_options( } set_git_config_entries(opt, git_config); } - opt.navigate = opt.navigate || env::get_boolean_env_var("DELTA_NAVIGATE"); + opt.navigate = opt.navigate || opt.env.navigate.is_some(); if opt.syntax_theme.is_none() { - opt.syntax_theme = env::get_env_var("BAT_THEME") + opt.syntax_theme = opt.env.bat_theme.clone(); } let option_names = cli::Opt::get_argument_and_option_names(); @@ -336,7 +336,7 @@ fn gather_features( builtin_features: &HashMap, git_config: &Option, ) -> Vec { - let from_env_var = env::get_env_var("DELTA_FEATURES"); + let from_env_var = &opt.env.features; let from_args = opt.features.as_deref().unwrap_or(""); let input_features: Vec<&str> = match from_env_var.as_deref() { Some(from_env_var) if from_env_var.starts_with('+') => from_env_var[1..] @@ -463,12 +463,9 @@ fn gather_builtin_features_from_flags_in_gitconfig( git_config: &GitConfig, ) { for child_feature in builtin_features.keys() { - if let Some(value) = - git_config.get::(&format!("{}.{}", git_config_key, child_feature)) + if let Some(true) = git_config.get::(&format!("{}.{}", git_config_key, child_feature)) { - if value { - gather_builtin_features_recursively(child_feature, features, builtin_features, opt); - } + gather_builtin_features_recursively(child_feature, features, builtin_features, opt); } } } @@ -507,17 +504,15 @@ fn gather_builtin_features_recursively( } for child_feature in builtin_features.keys() { if let Some(child_features_fn) = feature_data.get(child_feature) { - if let ProvenancedOptionValue::DefaultValue(OptionValue::Boolean(value)) = + if let ProvenancedOptionValue::DefaultValue(OptionValue::Boolean(true)) = child_features_fn(opt, &None) { - if value { - gather_builtin_features_recursively( - child_feature, - features, - builtin_features, - opt, - ); - } + gather_builtin_features_recursively( + child_feature, + features, + builtin_features, + opt, + ); } } } @@ -645,7 +640,7 @@ fn set_true_color(opt: &mut cli::Opt) { opt.computed.true_color = match opt.true_color.as_ref() { "always" => true, "never" => false, - "auto" => is_truecolor_terminal(), + "auto" => is_truecolor_terminal(&opt.env), _ => { fatal(format!( "Invalid value for --true-color option: {} (valid values are \"always\", \"never\", and \"auto\")", @@ -655,8 +650,9 @@ fn set_true_color(opt: &mut cli::Opt) { }; } -fn is_truecolor_terminal() -> bool { - env::get_env_var("COLORTERM") +fn is_truecolor_terminal(env: &DeltaEnv) -> bool { + env.colorterm + .as_ref() .map(|colorterm| colorterm == "truecolor" || colorterm == "24bit") .unwrap_or(false) } diff --git a/src/options/theme.rs b/src/options/theme.rs index 642699c21..2d853ada2 100644 --- a/src/options/theme.rs +++ b/src/options/theme.rs @@ -10,14 +10,13 @@ use bat; use 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 syntax_theme_name_from_bat_theme = &opt.env.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(), diff --git a/src/subcommands/show_colors.rs b/src/subcommands/show_colors.rs index 09a8f19b1..7aaa716ce 100644 --- a/src/subcommands/show_colors.rs +++ b/src/subcommands/show_colors.rs @@ -3,6 +3,7 @@ use crate::color; use crate::colors; use crate::config; use crate::delta; +use crate::env::DeltaEnv; use crate::git_config; use crate::paint; use crate::paint::BgShouldFill; @@ -16,11 +17,16 @@ pub fn show_colors() -> std::io::Result<()> { use crate::{delta::DiffType, utils}; let assets = utils::bat::assets::load_highlighting_assets(); - let opt = cli::Opt::from_args_and_git_config(git_config::GitConfig::try_create(), assets); + let env = DeltaEnv::default(); + let opt = cli::Opt::from_args_and_git_config( + env.clone(), + git_config::GitConfig::try_create(&env), + assets, + ); let config = config::Config::from(opt); let mut output_type = - OutputType::from_mode(PagingMode::QuitIfOneScreen, None, &config).unwrap(); + OutputType::from_mode(&env, PagingMode::QuitIfOneScreen, None, &config).unwrap(); let writer = output_type.handle().unwrap(); let mut painter = paint::Painter::new(writer, &config); diff --git a/src/subcommands/show_syntax_themes.rs b/src/subcommands/show_syntax_themes.rs index be7478a49..15fe0e21b 100644 --- a/src/subcommands/show_syntax_themes.rs +++ b/src/subcommands/show_syntax_themes.rs @@ -1,6 +1,7 @@ use crate::cli; use crate::config; use crate::delta; +use crate::env::DeltaEnv; use crate::options::theme::is_light_syntax_theme; use crate::utils; use crate::utils::bat::output::{OutputType, PagingMode}; @@ -9,8 +10,10 @@ use std::io::{self, ErrorKind, Read, Write}; #[cfg(not(tarpaulin_include))] pub fn show_syntax_themes() -> std::io::Result<()> { + let env = DeltaEnv::default(); let assets = utils::bat::assets::load_highlighting_assets(); let mut output_type = OutputType::from_mode( + &env, PagingMode::QuitIfOneScreen, None, &config::Config::from(cli::Opt::parse()), diff --git a/src/subcommands/show_themes.rs b/src/subcommands/show_themes.rs index 668c6f9f0..f168c21ed 100644 --- a/src/subcommands/show_themes.rs +++ b/src/subcommands/show_themes.rs @@ -3,6 +3,7 @@ use std::io::{self, ErrorKind, Read}; use crate::cli; use crate::config; use crate::delta; +use crate::env::DeltaEnv; use crate::git_config; use crate::options::get::get_themes; use crate::utils::bat::output::{OutputType, PagingMode}; @@ -24,17 +25,25 @@ pub fn show_themes(dark: bool, light: bool, computed_theme_is_light: bool) -> st } }; - let git_config = git_config::GitConfig::try_create(); - let opt = - cli::Opt::from_iter_and_git_config(&["", "", "--navigate", "--show-themes"], git_config); + let env = DeltaEnv::default(); + let git_config = git_config::GitConfig::try_create(&env); + let opt = cli::Opt::from_iter_and_git_config( + env.clone(), + &["", "", "--navigate", "--show-themes"], + git_config, + ); let mut output_type = - OutputType::from_mode(PagingMode::Always, None, &config::Config::from(opt)).unwrap(); + OutputType::from_mode(&env, PagingMode::Always, None, &config::Config::from(opt)).unwrap(); let title_style = ansi_term::Style::new().bold(); let writer = output_type.handle().unwrap(); - for theme in &get_themes(git_config::GitConfig::try_create()) { - let git_config = git_config::GitConfig::try_create(); - let opt = cli::Opt::from_iter_and_git_config(&["", "", "--features", theme], git_config); + for theme in &get_themes(git_config::GitConfig::try_create(&env)) { + let git_config = git_config::GitConfig::try_create(&env); + let opt = cli::Opt::from_iter_and_git_config( + env.clone(), + &["", "", "--features", theme], + git_config, + ); let is_dark_theme = opt.dark; let is_light_theme = opt.light; let config = config::Config::from(opt); diff --git a/src/tests/integration_test_utils.rs b/src/tests/integration_test_utils.rs index 5202492d9..5d997e370 100644 --- a/src/tests/integration_test_utils.rs +++ b/src/tests/integration_test_utils.rs @@ -12,6 +12,7 @@ use crate::ansi; use crate::cli; use crate::config; use crate::delta::delta; +use crate::env::DeltaEnv; use crate::git_config::GitConfig; use crate::tests::test_utils; use crate::utils::process::tests::FakeParentArgs; @@ -21,18 +22,35 @@ pub fn make_options_from_args_and_git_config( git_config_contents: Option<&[u8]>, git_config_path: Option<&str>, ) -> cli::Opt { - _make_options_from_args_and_git_config(args, git_config_contents, git_config_path, false) + _make_options_from_args_and_git_config( + DeltaEnv::default(), + args, + git_config_contents, + git_config_path, + false, + ) } -pub fn make_options_from_args_and_git_config_honoring_env_var( +pub fn make_options_from_args_and_git_config_with_custom_env( + env: DeltaEnv, args: &[&str], git_config_contents: Option<&[u8]>, git_config_path: Option<&str>, ) -> cli::Opt { - _make_options_from_args_and_git_config(args, git_config_contents, git_config_path, true) + _make_options_from_args_and_git_config(env, args, git_config_contents, git_config_path, false) +} + +pub fn make_options_from_args_and_git_config_honoring_env_var_with_custom_env( + env: DeltaEnv, + args: &[&str], + git_config_contents: Option<&[u8]>, + git_config_path: Option<&str>, +) -> cli::Opt { + _make_options_from_args_and_git_config(env, args, git_config_contents, git_config_path, true) } fn _make_options_from_args_and_git_config( + env: DeltaEnv, args: &[&str], git_config_contents: Option<&[u8]>, git_config_path: Option<&str>, @@ -42,13 +60,13 @@ fn _make_options_from_args_and_git_config( .map(|s| *s) .collect(); let git_config = match (git_config_contents, git_config_path) { - (Some(contents), Some(path)) => Some(make_git_config(contents, path, honor_env_var)), + (Some(contents), Some(path)) => Some(make_git_config(&env, contents, path, honor_env_var)), _ => { args.push("--no-gitconfig"); None } }; - cli::Opt::from_iter_and_git_config(args, git_config) + cli::Opt::from_iter_and_git_config(env, args, git_config) } pub fn make_options_from_args(args: &[&str]) -> cli::Opt { @@ -72,11 +90,16 @@ pub fn make_config_from_args(args: &[&str]) -> config::Config { config::Config::from(make_options_from_args(args)) } -pub fn make_git_config(contents: &[u8], path: &str, honor_env_var: bool) -> GitConfig { +pub fn make_git_config( + env: &DeltaEnv, + contents: &[u8], + path: &str, + honor_env_var: bool, +) -> GitConfig { let path = Path::new(path); let mut file = File::create(path).unwrap(); file.write_all(contents).unwrap(); - GitConfig::from_path(&path, honor_env_var) + GitConfig::from_path(env, &path, honor_env_var) } pub fn get_line_of_code_from_delta( diff --git a/src/utils/bat/output.rs b/src/utils/bat/output.rs index 62761c25b..22697d4d9 100644 --- a/src/utils/bat/output.rs +++ b/src/utils/bat/output.rs @@ -1,7 +1,6 @@ // https://github.com/sharkdp/bat a1b9334a44a2c652f52dddaa83dbacba57372468 // src/output.rs // See src/utils/bat/LICENSE -use std::env; use std::ffi::OsString; use std::io::{self, Write}; use std::path::PathBuf; @@ -10,6 +9,7 @@ use std::process::{Child, Command, Stdio}; use super::less::retrieve_less_version; use crate::config; +use crate::env::DeltaEnv; use crate::fatal; use crate::features::navigate; @@ -29,34 +29,32 @@ pub enum OutputType { impl OutputType { pub fn from_mode( + env: &DeltaEnv, mode: PagingMode, pager: Option, config: &config::Config, ) -> Result { use self::PagingMode::*; Ok(match mode { - Always => OutputType::try_pager(false, pager, config)?, - QuitIfOneScreen => OutputType::try_pager(true, pager, config)?, + Always => OutputType::try_pager(env, false, pager, config)?, + QuitIfOneScreen => OutputType::try_pager(env, true, pager, config)?, _ => OutputType::stdout(), }) } /// Try to launch the pager. Fall back to stdout in case of errors. fn try_pager( + env: &DeltaEnv, quit_if_one_screen: bool, pager_from_config: Option, config: &config::Config, ) -> Result { let mut replace_arguments_to_less = false; - let pager_from_env = match ( - env::var("DELTA_PAGER"), - env::var("BAT_PAGER"), - env::var("PAGER"), - ) { - (Ok(delta_pager), _, _) => Some(delta_pager), - (_, Ok(bat_pager), _) => Some(bat_pager), - (_, _, Ok(pager)) => { + let pager_from_env = match env.pagers.clone() { + (Some(delta_pager), _, _) => Some(delta_pager), + (_, Some(bat_pager), _) => Some(bat_pager), + (_, _, Some(pager)) => { // less needs to be called with the '-R' option in order to properly interpret ANSI // color sequences. If someone has set PAGER="less -F", we therefore need to // overwrite the arguments and add '-R'.