theme.rs 8.4 KB

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