1 use crate::options::{flags, vars, Vars, OptionsError}; 2 use crate::options::parser::MatchedFlags; 3 use crate::theme::{Options, UseColours, ColourScale, Definitions}; 4 5 6 impl Options { 7 pub fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> { 8 let use_colours = UseColours::deduce(matches)?; 9 let colour_scale = ColourScale::deduce(matches)?; 10 11 let definitions = if use_colours == UseColours::Never { 12 Definitions::default() 13 } 14 else { 15 Definitions::deduce(vars) 16 }; 17 18 Ok(Self { use_colours, colour_scale, definitions }) 19 } 20 } 21 22 23 impl UseColours { 24 fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> { 25 let word = match matches.get_where(|f| f.matches(&flags::COLOR) || f.matches(&flags::COLOUR))? { 26 Some(w) => w, 27 None => return Ok(Self::Automatic), 28 }; 29 30 if word == "always" { 31 Ok(Self::Always) 32 } 33 else if word == "auto" || word == "automatic" { 34 Ok(Self::Automatic) 35 } 36 else if word == "never" { 37 Ok(Self::Never) 38 } 39 else { 40 Err(OptionsError::BadArgument(&flags::COLOR, word.into())) 41 } 42 } 43 } is_valid_apev2_key(key)44 45 46 impl ColourScale { 47 fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> { 48 if matches.has_where(|f| f.matches(&flags::COLOR_SCALE) || f.matches(&flags::COLOUR_SCALE))?.is_some() { 49 Ok(Self::Gradient) 50 } 51 else { 52 Ok(Self::Fixed) 53 } 54 } 55 } 56 57 58 impl Definitions { 59 fn deduce<V: Vars>(vars: &V) -> Self { 60 let ls = vars.get(vars::LS_COLORS) .map(|e| e.to_string_lossy().to_string()); 61 let exa = vars.get(vars::EXA_COLORS).map(|e| e.to_string_lossy().to_string()); 62 Self { ls, exa } 63 } 64 } 65 66 67 #[cfg(test)] 68 mod terminal_test { 69 use super::*; 70 use std::ffi::OsString; 71 use crate::options::flags; 72 use crate::options::parser::{Flag, Arg}; 73 74 use crate::options::test::parse_for_test; 75 use crate::options::test::Strictnesses::*; 76 77 static TEST_ARGS: &[&Arg] = &[ &flags::COLOR, &flags::COLOUR, 78 &flags::COLOR_SCALE, &flags::COLOUR_SCALE, ]; 79 80 macro_rules! test { 81 ($name:ident: $type:ident <- $inputs:expr; $stricts:expr => $result:expr) => { 82 #[test] 83 fn $name() { 84 for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf)) { 85 assert_eq!(result, $result); 86 } 87 } 88 }; 89 90 ($name:ident: $type:ident <- $inputs:expr; $stricts:expr => err $result:expr) => { 91 #[test] 92 fn $name() { 93 for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf)) { 94 assert_eq!(result.unwrap_err(), $result); 95 } 96 } 97 }; 98 } 99 100 struct MockVars { 101 ls: &'static str, 102 exa: &'static str, 103 } 104 105 // Test impl that just returns the value it has. 106 impl Vars for MockVars { 107 fn get(&self, name: &'static str) -> Option<OsString> { 108 if name == vars::LS_COLORS && ! self.ls.is_empty() { 109 Some(OsString::from(self.ls.clone())) 110 } 111 else if name == vars::EXA_COLORS && ! self.exa.is_empty() { 112 Some(OsString::from(self.exa.clone())) 113 } 114 else { 115 None 116 } 117 } 118 } 119 120 121 122 // Default 123 test!(empty: UseColours <- []; Both => Ok(UseColours::Automatic)); 124 125 // --colour 126 test!(u_always: UseColours <- ["--colour=always"]; Both => Ok(UseColours::Always)); 127 test!(u_auto: UseColours <- ["--colour", "auto"]; Both => Ok(UseColours::Automatic)); 128 test!(u_never: UseColours <- ["--colour=never"]; Both => Ok(UseColours::Never)); 129 130 // --color 131 test!(no_u_always: UseColours <- ["--color", "always"]; Both => Ok(UseColours::Always)); 132 test!(no_u_auto: UseColours <- ["--color=auto"]; Both => Ok(UseColours::Automatic)); 133 test!(no_u_never: UseColours <- ["--color", "never"]; Both => Ok(UseColours::Never)); 134 135 // Errors 136 test!(no_u_error: UseColours <- ["--color=upstream"]; Both => err OptionsError::BadArgument(&flags::COLOR, OsString::from("upstream"))); // the error is for --color 137 test!(u_error: UseColours <- ["--colour=lovers"]; Both => err OptionsError::BadArgument(&flags::COLOR, OsString::from("lovers"))); // and so is this one! 138 139 // Overriding 140 test!(overridden_1: UseColours <- ["--colour=auto", "--colour=never"]; Last => Ok(UseColours::Never)); 141 test!(overridden_2: UseColours <- ["--color=auto", "--colour=never"]; Last => Ok(UseColours::Never)); 142 test!(overridden_3: UseColours <- ["--colour=auto", "--color=never"]; Last => Ok(UseColours::Never)); 143 test!(overridden_4: UseColours <- ["--color=auto", "--color=never"]; Last => Ok(UseColours::Never)); 144 145 test!(overridden_5: UseColours <- ["--colour=auto", "--colour=never"]; Complain => err OptionsError::Duplicate(Flag::Long("colour"), Flag::Long("colour"))); 146 test!(overridden_6: UseColours <- ["--color=auto", "--colour=never"]; Complain => err OptionsError::Duplicate(Flag::Long("color"), Flag::Long("colour"))); 147 test!(overridden_7: UseColours <- ["--colour=auto", "--color=never"]; Complain => err OptionsError::Duplicate(Flag::Long("colour"), Flag::Long("color"))); 148 test!(overridden_8: UseColours <- ["--color=auto", "--color=never"]; Complain => err OptionsError::Duplicate(Flag::Long("color"), Flag::Long("color"))); 149 150 test!(scale_1: ColourScale <- ["--color-scale", "--colour-scale"]; Last => Ok(ColourScale::Gradient)); 151 test!(scale_2: ColourScale <- ["--color-scale", ]; Last => Ok(ColourScale::Gradient)); 152 test!(scale_3: ColourScale <- [ "--colour-scale"]; Last => Ok(ColourScale::Gradient)); 153 test!(scale_4: ColourScale <- [ ]; Last => Ok(ColourScale::Fixed)); 154 155 test!(scale_5: ColourScale <- ["--color-scale", "--colour-scale"]; Complain => err OptionsError::Duplicate(Flag::Long("color-scale"), Flag::Long("colour-scale"))); 156 test!(scale_6: ColourScale <- ["--color-scale", ]; Complain => Ok(ColourScale::Gradient)); 157 test!(scale_7: ColourScale <- [ "--colour-scale"]; Complain => Ok(ColourScale::Gradient)); 158 test!(scale_8: ColourScale <- [ ]; Complain => Ok(ColourScale::Fixed)); 159 } 160