1use std::{
2 io::{stdin, stdout, BufRead, Write},
3 ops::Neg,
4};
5
6use colored::Colorize;
7
8use crate::{Node, Runtime};
9
10#[allow(missing_docs)]
12pub enum Color {
13 White,
14 Black,
15 Red,
16 Green,
17 Blue,
18 Cyan,
19 Magenta,
20 Yellow,
21}
22
23impl Neg for Color {
24 type Output = Self;
25 fn neg(self) -> Self::Output {
26 use Color::*;
27 match self {
28 White => Black,
29 Black => White,
30 Red => Cyan,
31 Cyan => Red,
32 Green => Magenta,
33 Magenta => Green,
34 Blue => Yellow,
35 Yellow => Blue,
36 }
37 }
38}
39
40pub trait Frontend {
44 fn background_color(&self) -> Color;
46 fn set_background_color(&mut self, color: Color);
48 fn clear(&mut self);
50 fn print_colored<S: ToString>(&mut self, text: S, color: Color);
52 fn newline(&mut self);
54 fn input(&mut self) -> String;
56 fn print<S: ToString>(&mut self, text: S) {
58 self.print_colored(text, -self.background_color());
59 }
60 fn println<S: ToString>(&mut self, text: S) {
62 self.print(text);
63 self.newline();
64 }
65}
66
67pub struct CliFrontend {
69 background_color: colored::Color,
70}
71
72impl CliFrontend {
73 pub fn new() -> Self {
75 Self::default()
76 }
77 pub fn with_bg_color(color: Color) -> Self {
79 let mut clif = Self::new();
80 clif.set_background_color(color);
81 clif
82 }
83}
84
85impl Default for CliFrontend {
86 fn default() -> Self {
87 CliFrontend {
88 background_color: colored::Color::Black,
89 }
90 }
91}
92
93impl Frontend for CliFrontend {
94 fn background_color(&self) -> Color {
95 use Color::*;
96 match self.background_color {
97 colored::Color::Black => Black,
98 colored::Color::White => White,
99 colored::Color::Red => Red,
100 colored::Color::Green => Green,
101 colored::Color::Blue => Blue,
102 colored::Color::Cyan => Cyan,
103 colored::Color::Magenta => Magenta,
104 colored::Color::Yellow => Yellow,
105 _ => Black,
106 }
107 }
108 fn set_background_color(&mut self, color: Color) {
109 use Color::*;
110 self.background_color = match color {
111 White => colored::Color::Black,
112 Black => colored::Color::White,
113 Red => colored::Color::Red,
114 Green => colored::Color::Green,
115 Blue => colored::Color::Blue,
116 Cyan => colored::Color::Cyan,
117 Magenta => colored::Color::Magenta,
118 Yellow => colored::Color::Yellow,
119 };
120 }
121 fn clear(&mut self) {
122 let (_, height) = terminal_size::terminal_size()
123 .unwrap_or_else(|| panic!("{}", "Unable to get terminal size".bright_red()));
124 println!("{}", (0..height.0).map(|_| '\n').collect::<String>());
125 }
126 fn print_colored<S: ToString>(&mut self, text: S, color: Color) {
127 use Color::*;
128 let color = match color {
129 Black => Colorize::black,
130 White => Colorize::white,
131 Red => Colorize::red,
132 Green => Colorize::green,
133 Blue => Colorize::blue,
134 Cyan => Colorize::cyan,
135 Magenta => Colorize::magenta,
136 Yellow => Colorize::yellow,
137 };
138 print!(
139 "{}",
140 color(text.to_string().as_ref()).on_color(self.background_color)
141 );
142 let _ = stdout().flush();
143 }
144 fn newline(&mut self) {
145 println!();
146 }
147 fn input(&mut self) -> String {
148 stdin()
149 .lock()
150 .lines()
151 .next()
152 .and_then(Result::ok)
153 .unwrap_or_else(|| panic!("{}", "Failed to read line".bright_red()))
154 }
155}
156
157impl<'a, N, F> Frontend for Runtime<'a, N, F>
158where
159 N: Node,
160 F: Frontend,
161{
162 fn background_color(&self) -> Color {
163 self.frontend.background_color()
164 }
165 fn set_background_color(&mut self, color: Color) {
166 self.frontend.set_background_color(color)
167 }
168 fn clear(&mut self) {
169 self.frontend.clear()
170 }
171 fn print_colored<S: ToString>(&mut self, text: S, color: Color) {
172 self.frontend.print_colored(text, color)
173 }
174 fn newline(&mut self) {
175 self.frontend.newline()
176 }
177 fn input(&mut self) -> String {
178 self.frontend.input()
179 }
180}