Better UI, needs two keys to close :(
This commit is contained in:
parent
2d9b9dbf9a
commit
de6607eb25
4 changed files with 106 additions and 21 deletions
19
Cargo.lock
generated
19
Cargo.lock
generated
|
|
@ -103,6 +103,7 @@ checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"crossterm_winapi",
|
"crossterm_winapi",
|
||||||
|
"futures-core",
|
||||||
"libc",
|
"libc",
|
||||||
"mio",
|
"mio",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
|
|
@ -151,6 +152,12 @@ dependencies = [
|
||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-core"
|
||||||
|
version = "0.3.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fwd"
|
name = "fwd"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
@ -161,6 +168,7 @@ dependencies = [
|
||||||
"procfs",
|
"procfs",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-stream",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -515,6 +523,17 @@ dependencies = [
|
||||||
"syn",
|
"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]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,10 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
|
crossterm = { version = "0.25", features = ["event-stream"] }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
crossterm = "0.25"
|
tokio-stream = "0.1"
|
||||||
|
|
||||||
[target.'cfg(target_os="linux")'.dependencies]
|
[target.'cfg(target_os="linux")'.dependencies]
|
||||||
procfs = "0.14.1"
|
procfs = "0.14.1"
|
||||||
|
|
|
||||||
|
|
@ -359,7 +359,7 @@ async fn client_main<Reader: AsyncRead + Unpin, Writer: AsyncWrite + Unpin>(
|
||||||
if let Err(e) = refresher.send(Message::Refresh).await {
|
if let Err(e) = refresher.send(Message::Refresh).await {
|
||||||
break Err::<(), _>(e);
|
break Err::<(), _>(e);
|
||||||
}
|
}
|
||||||
sleep(Duration::from_millis(100)).await;
|
sleep(Duration::from_millis(500)).await;
|
||||||
}
|
}
|
||||||
}, if !done_writing => {
|
}, if !done_writing => {
|
||||||
if let Err(e) = result {
|
if let Err(e) = result {
|
||||||
|
|
|
||||||
103
src/ui.rs
103
src/ui.rs
|
|
@ -2,33 +2,98 @@ use crate::message::PortDesc;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
cursor::MoveTo,
|
cursor::MoveTo,
|
||||||
execute,
|
event::{Event, EventStream, KeyCode, KeyEvent},
|
||||||
|
execute, queue,
|
||||||
|
style::Stylize,
|
||||||
terminal::{
|
terminal::{
|
||||||
Clear, ClearType, DisableLineWrap, EnableLineWrap, EnterAlternateScreen,
|
disable_raw_mode, enable_raw_mode, size, Clear, ClearType, DisableLineWrap, EnableLineWrap,
|
||||||
LeaveAlternateScreen,
|
EnterAlternateScreen, LeaveAlternateScreen,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use std::io::stdout;
|
use std::io::{stdout, Write};
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
|
use tokio_stream::StreamExt;
|
||||||
|
|
||||||
pub async fn run_ui(port_receiver: &mut mpsc::Receiver<Vec<PortDesc>>) -> Result<()> {
|
pub async fn run_ui(port_receiver: &mut mpsc::Receiver<Vec<PortDesc>>) -> Result<()> {
|
||||||
let mut stdout = stdout();
|
enable_raw_mode()?;
|
||||||
execute!(stdout, EnterAlternateScreen, DisableLineWrap)?;
|
let result = run_ui_core(port_receiver).await;
|
||||||
while let Some(mut ports) = port_receiver.recv().await {
|
execute!(stdout(), EnableLineWrap, LeaveAlternateScreen)?;
|
||||||
ports.sort_by(|a, b| a.port.partial_cmp(&b.port).unwrap());
|
disable_raw_mode()?;
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
execute!(stdout, Clear(ClearType::All), MoveTo(0, 0))?;
|
async fn run_ui_core(port_receiver: &mut mpsc::Receiver<Vec<PortDesc>>) -> Result<()> {
|
||||||
println!("Port Url Description");
|
let mut stdout = stdout();
|
||||||
println!("----- ------------------------ -----------");
|
|
||||||
for port in ports {
|
execute!(stdout, EnterAlternateScreen, DisableLineWrap)?;
|
||||||
println!(
|
let mut events = EventStream::new();
|
||||||
"{:5} {:24} {}",
|
|
||||||
port.port,
|
let mut ports = None;
|
||||||
format!("http://locahost:{}/", port.port),
|
loop {
|
||||||
port.desc
|
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:<url_width$} {description:<description_width$}\r\n",
|
||||||
|
port = "port",
|
||||||
|
url = "url",
|
||||||
|
description = "description"
|
||||||
|
)
|
||||||
|
.negative()
|
||||||
|
);
|
||||||
|
if let Some(ports) = &mut ports {
|
||||||
|
ports.sort_by(|a, b| a.port.partial_cmp(&b.port).unwrap());
|
||||||
|
for port in ports {
|
||||||
|
print!(
|
||||||
|
" {:port_width$} {:url_width$} {:description_width$}\r\n",
|
||||||
|
port.port,
|
||||||
|
format!("http://locahost:{}/", port.port),
|
||||||
|
port.desc
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
queue!(stdout, MoveTo(0, rows - 1))?;
|
||||||
|
print!(
|
||||||
|
"{}",
|
||||||
|
format!("{:columns$}", " Press ESC or q to quit").negative()
|
||||||
|
);
|
||||||
|
stdout.flush()?;
|
||||||
}
|
}
|
||||||
execute!(stdout, EnableLineWrap, LeaveAlternateScreen)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue