| 51 | |
| 52 | impl Spinner { |
| 53 | pub fn new(components: Vec<SpinnerComponent>) -> Self { |
| 54 | let (sender, recv) = channel::<Option<String>>(); |
| 55 | |
| 56 | stdout().execute(crossterm::cursor::Hide).ok(); |
| 57 | |
| 58 | let join = thread::spawn(move || { |
| 59 | 'outer: loop { |
| 60 | let mut stdout = stdout(); |
| 61 | for frame in FRAMES.iter() { |
| 62 | let (do_stop, stop_symbol) = match recv.try_recv() { |
| 63 | Ok(stop_symbol) => (true, stop_symbol), |
| 64 | Err(TryRecvError::Disconnected) => (true, None), |
| 65 | Err(TryRecvError::Empty) => (false, None), |
| 66 | }; |
| 67 | |
| 68 | let frame = stop_symbol.unwrap_or_else(|| (*frame).to_string()); |
| 69 | |
| 70 | let line = components.iter().fold(String::new(), |mut acc, elem| { |
| 71 | acc.push_str(match elem { |
| 72 | SpinnerComponent::Text(t) => t, |
| 73 | SpinnerComponent::Spinner => &frame, |
| 74 | }); |
| 75 | acc |
| 76 | }); |
| 77 | |
| 78 | print!("\r{line}"); |
| 79 | |
| 80 | stdout.flush().unwrap(); |
| 81 | |
| 82 | if do_stop { |
| 83 | stdout.execute(crossterm::cursor::Show).ok(); |
| 84 | break 'outer; |
| 85 | } |
| 86 | |
| 87 | thread::sleep(INTERVAL); |
| 88 | } |
| 89 | } |
| 90 | }); |
| 91 | |
| 92 | Self { |
| 93 | sender, |
| 94 | join: Some(join), |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | fn stop_inner(&mut self, stop_symbol: Option<String>) { |
| 99 | self.sender.send(stop_symbol).expect("Could not stop spinner thread."); |