From e852f42ac67edd6b7691de922c6b9577274ee384 Mon Sep 17 00:00:00 2001 From: sreedev Date: Mon, 2 Jan 2023 02:24:05 -0500 Subject: [PATCH] ui updates --- Cargo.lock | 73 +++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 ++ src/app/event_handler.rs | 22 ++++++++++++ src/app/events.rs | 4 +++ src/app/mod.rs | 78 ++++++++++++++++++++++++++++++++++++++++ src/app/ui.rs | 21 +++++++++++ src/main.rs | 9 ++--- 7 files changed, 203 insertions(+), 6 deletions(-) create mode 100644 src/app/event_handler.rs create mode 100644 src/app/events.rs create mode 100644 src/app/mod.rs create mode 100644 src/app/ui.rs diff --git a/Cargo.lock b/Cargo.lock index 59f1ff8..874a50a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,6 +58,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +[[package]] +name = "cassowary" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" + [[package]] name = "cc" version = "1.0.78" @@ -192,6 +198,31 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossterm" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" +dependencies = [ + "bitflags", + "crossterm_winapi", + "libc", + "mio", + "parking_lot", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c" +dependencies = [ + "winapi", +] + [[package]] name = "cxx" version = "1.0.85" @@ -244,6 +275,7 @@ dependencies = [ "chrono", "clap", "colored", + "crossterm", "fxhash", "glob", "humansize", @@ -252,6 +284,7 @@ dependencies = [ "sqlite", "thiserror", "tokio", + "tui", ] [[package]] @@ -647,6 +680,27 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" +[[package]] +name = "signal-hook" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + [[package]] name = "signal-hook-registry" version = "1.4.0" @@ -790,12 +844,31 @@ dependencies = [ "syn", ] +[[package]] +name = "tui" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccdd26cbd674007e649a272da4475fb666d3aa0ad0531da7136db6fab0e5bad1" +dependencies = [ + "bitflags", + "cassowary", + "crossterm", + "unicode-segmentation", + "unicode-width", +] + [[package]] name = "unicode-ident" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +[[package]] +name = "unicode-segmentation" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" + [[package]] name = "unicode-width" version = "0.1.10" diff --git a/Cargo.toml b/Cargo.toml index 87cad63..423f007 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ anyhow = "1.0.68" chrono = "0.4.23" clap = { version = "4.0.32", features = ["derive"] } colored = "2.0.0" +crossterm = "0.25.0" fxhash = "0.2.1" glob = "0.3.0" humansize = "2.1.2" @@ -18,3 +19,4 @@ rayon = "1.6.1" sqlite = "0.30.3" thiserror = "1.0.38" tokio = { version = "1.23.0", features = ["full"] } +tui = "0.19.0" diff --git a/src/app/event_handler.rs b/src/app/event_handler.rs new file mode 100644 index 0000000..7caa979 --- /dev/null +++ b/src/app/event_handler.rs @@ -0,0 +1,22 @@ +use crossterm::event::{self, KeyCode, KeyEvent}; +use anyhow::Result; +use super::events; + +pub struct EventHandler; + +impl EventHandler { + pub fn init() -> Result { + match event::read()? { + event::Event::Key(keycode) => Self::handle_keypress(keycode), + _ => Ok(events::Event::Noop), + } + } + + fn handle_keypress(keyevent: KeyEvent) -> Result { + match keyevent.code { + KeyCode::Char('q') => Ok(events::Event::Exit), + _ => Ok(events::Event::Noop) + } + } +} + diff --git a/src/app/events.rs b/src/app/events.rs new file mode 100644 index 0000000..a889cc3 --- /dev/null +++ b/src/app/events.rs @@ -0,0 +1,4 @@ +pub enum Event { + Exit, + Noop +} diff --git a/src/app/mod.rs b/src/app/mod.rs new file mode 100644 index 0000000..04ed962 --- /dev/null +++ b/src/app/mod.rs @@ -0,0 +1,78 @@ +mod event_handler; +mod events; +mod ui; + +use crate::database; +use crate::output; +use crate::params::Params; +use crate::scanner; +use anyhow::{anyhow, Result}; +use std::time::Duration; +use crossterm::{event, execute, terminal}; +use event_handler::EventHandler; +use std::io; +use std::thread; +use tui::{ + backend::CrosstermBackend, + widgets::{Block, Borders, Widget}, + Terminal, +}; +use ui::Ui; + +pub struct App; + +impl App { + pub fn init(app_args: &Params) -> Result<()> { + let connection = database::get_connection(&app_args)?; + let duplicates = scanner::duplicates(&app_args, &connection)?; + let mut term = Self::init_terminal()?; + + Self::init_render_loop(&mut term)?; + Self::cleanup(&mut term)?; + + output::print(duplicates, &app_args); /* TODO: APP TUI INIT FUNCTION */ + Ok(()) + } + + fn cleanup(term: &mut Terminal>) -> Result<()> { + terminal::disable_raw_mode()?; + execute!( + term.backend_mut(), + terminal::LeaveAlternateScreen, + event::DisableMouseCapture + )?; + + term.show_cursor()?; + Ok(()) + } + + fn render_cycle(term: &mut Terminal>) -> Result<()> { + match EventHandler::init()? { + events::Event::Noop => Ui::render_frame(term), + events::Event::Exit => Err(anyhow!("Exit")), + } + } + + fn init_render_loop(term: &mut Terminal>) -> Result<()> { + loop { + match Self::render_cycle(term) { + Ok(_) => continue, + Err(_) => break, + } + } + + Ok(()) + } + + fn init_terminal() -> Result>> { + terminal::enable_raw_mode()?; + let mut stdout = io::stdout(); + execute!( + stdout, + terminal::EnterAlternateScreen, + event::EnableMouseCapture + )?; + let backend = CrosstermBackend::new(stdout); + Ok(Terminal::new(backend)?) + } +} diff --git a/src/app/ui.rs b/src/app/ui.rs new file mode 100644 index 0000000..8326b6c --- /dev/null +++ b/src/app/ui.rs @@ -0,0 +1,21 @@ +use tui::{ + backend::CrosstermBackend, + widgets::{Block, Borders, Widget}, + Terminal, +}; +use anyhow::Result; +use std::io; + +pub struct Ui; + +impl Ui { + pub fn render_frame(term: &mut Terminal>) -> Result<()> { + term.draw(|f| { + let size = f.size(); + let block = Block::default().title("Block").borders(Borders::ALL); + + f.render_widget(block, size); + })?; + Ok(()) + } +} diff --git a/src/main.rs b/src/main.rs index d5193da..7cb8c91 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,16 +2,13 @@ mod params; mod database; mod output; mod scanner; +mod app; use anyhow::Result; use clap::Parser; +use app::App; #[tokio::main] async fn main() -> Result<()> { - let app_args = params::Params::parse(); - let connection = database::get_connection(&app_args)?; - let duplicates = scanner::duplicates(&app_args, &connection)?; - - output::print(duplicates, &app_args); - Ok(()) + App::init(¶ms::Params::parse()) }