Repository: dandavison/delta
Pull request #490 (2021-01-06 06:44:17)

For Mac mouse-scrolling works by updating less


Patch:
diff --git a/README.md b/README.md
index 3873659..7c4fa8a 100644
--- a/README.md
+++ b/README.md
@@ -483,8 +483,11 @@ Delta works on Windows. However, it is essential to use a recent version of `les
 
 ### Mouse scrolling
 
-If mouse scrolling isn't working correctly, try setting your `BAT_PAGER` environment variable to (at least) `less -R` .
-See [issue #58](https://github.com/dandavison/delta/issues/58) and [bat README / "Using a different pager"](https://github.com/sharkdp/bat#using-a-different-pager).
+If mouse scrolling isn't working correctly, ensure that you have the most recent version of `less`.
+* For Windows you can download from https://github.com/jftuga/less-Windows/releases/latest
+* For Mac you can install `brew install less; brew link less`
+
+Alternatively try setting your `DELTA_PAGER` environment variable to (at least) `less -R`. See [issue #58](https://github.com/dandavison/delta/issues/58). See also [bat README / "Using a different pager"](https://github.com/sharkdp/bat#using-a-different-pager), since the `DELTA_PAGER` environment variable functions very similarly for delta.
 
 
 ### Using Delta with Magit
@@ -700,9 +703,16 @@ OPTIONS:
         --hunk-header-style <hunk-header-style>
             Style (foreground, background, attributes) for the hunk-header. See STYLES section. Special attributes
             'file' and 'line-number' can be used to include the file path, and number of first hunk line, in the hunk
-            header. If included in the hunk header, 'file' and 'line-number' are styled according to 'file-style' and
-            'hunk-header-decoration-style' respectively. The style 'omit' can be used to remove the hunk header section
-            from the output [default: line-number syntax]
+            header. The style 'omit' can be used to remove the hunk header section from the output [default: line-
+            number syntax]
+        --hunk-header-file-style <hunk-header-file-style>
+            Style (foreground, background, attributes) for the file path part of the hunk-header. See STYLES section.
+            The file path will only be displayed if hunk-header-style contains the 'file' special attribute [default:
+            blue]
+        --hunk-header-line-number-style <hunk-header-line-number-style>
+            Style (foreground, background, attributes) for the line number part of the hunk-header. See STYLES section.
+            The line number will only be displayed if hunk-header-style contains the 'line-number' special attribute
+            [default: blue]
         --hunk-header-decoration-style <hunk-header-decoration-style>
             Style (foreground, background, attributes) for the hunk-header decoration. See STYLES section. The style
             string should contain one of the special attributes 'box', 'ul' (underline), 'ol' (overline), or the
diff --git a/src/cli.rs b/src/cli.rs
index ee3baac..41f6eb8 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -11,8 +11,7 @@ use syntect::parsing::SyntaxSet;
 
 use crate::bat_utils::assets::HighlightingAssets;
 use crate::bat_utils::output::PagingMode;
-use crate::git_config::GitConfig;
-use crate::git_config_entry::GitConfigEntry;
+use crate::git_config::{GitConfig, GitConfigEntry};
 use crate::options;
 
 #[derive(StructOpt, Clone, Default)]
@@ -366,10 +365,8 @@ pub struct Opt {
     #[structopt(long = "hunk-header-style", default_value = "line-number syntax")]
     /// Style (foreground, background, attributes) for the hunk-header. See STYLES section. Special
     /// attributes 'file' and 'line-number' can be used to include the file path, and number of
-    /// first hunk line, in the hunk header. If included in the hunk header, 'file' and
-    /// 'line-number' are styled according to 'file-style' and 'hunk-header-decoration-style'
-    /// respectively. The style 'omit' can be used to remove the hunk header section from the
-    /// output.
+    /// first hunk line, in the hunk header. The style 'omit' can be used to remove the hunk header
+    /// section from the output.
     pub hunk_header_style: String,
 
     #[structopt(long = "hunk-header-file-style", default_value = "blue")]
diff --git a/src/config.rs b/src/config.rs
index d782895..23b7b97 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -14,7 +14,7 @@ use crate::color;
 use crate::delta::State;
 use crate::env;
 use crate::features::side_by_side;
-use crate::git_config_entry::GitConfigEntry;
+use crate::git_config::GitConfigEntry;
 use crate::style::{self, Style};
 
 pub struct Config {
diff --git a/src/features/hyperlinks.rs b/src/features/hyperlinks.rs
index 3bb5e70..d59f5e9 100644
--- a/src/features/hyperlinks.rs
+++ b/src/features/hyperlinks.rs
@@ -5,7 +5,7 @@ use regex::{Captures, Regex};
 
 use crate::config::Config;
 use crate::features::OptionValueFunction;
-use crate::git_config_entry::{GitConfigEntry, GitRemoteRepo};
+use crate::git_config::{GitConfigEntry, GitRemoteRepo};
 
 pub fn make_feature() -> Vec<(String, OptionValueFunction)> {
     builtin_feature!([
diff --git a/src/git_config.rs b/src/git_config.rs
deleted file mode 100644
index ab831b3..0000000
--- a/src/git_config.rs
+++ /dev/null
@@ -1,101 +0,0 @@
-#[cfg(test)]
-use std::path::Path;
-use std::process;
-
-pub struct GitConfig {
-    config: git2::Config,
-    pub enabled: bool,
-    pub repo: Option<git2::Repository>,
-}
-
-impl GitConfig {
-    pub fn try_create() -> Option<Self> {
-        let repo = match std::env::current_dir() {
-            Ok(dir) => git2::Repository::discover(dir).ok(),
-            _ => None,
-        };
-        let config = match &repo {
-            Some(repo) => repo.config().ok(),
-            None => git2::Config::open_default().ok(),
-        };
-        match config {
-            Some(mut config) => {
-                let config = config.snapshot().unwrap_or_else(|err| {
-                    eprintln!("Failed to read git config: {}", err);
-                    process::exit(1)
-                });
-                Some(Self {
-                    config,
-                    repo,
-                    enabled: true,
-                })
-            }
-            None => None,
-        }
-    }
-
-    #[cfg(test)]
-    pub fn from_path(path: &Path) -> Self {
-        Self {
-            config: git2::Config::open(path).unwrap(),
-            repo: None,
-            enabled: true,
-        }
-    }
-
-    pub fn get<T>(&self, key: &str) -> Option<T>
-    where
-        T: GitConfigGet,
-    {
-        if self.enabled {
-            T::git_config_get(key, self)
-        } else {
-            None
-        }
-    }
-}
-
-pub trait GitConfigGet {
-    fn git_config_get(key: &str, git_config: &GitConfig) -> Option<Self>
-    where
-        Self: Sized;
-}
-
-impl GitConfigGet for String {
-    fn git_config_get(key: &str, git_config: &GitConfig) -> Option<Self> {
-        git_config.config.get_string(key).ok()
-    }
-}
-
-impl GitConfigGet for Option<String> {
-    fn git_config_get(key: &str, git_config: &GitConfig) -> Option<Self> {
-        match git_config.config.get_string(key) {
-            Ok(value) => Some(Some(value)),
-            _ => None,
-        }
-    }
-}
-
-impl GitConfigGet for bool {
-    fn git_config_get(key: &str, git_config: &GitConfig) -> Option<Self> {
-        git_config.config.get_bool(key).ok()
-    }
-}
-
-impl GitConfigGet for usize {
-    fn git_config_get(key: &str, git_config: &GitConfig) -> Option<Self> {
-        match git_config.config.get_i64(key) {
-            Ok(value) => Some(value as usize),
-            _ => None,
-        }
-    }
-}
-
-impl GitConfigGet for f64 {
-    fn git_config_get(key: &str, git_config: &GitConfig) -> Option<Self> {
-        match git_config.config.get_string(key) {
-            Ok(value) => value.parse::<f64>().ok(),
-            _ => None,
-        }
-    }
-}
diff --git a/src/git_config_entry.rs b/src/git_config/git_config_entry.rs
similarity index 100%
rename from src/git_config_entry.rs
rename to src/git_config/git_config_entry.rs
diff --git a/src/git_config/mod.rs b/src/git_config/mod.rs
new file mode 100644
index 0000000..827446e
--- /dev/null
+++ b/src/git_config/mod.rs
@@ -0,0 +1,198 @@
+mod git_config_entry;
+
+pub use git_config_entry::{GitConfigEntry, GitRemoteRepo};
+
+use regex::Regex;
+use std::collections::HashMap;
+use std::env;
+#[cfg(test)]
+use std::path::Path;
+use std::process;
+
+use lazy_static::lazy_static;
+
+pub struct GitConfig {
+    config: git2::Config,
+    config_from_env_var: HashMap<String, String>,
+    pub enabled: bool,
+    pub repo: Option<git2::Repository>,
+}
+
+impl GitConfig {
+    pub fn try_create() -> Option<Self> {
+        let repo = match std::env::current_dir() {
+            Ok(dir) => git2::Repository::discover(dir).ok(),
+            _ => None,
+        };
+        let config = match &repo {
+            Some(repo) => repo.config().ok(),
+            None => git2::Config::open_default().ok(),
+        };
+        match config {
+            Some(mut config) => {
+                let config = config.snapshot().unwrap_or_else(|err| {
+                    eprintln!("Failed to read git config: {}", err);
+                    process::exit(1)
+                });
+                Some(Self {
+                    config,
+                    config_from_env_var: parse_config_from_env_var(),
+                    repo,
+                    enabled: true,
+                })
+            }
+            None => None,
+        }
+    }
+
+    #[cfg(test)]
+    pub fn from_path(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()
+            } else {
+                HashMap::new()
+            },
+            repo: None,
+            enabled: true,
+        }
+    }
+
+    pub fn get<T>(&self, key: &str) -> Option<T>
+    where
+        T: GitConfigGet,
+    {
+        if self.enabled {
+            T::git_config_get(key, self)
+        } else {
+            None
+        }
+    }
+}
+
+fn parse_config_from_env_var() -> HashMap<String, String> {
+    if let Ok(s) = env::var("GIT_CONFIG_PARAMETERS") {
+        parse_config_from_env_var_value(&s)
+    } else {
+        HashMap::new()
+    }
+}
+
+lazy_static! {
+    static ref GIT_CONFIG_PARAMETERS_REGEX: Regex =
+        Regex::new(r"'(delta\.[a-z-]+)=([^']+)'").unwrap();
+}
+
+fn parse_config_from_env_var_value(s: &str) -> HashMap<String, String> {
+    GIT_CONFIG_PARAMETERS_REGEX
+        .captures_iter(s)
+        .map(|captures| (captures[1].to_string(), captures[2].to_string()))
+        .collect()
+}
+
+pub trait GitConfigGet {
+    fn git_config_get(key: &str, git_config: &GitConfig) -> Option<Self>
+    where
+        Self: Sized;
+}
+
+impl GitConfigGet for String {
+    fn git_config_get(key: &str, git_config: &GitConfig) -> Option<Self> {
+        match git_config.config_from_env_var.get(key) {
+            Some(val) => Some(val.to_string()),
+            None => git_config.config.get_string(key).ok(),
+        }
+    }
+}
+
+impl GitConfigGet for Option<String> {
+    fn git_config_get(key: &str, git_config: &GitConfig) -> Option<Self> {
+        match git_config.config_from_env_var.get(key) {
+            Some(val) => Some(Some(val.to_string())),
+            None => match git_config.config.get_string(key) {
+                Ok(val) => Some(Some(val)),
+                _ => None,
+            },
+        }
+    }
+}
+
+impl GitConfigGet for bool {
+    fn git_config_get(key: &str, git_config: &GitConfig) -> Option<Self> {
+        match git_config.config_from_env_var.get(key).map(|s| s.as_str()) {
+            Some("true") => Some(true),
+            Some("false") => Some(false),
+            _ => git_config.config.get_bool(key).ok(),
+        }
+    }
+}
+
+impl GitConfigGet for usize {
+    fn git_config_get(key: &str, git_config: &GitConfig) -> Option<Self> {
+        if let Some(s) = git_config.config_from_env_var.get(key) {
+            if let Ok(n) = s.parse::<usize>() {
+                return Some(n);
+            }
+        }
+        match git_config.config.get_i64(key) {
+            Ok(value) => Some(value as usize),
+            _ => None,
+        }
+    }
+}
+
+impl GitConfigGet for f64 {
+    fn git_config_get(key: &str, git_config: &GitConfig) -> Option<Self> {
+        if let Some(s) = git_config.config_from_env_var.get(key) {
+            if let Ok(n) = s.parse::<f64>() {
+                return Some(n);
+            }
+        }
+        match git_config.config.get_string(key) {
+            Ok(value) => value.parse::<f64>().ok(),
+            _ => None,
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+
+    use super::parse_config_from_env_var_value;
+
+    #[test]
+    fn test_parse_config_from_env_var_value() {
+        // To generate test cases, use git -c ... with
+        // [core]
+        //     pager = env | grep GIT_CONFIG_PARAMETERS
+
+        let config = parse_config_from_env_var_value("'user.name=xxx'");
+        assert!(config.is_empty());
+
+        let config = parse_config_from_env_var_value("'delta.plus-style=green'");
+        assert_eq!(config["delta.plus-style"], "green");
+
+        let config = parse_config_from_env_var_value(
+            r##"'user.name=xxx' 'delta.hunk-header-line-number-style=red "#067a00"'"##,
+        );
+        assert_eq!(
+            config["delta.hunk-header-line-number-style"],
+            r##"red "#067a00""##
+        );
+
+        let config =
+            parse_config_from_env_var_value(r##"'user.name=xxx' 'delta.side-by-side=false'"##);
+        assert_eq!(config["delta.side-by-side"], "false");
+
+        let config = parse_config_from_env_var_value(
+            r##"'delta.plus-style=green' 'delta.side-by-side=false' 'delta.hunk-header-line-number-style=red "#067a00"'"##,
+        );
+        assert_eq!(config["delta.plus-style"], "green");
+        assert_eq!(config["delta.side-by-side"], "false");
+        assert_eq!(
+            config["delta.hunk-header-line-number-style"],
+            r##"red "#067a00""##
+        );
+    }
+}
diff --git a/src/main.rs b/src/main.rs
index cad56b9..5757fba 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -17,7 +17,6 @@ mod env;
 mod features;
 mod format;
 mod git_config;
-mod git_config_entry;
 mod hunk_header;
 mod options;
 mod paint;
diff --git a/src/options/get.rs b/src/options/get.rs
index e29b8cd..a36987c 100644
--- a/src/options/get.rs
+++ b/src/options/get.rs
@@ -109,3 +109,170 @@ impl GetOptionValue for String {}
 impl GetOptionValue for bool {}
 impl GetOptionValue for f64 {}
 impl GetOptionValue for usize {}
+
+#[cfg(test)]
+pub mod tests {
+    use std::env;
+    use std::fs::remove_file;
+
+    use crate::tests::integration_test_utils::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";
+
+        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),
+        );
+        assert_eq!(opt.plus_style, "green");
+
+        remove_file(git_config_path).unwrap();
+
+        // ----------------------------------------------------------------------------------------
+        // 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),
+        );
+        assert_eq!(opt.minus_style, r##"magenta italic ol "#aabbcc""##,);
+
+        remove_file(git_config_path).unwrap();
+
+        // ----------------------------------------------------------------------------------------
+        // 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),
+        );
+        assert_eq!(opt.plus_style, "green");
+
+        remove_file(git_config_path).unwrap();
+
+        // ----------------------------------------------------------------------------------------
+        // 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),
+        );
+        assert_eq!(opt.side_by_side, false);
+
+        remove_file(git_config_path).unwrap();
+
+        // ----------------------------------------------------------------------------------------
+        // 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),
+        );
+        assert_eq!(opt.max_line_length, 2);
+
+        remove_file(git_config_path).unwrap();
+
+        // ----------------------------------------------------------------------------------------
+        // 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),
+        );
+        assert_eq!(opt.max_line_distance, 0.7);
+
+        remove_file(git_config_path).unwrap();
+    }
+}
diff --git a/src/options/rewrite.rs b/src/options/rewrite.rs
index 1259775..1c4759e 100644
--- a/src/options/rewrite.rs
+++ b/src/options/rewrite.rs
@@ -109,7 +109,7 @@ fn rewrite_options_to_implement_deprecated_hunk_style_option(opt: &mut cli::Opt)
         }
         match opt.deprecated_hunk_style.as_deref().map(str::to_lowercase) {
             Some(attr) if attr == "plain" => opt.hunk_header_decoration_style = "".to_string(),
-            Some(attr) if attr == "" => {}
+            Some(attr) if attr.is_empty() => {}
             Some(attr) => opt.hunk_header_decoration_style = attr,
             None => {}
         }
diff --git a/src/options/set.rs b/src/options/set.rs
index eb74a31..354eeea 100644
--- a/src/options/set.rs
+++ b/src/options/set.rs
@@ -13,8 +13,7 @@ use crate::config;
 use crate::env;
 use crate::errors::*;
 use crate::features;
-use crate::git_config;
-use crate::git_config_entry::{self, GitConfigEntry};
+use crate::git_config::{GitConfig, GitConfigEntry, GitRemoteRepo};
 use crate::options::option_value::{OptionValue, ProvenancedOptionValue};
 use crate::options::theme;
 
@@ -64,7 +63,7 @@ macro_rules! set_options {
 
 pub fn set_options(
     opt: &mut cli::Opt,
-    git_config: &mut Option<git_config::GitConfig>,
+    git_config: &mut Option<GitConfig>,
     arg_matches: &clap::ArgMatches,
     assets: HighlightingAssets,
 ) {
@@ -204,7 +203,7 @@ pub fn set_options(
 #[allow(non_snake_case)]
 fn set__light__dark__syntax_theme__options(
     opt: &mut cli::Opt,
-    git_config: &mut Option<git_config::GitConfig>,
+    git_config: &mut Option<GitConfig>,
     arg_matches: &clap::ArgMatches,
     option_names: &HashMap<&str, &str>,
 ) {
@@ -291,7 +290,7 @@ fn set__light__dark__syntax_theme__options(
 fn gather_features(
     opt: &cli::Opt,
     builtin_features: &HashMap<String, features::BuiltinFeature>,
-    git_config: &Option<git_config::GitConfig>,
+    git_config: &Option<GitConfig>,
 ) -> Vec<String> {
     let mut features = VecDeque::new();
 
@@ -372,7 +371,7 @@ fn gather_features_recursively(
     features: &mut VecDeque<String>,
     builtin_features: &HashMap<String, features::BuiltinFeature>,
     opt: &cli::Opt,
-    git_config: &git_config::GitConfig,
+    git_config: &GitConfig,
 ) {
     if builtin_features.contains_key(feature) {
         gather_builtin_features_recursively(feature, features, builtin_features, opt);
@@ -408,7 +407,7 @@ fn gather_builtin_features_from_flags_in_gitconfig(
     features: &mut VecDeque<String>,
     builtin_features: &HashMap<String, features::BuiltinFeature>,
     opt: &cli::Opt,
-    git_config: &git_config::GitConfig,
+    git_config: &GitConfig,
 ) {
     for child_feature in builtin_features.keys() {
         if let Some(value) =
@@ -510,7 +509,7 @@ fn parse_paging_mode(paging_mode_string: &str) -> PagingMode {
 
 fn set_widths(
     opt: &mut cli::Opt,
-    git_config: &mut Option<git_config::GitConfig>,
+    git_config: &mut Option<GitConfig>,
     arg_matches: &clap::ArgMatches,
     option_names: &HashMap<&str, &str>,
 ) {
@@ -571,7 +570,7 @@ fn is_truecolor_terminal() -> bool {
         .unwrap_or(false)
 }
 
-fn set_git_config_entries(opt: &mut cli::Opt, git_config: &mut git_config::GitConfig) {
+fn set_git_config_entries(opt: &mut cli::Opt, git_config: &mut GitConfig) {
     // Styles
     for key in &["color.diff.old", "color.diff.new"] {
         if let Some(style_string) = git_config.get::<String>(key) {
@@ -583,7 +582,7 @@ fn set_git_config_entries(opt: &mut cli::Opt, git_config: &mut git_config::GitCo
     // Strings
     for key in &["remote.origin.url"] {
         if let Some(string) = git_config.get::<String>(key) {
-            if let Ok(repo) = git_config_entry::GitRemoteRepo::from_str(&string) {
+            if let Ok(repo) = GitRemoteRepo::from_str(&string) {
                 opt.git_config_entries
                     .insert(key.to_string(), GitConfigEntry::GitRemote(repo));
             }
diff --git a/src/style.rs b/src/style.rs
index 350023c..32f2f71 100644
--- a/src/style.rs
+++ b/src/style.rs
@@ -166,17 +166,17 @@ fn ansi_term_color_equality(a: Option<ansi_term::Color>, b: Option<ansi_term::Co
 }
 
 fn ansi_term_16_color_equality(a: ansi_term::Color, b: ansi_term::Color) -> bool {
-    match (a, b) {
-        (ansi_term::Color::Fixed(0), ansi_term::Color::Black) => true,
-        (ansi_term::Color::Fixed(1), ansi_term::Color::Red) => true,
-        (ansi_term::Color::Fixed(2), ansi_term::Color::Green) => true,
-        (ansi_term::Color::Fixed(3), ansi_term::Color::Yellow) => true,
-        (ansi_term::Color::Fixed(4), ansi_term::Color::Blue) => true,
-        (ansi_term::Color::Fixed(5), ansi_term::Color::Purple) => true,
-        (ansi_term::Color::Fixed(6), ansi_term::Color::Cyan) => true,
-        (ansi_term::Color::Fixed(7), ansi_term::Color::White) => true,
-        _ => false,
-    }
+    matches!(
+        (a, b),
+        (ansi_term::Color::Fixed(0), ansi_term::Color::Black)
+            | (ansi_term::Color::Fixed(1), ansi_term::Color::Red)
+            | (ansi_term::Color::Fixed(2), ansi_term::Color::Green)
+            | (ansi_term::Color::Fixed(3), ansi_term::Color::Yellow)
+            | (ansi_term::Color::Fixed(4), ansi_term::Color::Blue)
+            | (ansi_term::Color::Fixed(5), ansi_term::Color::Purple)
+            | (ansi_term::Color::Fixed(6), ansi_term::Color::Cyan)
+            | (ansi_term::Color::Fixed(7), ansi_term::Color::White)
+    )
 }
 
 lazy_static! {
diff --git a/themes.gitconfig b/themes.gitconfig
index 40e675b..c295a8c 100644
--- a/themes.gitconfig
+++ b/themes.gitconfig
@@ -23,50 +23,50 @@
 
 [delta "woolly-mammoth"]
     # author: https://github.com/Kr1ss-XD
-	dark							= true
-	syntax-theme					= Vibrant Sunburst
-	zero-style						= syntax
-	minus-style						= syntax                 "#400000"
-	minus-emph-style				= syntax     bold        "#780000"
-	plus-style						= syntax                 "#004000"
-	plus-emph-style					= syntax     bold        "#007800"
-	whitespace-error-style			= "#280050"  reverse
-	commit-style					= 232        bold italic 130
-	commit-decoration-style			= 232                    130   box
-	file-style						= 232        bold        184
-	file-decoration-style			= "#606018"                    overline
-	hunk-header-style				= syntax     bold italic 237
-	hunk-header-decoration-style	=                              none
-	line-numbers					= true
-	line-numbers-zero-style			= "#545474" italic
-	line-numbers-left-format		= "{nm:>1}┊"
-	line-numbers-right-format		= "{np:>1}┊"
-	line-numbers-left-style			= red
-	line-numbers-right-style		= green
-	line-numbers-minus-style		= red       italic black
-	line-numbers-plus-style			= green     italic black
-	file-added-label				= [+]
-	file-copied-label				= [C]
-	file-modified-label				= [M]
-	file-removed-label				= [-]
-	file-renamed-label				= [R]
+    dark = true
+    syntax-theme = Vibrant Sunburst
+    zero-style = syntax
+    minus-style = syntax "#400000"
+    minus-emph-style = syntax bold "#780000"
+    plus-style = syntax "#004000"
+    plus-emph-style = syntax bold "#007800"
+    whitespace-error-style = "#280050" reverse
+    commit-style = 232 bold italic 130
+    commit-decoration-style = 232 130 box
+    file-style = 232 bold 184
+    file-decoration-style = "#606018" overline
+    hunk-header-style = syntax bold italic 237
+    hunk-header-decoration-style = none
+    line-numbers = true
+    line-numbers-zero-style = "#545474" italic
+    line-numbers-left-format = "{nm:>1}┊"
+    line-numbers-right-format = "{np:>1}┊"
+    line-numbers-left-style = red
+    line-numbers-right-style = green
+    line-numbers-minus-style = red italic black
+    line-numbers-plus-style = green italic black
+    file-added-label = [+]
+    file-copied-label = [C]
+    file-modified-label = [M]
+    file-removed-label = [-]
+    file-renamed-label = [R]
 
 [delta "villsau"]
-	# author: https://github.com/torarnv
-	syntax-theme = OneHalfDark
-	line-numbers = false
-	hunk-header-style = file line-number syntax
-	hunk-header-line-number-style = dim magenta
-	hunk-header-file-style = magenta
-	hunk-header-decoration-style = omit
-	file-style = omit
-	zero-style = dim syntax
-	minus-style = bold red
-	minus-non-emph-style = dim red
-	minus-emph-style = bold red 52
-	minus-empty-line-marker-style = normal "#3f0001"
-	plus-style = bold green
-	plus-non-emph-style = dim green
-	plus-emph-style = bold green 22
-	plus-empty-line-marker-style = normal "#002800"
-	whitespace-error-style = reverse red
+    # author: https://github.com/torarnv
+    syntax-theme = OneHalfDark
+    line-numbers = false
+    hunk-header-style = file line-number syntax
+    hunk-header-line-number-style = dim magenta
+    hunk-header-file-style = magenta
+    hunk-header-decoration-style = omit
+    file-style = omit
+    zero-style = dim syntax
+    minus-style = bold red
+    minus-non-emph-style = dim red
+    minus-emph-style = bold red 52
+    minus-empty-line-marker-style = normal "#3f0001"
+    plus-style = bold green
+    plus-non-emph-style = dim green
+    plus-emph-style = bold green 22
+    plus-empty-line-marker-style = normal "#002800"
+    whitespace-error-style = reverse red


Test patch:
diff --git a/src/tests/integration_test_utils.rs b/src/tests/integration_test_utils.rs
index 37ae057..8eb3674 100644
--- a/src/tests/integration_test_utils.rs
+++ b/src/tests/integration_test_utils.rs
@@ -17,12 +17,29 @@ pub mod integration_test_utils {
         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, false)
+    }
+
+    pub fn make_options_from_args_and_git_config_honoring_env_var(
+        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)
+    }
+
+    fn _make_options_from_args_and_git_config(
+        args: &[&str],
+        git_config_contents: Option<&[u8]>,
+        git_config_path: Option<&str>,
+        honor_env_var: bool,
     ) -> cli::Opt {
         let mut args: Vec<&str> = itertools::chain(&["/dev/null", "/dev/null"], args)
             .map(|s| *s)
             .collect();
         let mut git_config = match (git_config_contents, git_config_path) {
-            (Some(contents), Some(path)) => Some(make_git_config(contents, path)),
+            (Some(contents), Some(path)) => Some(make_git_config(contents, path, honor_env_var)),
             _ => {
                 args.push("--no-gitconfig");
                 None
@@ -52,11 +69,11 @@ pub mod integration_test_utils {
         config::Config::from(make_options_from_args(args))
     }
 
-    fn make_git_config(contents: &[u8], path: &str) -> GitConfig {
+    fn make_git_config(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)
+        GitConfig::from_path(&path, honor_env_var)
     }
 
     pub fn get_line_of_code_from_delta(