1
0

lsc.rs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. use std::ops::FnMut;
  2. use ansi_term::{Colour, Style};
  3. use ansi_term::Colour::*;
  4. pub struct LSColors<'var>(pub &'var str);
  5. impl<'var> LSColors<'var> {
  6. pub fn each_pair<C>(&mut self, mut callback: C) where C: FnMut(Pair<'var>) -> () {
  7. for next in self.0.split(":") {
  8. let bits = next.split("=")
  9. .take(3)
  10. .collect::<Vec<_>>();
  11. if bits.len() == 2 && !bits[0].is_empty() && !bits[1].is_empty() {
  12. callback(Pair { key: bits[0], value: bits[1] });
  13. }
  14. }
  15. }
  16. }
  17. pub struct Pair<'var> {
  18. pub key: &'var str,
  19. pub value: &'var str,
  20. }
  21. use std::iter::Peekable;
  22. fn parse_into_high_colour<'a, I>(iter: &mut Peekable<I>) -> Option<Colour>
  23. where I: Iterator<Item=&'a str> {
  24. match iter.peek() {
  25. Some(&"5") => {
  26. let _5 = iter.next();
  27. if let Some(byte) = iter.next() {
  28. if let Ok(num) = byte.parse() {
  29. return Some(Fixed(num));
  30. }
  31. }
  32. }
  33. _ => {},
  34. }
  35. None
  36. }
  37. impl<'var> Pair<'var> {
  38. pub fn to_style(&self) -> Style {
  39. let mut style = Style::default();
  40. let mut iter = self.value.split(";").peekable();
  41. while let Some(num) = iter.next() {
  42. match num {
  43. // Bold and italic
  44. "1" => style = style.bold(),
  45. "4" => style = style.underline(),
  46. // Foreground colours
  47. "30" => style = style.fg(Black),
  48. "31" => style = style.fg(Red),
  49. "32" => style = style.fg(Green),
  50. "33" => style = style.fg(Yellow),
  51. "34" => style = style.fg(Blue),
  52. "35" => style = style.fg(Purple),
  53. "36" => style = style.fg(Cyan),
  54. "37" => style = style.fg(White),
  55. "38" => if let Some(c) = parse_into_high_colour(&mut iter) { style = style.fg(c) },
  56. // Background colours
  57. "40" => style = style.on(Black),
  58. "41" => style = style.on(Red),
  59. "42" => style = style.on(Green),
  60. "43" => style = style.on(Yellow),
  61. "44" => style = style.on(Blue),
  62. "45" => style = style.on(Purple),
  63. "46" => style = style.on(Cyan),
  64. "47" => style = style.on(White),
  65. "48" => if let Some(c) = parse_into_high_colour(&mut iter) { style = style.on(c) },
  66. _ => {/* ignore the error and do nothing */},
  67. }
  68. }
  69. style
  70. }
  71. }
  72. #[cfg(test)]
  73. mod ansi_test {
  74. use super::*;
  75. use ansi_term::Style;
  76. macro_rules! test {
  77. ($name:ident: $input:expr => $result:expr) => {
  78. #[test]
  79. fn $name() {
  80. assert_eq!(Pair { key: "", value: $input }.to_style(), $result);
  81. }
  82. };
  83. }
  84. // Styles
  85. test!(bold: "1" => Style::default().bold());
  86. test!(under: "4" => Style::default().underline());
  87. test!(both: "1;4" => Style::default().bold().underline());
  88. test!(fg: "31" => Red.normal());
  89. test!(bg: "43" => Style::default().on(Yellow));
  90. test!(bfg: "31;43" => Red.on(Yellow));
  91. test!(all: "43;31;1;4" => Red.on(Yellow).bold().underline());
  92. test!(again: "1;1;1;1;1" => Style::default().bold());
  93. // Failure cases
  94. test!(empty: "" => Style::default());
  95. test!(semis: ";;;;;;" => Style::default());
  96. test!(nines: "99999999" => Style::default());
  97. test!(word: "GREEN" => Style::default());
  98. // Higher colours
  99. test!(hifg: "38;5;149" => Fixed(149).normal());
  100. test!(hibg: "48;5;1" => Style::default().on(Fixed(1)));
  101. test!(hibo: "48;5;1;1" => Style::default().on(Fixed(1)).bold());
  102. test!(hiund: "4;48;5;1" => Style::default().on(Fixed(1)).underline());
  103. test!(fgbg: "38;5;121;48;5;212" => Fixed(121).on(Fixed(212)));
  104. test!(bgfg: "48;5;121;38;5;212" => Fixed(212).on(Fixed(121)));
  105. test!(toohi: "48;5;999" => Style::default());
  106. }
  107. #[cfg(test)]
  108. mod test {
  109. use super::*;
  110. macro_rules! test {
  111. ($name:ident: $input:expr => $result:expr) => {
  112. #[test]
  113. fn $name() {
  114. let mut lscs = Vec::new();
  115. LSColors($input).each_pair(|p| lscs.push( (p.key.clone(), p.to_style()) ));
  116. assert_eq!(lscs, $result.to_vec());
  117. }
  118. };
  119. }
  120. // Bad parses
  121. test!(empty: "" => []);
  122. test!(jibber: "blah" => []);
  123. test!(equals: "=" => []);
  124. test!(starts: "=di" => []);
  125. test!(ends: "id=" => []);
  126. // Foreground colours
  127. test!(green: "cb=32" => [ ("cb", Green.normal()) ]);
  128. test!(red: "di=31" => [ ("di", Red.normal()) ]);
  129. test!(blue: "la=34" => [ ("la", Blue.normal()) ]);
  130. // Background colours
  131. test!(yellow: "do=43" => [ ("do", Style::default().on(Yellow)) ]);
  132. test!(purple: "re=45" => [ ("re", Style::default().on(Purple)) ]);
  133. test!(cyan: "mi=46" => [ ("mi", Style::default().on(Cyan)) ]);
  134. // Bold and underline
  135. test!(bold: "fa=1" => [ ("fa", Style::default().bold()) ]);
  136. test!(under: "so=4" => [ ("so", Style::default().underline()) ]);
  137. test!(both: "la=1;4" => [ ("la", Style::default().bold().underline()) ]);
  138. // More and many
  139. test!(more: "me=43;21;55;34:yu=1;4;1" => [ ("me", Blue.on(Yellow)), ("yu", Style::default().bold().underline()) ]);
  140. test!(many: "red=31:green=32:blue=34" => [ ("red", Red.normal()), ("green", Green.normal()), ("blue", Blue.normal()) ]);
  141. }