85 lines
2.3 KiB
Rust
85 lines
2.3 KiB
Rust
use std::io::stdout;
|
|
use std::io::Write;
|
|
|
|
use anyhow::{bail, Result};
|
|
use crossterm::{
|
|
cursor::{self, MoveTo},
|
|
event::{Event, EventStream, KeyCode, KeyModifiers},
|
|
terminal::{self, disable_raw_mode, enable_raw_mode},
|
|
ExecutableCommand, QueueableCommand,
|
|
};
|
|
use futures::StreamExt;
|
|
use tokio::sync::broadcast::Sender;
|
|
|
|
use crate::message::Message;
|
|
|
|
pub(crate) struct Ui {
|
|
sender: Sender<Message>,
|
|
}
|
|
|
|
impl Ui {
|
|
pub(crate) fn new(sender: Sender<Message>) -> Self {
|
|
Self { sender }
|
|
}
|
|
|
|
pub(crate) async fn main_loop(self) -> Result<()> {
|
|
let mut reader = EventStream::new();
|
|
|
|
loop {
|
|
enable_raw_mode()?;
|
|
stdout().execute(cursor::Hide)?;
|
|
|
|
if let Some(Ok(Event::Key(key_event))) = reader.next().await {
|
|
let should_exit = self.handle_key_event(key_event)?;
|
|
if should_exit {
|
|
return Ok(());
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
fn handle_key_event(&self, key_event: crossterm::event::KeyEvent) -> Result<bool> {
|
|
if Self::is_char_q(key_event) {
|
|
self.prepare_for_program_quit()?;
|
|
return Ok(true);
|
|
};
|
|
if Self::is_ctrl_c(key_event) {
|
|
self.prepare_for_program_quit()?;
|
|
self.sender.send(Message::Quit)?;
|
|
bail!("<Ctrl-C>");
|
|
}
|
|
if Self::is_space(key_event) {
|
|
self.sender.send(Message::TogglePause)?;
|
|
}
|
|
Ok(false)
|
|
}
|
|
|
|
fn prepare_for_program_quit(&self) -> Result<()> {
|
|
self.sender.send(Message::Quit)?;
|
|
disable_raw_mode()?;
|
|
stdout().execute(cursor::Show)?;
|
|
Ok(())
|
|
}
|
|
|
|
fn is_char_q(key_event: crossterm::event::KeyEvent) -> bool {
|
|
key_event.code == KeyCode::Char('q')
|
|
}
|
|
|
|
fn is_space(key_event: crossterm::event::KeyEvent) -> bool {
|
|
key_event.code == KeyCode::Char(' ')
|
|
}
|
|
|
|
fn is_ctrl_c(key_event: crossterm::event::KeyEvent) -> bool {
|
|
key_event.code == KeyCode::Char('c') && key_event.modifiers.contains(KeyModifiers::CONTROL)
|
|
}
|
|
}
|
|
|
|
pub(crate) fn clear_terminal() -> Result<()> {
|
|
let mut stdout = stdout();
|
|
stdout.queue(terminal::Clear(terminal::ClearType::All))?;
|
|
stdout.queue(terminal::Clear(terminal::ClearType::Purge))?;
|
|
stdout.queue(MoveTo(0, 0))?;
|
|
stdout.flush()?;
|
|
Ok(())
|
|
}
|