From f6a6f75603d32eeb12e87a5982fc2aab668564bc Mon Sep 17 00:00:00 2001 From: Remigiusz Micielski Date: Thu, 31 Oct 2024 14:02:46 +0100 Subject: [PATCH] refactor: move Tui to intuitils --- Cargo.lock | 8 ++- Cargo.toml | 2 +- rm-main/src/tui/app.rs | 23 +++---- rm-main/src/tui/mod.rs | 1 - rm-main/src/tui/terminal.rs | 117 ------------------------------------ 5 files changed, 19 insertions(+), 132 deletions(-) delete mode 100644 rm-main/src/tui/terminal.rs diff --git a/Cargo.lock b/Cargo.lock index b7cedaa..dce0767 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -938,14 +938,18 @@ dependencies = [ [[package]] name = "intuitils" -version = "0.0.3" +version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f619d42c7cc56f9a2d773a1570a07118105113bc8467460dc95d5f828d7b3c" +checksum = "c01810c86170f0bc2dab8dbeea9958e73e5aa90d9dd9881a954a29deeb36af22" dependencies = [ "anyhow", "crossterm", + "futures", + "ratatui", "serde", "thiserror", + "tokio", + "tokio-util", "toml", "xdg", ] diff --git a/Cargo.toml b/Cargo.toml index 111398b..50a8b32 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ license = "GPL-3.0-or-later" rm-config = { version = "0.5", path = "rm-config" } rm-shared = { version = "0.5", path = "rm-shared" } -intuitils = "0.0.3" +intuitils = "0.0.4" magnetease = "0.3" anyhow = "1" diff --git a/rm-main/src/tui/app.rs b/rm-main/src/tui/app.rs index b6ae1d0..344384a 100644 --- a/rm-main/src/tui/app.rs +++ b/rm-main/src/tui/app.rs @@ -5,6 +5,7 @@ use crate::{ tui::components::Component, }; +use intuitils::Terminal; use rm_config::CONFIG; use rm_shared::action::{Action, UpdateAction}; @@ -13,7 +14,7 @@ use crossterm::event::{Event, KeyCode, KeyModifiers}; use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; use transmission_rpc::{types::SessionGet, TransClient}; -use super::{components::CurrentTab, main_window::MainWindow, terminal::Tui}; +use super::{components::CurrentTab, main_window::MainWindow}; #[derive(Clone)] pub struct Ctx { @@ -96,22 +97,22 @@ impl App { } pub async fn run(&mut self) -> Result<()> { - let mut tui = Tui::new()?; + let mut terminal = Terminal::new()?; - tui.enter()?; + terminal.init()?; - self.render(&mut tui)?; + self.render(&mut terminal)?; - self.main_loop(&mut tui).await?; + self.main_loop(&mut terminal).await?; - tui.exit()?; + terminal.exit()?; Ok(()) } - async fn main_loop(&mut self, tui: &mut Tui) -> Result<()> { + async fn main_loop(&mut self, terminal: &mut Terminal) -> Result<()> { let mut interval = tokio::time::interval(tokio::time::Duration::from_millis(250)); loop { - let tui_event = tui.next(); + let tui_event = terminal.next(); let action = self.action_rx.recv(); let update_action = self.update_rx.recv(); let tick_action = interval.tick(); @@ -130,7 +131,7 @@ impl App { action = action => { if let Some(action) = action { if action.is_render() { - self.render(tui)?; + self.render(terminal)?; } else { self.handle_user_action(action).await } @@ -144,8 +145,8 @@ impl App { } } - fn render(&mut self, tui: &mut Tui) -> Result<()> { - tui.terminal.draw(|f| { + fn render(&mut self, terminal: &mut Terminal) -> Result<()> { + terminal.draw(|f| { self.main_window.render(f, f.area()); })?; Ok(()) diff --git a/rm-main/src/tui/mod.rs b/rm-main/src/tui/mod.rs index f10aad6..41d40f3 100644 --- a/rm-main/src/tui/mod.rs +++ b/rm-main/src/tui/mod.rs @@ -3,4 +3,3 @@ mod components; mod global_popups; pub mod main_window; mod tabs; -pub mod terminal; diff --git a/rm-main/src/tui/terminal.rs b/rm-main/src/tui/terminal.rs deleted file mode 100644 index e4da25c..0000000 --- a/rm-main/src/tui/terminal.rs +++ /dev/null @@ -1,117 +0,0 @@ -use std::{io, time::Duration}; - -use anyhow::Result; -use crossterm::{ - cursor, - event::{DisableMouseCapture, EnableMouseCapture, Event, KeyEventKind}, - terminal::{EnterAlternateScreen, LeaveAlternateScreen}, -}; -use futures::{FutureExt, StreamExt}; -use ratatui::{backend::CrosstermBackend as Backend, Terminal}; -use tokio::{ - sync::mpsc::{self, UnboundedReceiver, UnboundedSender}, - task::JoinHandle, -}; -use tokio_util::sync::CancellationToken; - -pub struct Tui { - pub terminal: Terminal>, - pub task: JoinHandle>, - pub cancellation_token: CancellationToken, - pub event_rx: UnboundedReceiver, - pub event_tx: UnboundedSender, -} - -impl Tui { - pub(crate) fn new() -> Result { - let terminal = Terminal::new(Backend::new(std::io::stdout()))?; - let (event_tx, event_rx) = mpsc::unbounded_channel(); - let cancellation_token = CancellationToken::new(); - let task = tokio::spawn(async { Ok(()) }); - Ok(Self { - terminal, - task, - cancellation_token, - event_rx, - event_tx, - }) - } - - pub(crate) fn enter(&mut self) -> Result<()> { - crossterm::terminal::enable_raw_mode()?; - crossterm::execute!( - std::io::stdout(), - EnterAlternateScreen, - cursor::Hide, - EnableMouseCapture - )?; - self.start()?; - Ok(()) - } - - pub fn start(&mut self) -> Result<()> { - self.cancellation_token = CancellationToken::new(); - let cancellation_token = self.cancellation_token.clone(); - let event_tx = self.event_tx.clone(); - - self.task = tokio::spawn(async move { - let mut reader = crossterm::event::EventStream::new(); - loop { - let crossterm_event = reader.next().fuse(); - tokio::select! { - _ = cancellation_token.cancelled() => break, - event = crossterm_event => Self::handle_crossterm_event(event, &event_tx)?, - } - } - Ok(()) - }); - Ok(()) - } - - fn handle_crossterm_event( - event: Option>, - event_tx: &UnboundedSender, - ) -> Result<()> { - match event { - Some(Ok(Event::Key(key))) => { - if key.kind == KeyEventKind::Press { - event_tx.send(Event::Key(key)).unwrap(); - } - } - Some(Ok(event)) => event_tx.send(event).unwrap(), - Some(Err(e)) => Err(e)?, - _ => (), - } - Ok(()) - } - - pub(crate) fn exit(&mut self) -> Result<()> { - self.cancellation_token.cancel(); - let mut counter = 0; - while !self.task.is_finished() { - std::thread::sleep(Duration::from_millis(1)); - counter += 1; - if counter > 50 { - self.task.abort(); - } - if counter > 100 { - break; - } - } - if crossterm::terminal::is_raw_mode_enabled()? { - self.terminal.flush()?; - crossterm::execute!( - std::io::stdout(), - LeaveAlternateScreen, - cursor::Show, - DisableMouseCapture - )?; - crossterm::terminal::disable_raw_mode()?; - } - Ok(()) - } - - pub async fn next(&mut self) -> Option { - self.event_rx.recv().await - } -}