theme.rs 8.5 KB

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