diff --git a/Cargo.lock b/Cargo.lock index 6997254..d8238b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,6 +103,7 @@ checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" dependencies = [ "bitflags", "crossterm_winapi", + "futures-core", "libc", "mio", "parking_lot", @@ -151,6 +152,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "futures-core" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf" + [[package]] name = "fwd" version = "0.1.0" @@ -161,6 +168,7 @@ dependencies = [ "procfs", "thiserror", "tokio", + "tokio-stream", ] [[package]] @@ -515,6 +523,17 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-stream" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6edf2d6bc038a43d31353570e27270603f4648d18f5ed10c0e179abe43255af" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + [[package]] name = "unicode-ident" version = "1.0.4" diff --git a/Cargo.toml b/Cargo.toml index 33b5a89..5427046 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,9 +8,10 @@ edition = "2021" [dependencies] anyhow = "1.0" bytes = "1" +crossterm = { version = "0.25", features = ["event-stream"] } thiserror = "1.0" tokio = { version = "1", features = ["full"] } -crossterm = "0.25" +tokio-stream = "0.1" [target.'cfg(target_os="linux")'.dependencies] procfs = "0.14.1" diff --git a/src/lib.rs b/src/lib.rs index a3e8676..f6c7d4e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -359,7 +359,7 @@ async fn client_main( if let Err(e) = refresher.send(Message::Refresh).await { break Err::<(), _>(e); } - sleep(Duration::from_millis(100)).await; + sleep(Duration::from_millis(500)).await; } }, if !done_writing => { if let Err(e) = result { diff --git a/src/ui.rs b/src/ui.rs index 198646a..e9bba31 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -2,33 +2,98 @@ use crate::message::PortDesc; use anyhow::Result; use crossterm::{ cursor::MoveTo, - execute, + event::{Event, EventStream, KeyCode, KeyEvent}, + execute, queue, + style::Stylize, terminal::{ - Clear, ClearType, DisableLineWrap, EnableLineWrap, EnterAlternateScreen, - LeaveAlternateScreen, + disable_raw_mode, enable_raw_mode, size, Clear, ClearType, DisableLineWrap, EnableLineWrap, + EnterAlternateScreen, LeaveAlternateScreen, }, }; -use std::io::stdout; +use std::io::{stdout, Write}; use tokio::sync::mpsc; +use tokio_stream::StreamExt; pub async fn run_ui(port_receiver: &mut mpsc::Receiver>) -> Result<()> { - let mut stdout = stdout(); - execute!(stdout, EnterAlternateScreen, DisableLineWrap)?; - while let Some(mut ports) = port_receiver.recv().await { - ports.sort_by(|a, b| a.port.partial_cmp(&b.port).unwrap()); + enable_raw_mode()?; + let result = run_ui_core(port_receiver).await; + execute!(stdout(), EnableLineWrap, LeaveAlternateScreen)?; + disable_raw_mode()?; + result +} - execute!(stdout, Clear(ClearType::All), MoveTo(0, 0))?; - println!("Port Url Description"); - println!("----- ------------------------ -----------"); - for port in ports { - println!( - "{:5} {:24} {}", - port.port, - format!("http://locahost:{}/", port.port), - port.desc - ); +async fn run_ui_core(port_receiver: &mut mpsc::Receiver>) -> Result<()> { + let mut stdout = stdout(); + + execute!(stdout, EnterAlternateScreen, DisableLineWrap)?; + let mut events = EventStream::new(); + + let mut ports = None; + loop { + tokio::select! { + ev = events.next() => { + match ev { + Some(Ok(Event::Key(ev))) => { + match ev { + KeyEvent {code:KeyCode::Esc, ..} => { break; }, + KeyEvent {code:KeyCode::Char('q'), ..} => { break; }, + _ => () + } + }, + Some(Ok(_)) => (), // Don't care about this event... + Some(Err(_)) => (), // Hmmmmmm.....? + None => (), // ....no events? what? + } + } + pr = port_receiver.recv() => { + match pr { + Some(p) => { ports = Some(p); } + None => break, + } + } } + + let (columns, rows) = size()?; + + queue!(stdout, Clear(ClearType::All), MoveTo(0, 0))?; + + // How wide are all the things? + let columns: usize = columns.into(); + let padding = 1; + let port_width = 5; // 5 characters for 16-bit number + let url_width = "http://localhost:/".len() + port_width; + + let description_width = columns - (padding + port_width + padding + url_width + padding); + + print!( + "{}", + format!( + " {port:>port_width$} {url: