colours.rs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. pub enum Colour {
  2. // These are the standard numeric sequences.
  3. // See http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
  4. Black = 30, Red = 31, Green = 32, Yellow = 33, Blue = 34, Purple = 35, Cyan = 36, White = 37,
  5. }
  6. // There are only three different styles: plain (no formatting), only
  7. // a foreground colour, and a catch-all for anything more complicated
  8. // than that. It's technically possible to write other cases such as
  9. // "bold foreground", but probably isn't worth writing all the code.
  10. pub enum Style {
  11. Plain,
  12. Foreground(Colour),
  13. Style(StyleStruct),
  14. }
  15. // Having a struct inside an enum is currently unfinished in Rust, but
  16. // should be put in there when that feature is complete.
  17. pub struct StyleStruct {
  18. foreground: Colour,
  19. background: Option<Colour>,
  20. bold: bool,
  21. underline: bool,
  22. }
  23. impl Style {
  24. pub fn paint(&self, input: &str) -> String {
  25. match *self {
  26. Plain => input.to_string(),
  27. Foreground(c) => c.paint(input),
  28. Style(s) => match s {
  29. StyleStruct { foreground, background, bold, underline } => {
  30. let bg = match background {
  31. Some(c) => format!("{};", c as int + 10),
  32. None => "".to_string()
  33. };
  34. let bo = if bold { "1;" } else { "" };
  35. let un = if underline { "4;" } else { "" };
  36. let painted = format!("\x1B[{}{}{}{}m{}\x1B[0m", bo, un, bg, foreground as int, input.to_string());
  37. return painted.to_string();
  38. }
  39. }
  40. }
  41. }
  42. }
  43. impl Style {
  44. pub fn bold(&self) -> Style {
  45. match *self {
  46. Plain => Style(StyleStruct { foreground: White, background: None, bold: true, underline: false }),
  47. Foreground(c) => Style(StyleStruct { foreground: c, background: None, bold: true, underline: false }),
  48. Style(st) => Style(StyleStruct { foreground: st.foreground, background: st.background, bold: true, underline: false }),
  49. }
  50. }
  51. pub fn underline(&self) -> Style {
  52. match *self {
  53. Plain => Style(StyleStruct { foreground: White, background: None, bold: false, underline: true }),
  54. Foreground(c) => Style(StyleStruct { foreground: c, background: None, bold: false, underline: true }),
  55. Style(st) => Style(StyleStruct { foreground: st.foreground, background: st.background, bold: false, underline: true }),
  56. }
  57. }
  58. pub fn on(&self, background: Colour) -> Style {
  59. match *self {
  60. Plain => Style(StyleStruct { foreground: White, background: Some(background), bold: false, underline: false }),
  61. Foreground(c) => Style(StyleStruct { foreground: c, background: Some(background), bold: false, underline: false }),
  62. Style(st) => Style(StyleStruct { foreground: st.foreground, background: Some(background), bold: false, underline: false }),
  63. }
  64. }
  65. }
  66. impl Colour {
  67. // This is a short-cut so you don't have to use Blue.normal() just
  68. // to turn Blue into a Style.
  69. pub fn paint(&self, input: &str) -> String {
  70. let re = format!("\x1B[{}m{}\x1B[0m", *self as int, input);
  71. return re.to_string();
  72. }
  73. pub fn underline(&self) -> Style {
  74. Style(StyleStruct { foreground: *self, background: None, bold: false, underline: true })
  75. }
  76. pub fn bold(&self) -> Style {
  77. Style(StyleStruct { foreground: *self, background: None, bold: true, underline: false })
  78. }
  79. pub fn normal(&self) -> Style {
  80. Style(StyleStruct { foreground: *self, background: None, bold: false, underline: false })
  81. }
  82. pub fn on(&self, background: Colour) -> Style {
  83. Style(StyleStruct { foreground: *self, background: Some(background), bold: false, underline: false })
  84. }
  85. }
  86. pub fn strip_formatting(input: &String) -> String {
  87. let re = regex!("\x1B\\[.+?m");
  88. re.replace_all(input.as_slice(), "").to_string()
  89. }