1 use std::error; 2 3 use rand::{distributions::Uniform, prelude::Distribution, rngs::ThreadRng}; 4 use ratatui::widgets::ListState; 5 6 /// Application result type. 7 pub type AppResult<T> = std::result::Result<T, Box<dyn error::Error>>; 8 9 /// Application. 10 #[derive(Debug)] 11 pub struct App<'a> { 12 /// APP的标题 13 pub title: &'a str, 14 /// Is the application running? 15 pub running: bool, 16 17 pub enhanced_graphics: bool, 18 19 /// counter 20 pub counter: u8, 21 22 pub tabs: TabsState<'a>, 23 24 pub memory_log_sparkline: Signal<RandomSignal>, 25 26 logs: Vec<String>, 27 pub stateful_logs: StatefulList<(&'a str, &'a str)>, 28 29 backend_log_receiver: Option<std::sync::mpsc::Receiver<String>>, 30 } 31 32 impl<'a> App<'a> { 33 /// Constructs a new instance of [`App`]. 34 pub fn new(title: &'a str) -> Self { 35 let mut rand_signal = RandomSignal::new(0, 100); 36 let sparkline_points = rand_signal.by_ref().take(300).collect(); 37 let sparkline = Signal { 38 source: rand_signal, 39 points: sparkline_points, 40 tick_rate: 1, 41 }; 42 43 Self { 44 title, 45 running: true, 46 enhanced_graphics: true, 47 counter: 0, 48 tabs: TabsState::new(vec!["Tab0", "Tab1", "Tab2"]), 49 memory_log_sparkline: sparkline, 50 logs: Vec::new(), 51 stateful_logs: StatefulList::with_items(vec![]), 52 backend_log_receiver: None, 53 } 54 } 55 56 pub fn set_backend_log_receiver(&mut self, receiver: std::sync::mpsc::Receiver<String>) { 57 self.backend_log_receiver = Some(receiver); 58 } 59 60 /// Handles the tick event of the terminal. 61 pub fn tick(&mut self) { 62 self.memory_log_sparkline.on_tick(); 63 self.handle_logs_on_tick(); 64 } 65 66 /// 当到达tick时,处理日志 67 fn handle_logs_on_tick(&mut self) { 68 let logs_to_push = self 69 .backend_log_receiver 70 .as_ref() 71 .map(|rv| rv.try_iter().collect::<Vec<String>>()); 72 73 if let Some(logs) = logs_to_push { 74 for log in logs { 75 self.push_log(log); 76 } 77 } 78 } 79 80 /// Set running to false to quit the application. 81 pub fn quit(&mut self) { 82 self.running = false; 83 } 84 85 pub fn increment_counter(&mut self) { 86 if let Some(res) = self.counter.checked_add(1) { 87 self.counter = res; 88 } 89 } 90 91 pub fn decrement_counter(&mut self) { 92 if let Some(res) = self.counter.checked_sub(1) { 93 self.counter = res; 94 } 95 } 96 97 pub fn push_log(&mut self, log: String) { 98 self.logs.push(log); 99 } 100 101 pub fn logs(&self) -> &Vec<String> { 102 &self.logs 103 } 104 } 105 106 #[derive(Debug)] 107 pub struct TabsState<'a> { 108 pub titles: Vec<&'a str>, 109 pub index: usize, 110 } 111 112 impl<'a> TabsState<'a> { 113 pub fn new(titles: Vec<&'a str>) -> TabsState { 114 TabsState { titles, index: 0 } 115 } 116 pub fn next(&mut self) { 117 self.index = (self.index + 1) % self.titles.len(); 118 } 119 120 pub fn previous(&mut self) { 121 if self.index > 0 { 122 self.index -= 1; 123 } else { 124 self.index = self.titles.len() - 1; 125 } 126 } 127 } 128 129 #[derive(Clone, Debug)] 130 pub struct Signal<S: Iterator> { 131 source: S, 132 pub points: Vec<S::Item>, 133 tick_rate: usize, 134 } 135 136 impl<S> Signal<S> 137 where 138 S: Iterator, 139 { 140 fn on_tick(&mut self) { 141 for _ in 0..self.tick_rate { 142 self.points.remove(0); 143 } 144 self.points 145 .extend(self.source.by_ref().take(self.tick_rate)); 146 } 147 } 148 149 #[derive(Clone, Debug)] 150 pub struct RandomSignal { 151 distribution: Uniform<u64>, 152 rng: ThreadRng, 153 } 154 155 impl RandomSignal { 156 pub fn new(lower: u64, upper: u64) -> RandomSignal { 157 RandomSignal { 158 distribution: Uniform::new(lower, upper), 159 rng: rand::thread_rng(), 160 } 161 } 162 } 163 164 impl Iterator for RandomSignal { 165 type Item = u64; 166 fn next(&mut self) -> Option<u64> { 167 Some(self.distribution.sample(&mut self.rng)) 168 } 169 } 170 171 #[derive(Debug)] 172 pub struct StatefulList<T> { 173 pub state: ListState, 174 pub items: Vec<T>, 175 } 176 177 impl<T> StatefulList<T> { 178 pub fn with_items(items: Vec<T>) -> StatefulList<T> { 179 StatefulList { 180 state: ListState::default(), 181 items, 182 } 183 } 184 185 pub fn next(&mut self) { 186 let i = match self.state.selected() { 187 Some(i) => { 188 if i >= self.items.len() - 1 { 189 0 190 } else { 191 i + 1 192 } 193 } 194 None => 0, 195 }; 196 self.state.select(Some(i)); 197 } 198 199 pub fn previous(&mut self) { 200 let i = match self.state.selected() { 201 Some(i) => { 202 if i == 0 { 203 self.items.len() - 1 204 } else { 205 i - 1 206 } 207 } 208 None => 0, 209 }; 210 self.state.select(Some(i)); 211 } 212 } 213