Open urls

This commit is contained in:
John Doty 2022-10-12 17:44:36 -07:00
parent e7946333ad
commit 006eba0dfe
3 changed files with 59 additions and 14 deletions

17
Cargo.lock generated
View file

@ -166,6 +166,7 @@ dependencies = [
"bytes", "bytes",
"crossterm", "crossterm",
"log", "log",
"open",
"procfs", "procfs",
"thiserror", "thiserror",
"tokio", "tokio",
@ -314,6 +315,16 @@ version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
[[package]]
name = "open"
version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4a3100141f1733ea40b53381b0ae3117330735ef22309a190ac57b9576ea716"
dependencies = [
"pathdiff",
"windows-sys",
]
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.12.1" version = "0.12.1"
@ -337,6 +348,12 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "pathdiff"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.9" version = "0.2.9"

View file

@ -9,10 +9,11 @@ edition = "2021"
anyhow = "1.0" anyhow = "1.0"
bytes = "1" bytes = "1"
crossterm = { version = "0.25", features = ["event-stream"] } crossterm = { version = "0.25", features = ["event-stream"] }
log = { version = "0.4", features = ["std"] }
open = "3"
thiserror = "1.0" thiserror = "1.0"
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }
tokio-stream = "0.1" tokio-stream = "0.1"
log = { version = "0.4", features = ["std"] }
[target.'cfg(target_os="linux")'.dependencies] [target.'cfg(target_os="linux")'.dependencies]
procfs = "0.14.1" procfs = "0.14.1"

View file

@ -11,6 +11,7 @@ use crossterm::{
}, },
}; };
use log::{Level, Metadata, Record}; use log::{Level, Metadata, Record};
use open;
use std::collections::vec_deque::VecDeque; use std::collections::vec_deque::VecDeque;
use std::io::{stdout, Write}; use std::io::{stdout, Write};
use tokio::sync::mpsc; use tokio::sync::mpsc;
@ -62,20 +63,42 @@ async fn run_ui_core(
execute!(stdout, EnterAlternateScreen, DisableLineWrap)?; execute!(stdout, EnterAlternateScreen, DisableLineWrap)?;
let mut events = EventStream::new(); let mut events = EventStream::new();
let mut selection = 0;
let mut show_logs = false; let mut show_logs = false;
let mut lines: VecDeque<String> = VecDeque::with_capacity(1024); let mut lines: VecDeque<String> = VecDeque::with_capacity(1024);
let mut ports = None; let mut ports: Option<Vec<PortDesc>> = None;
loop { loop {
tokio::select! { tokio::select! {
ev = events.next() => { ev = events.next() => {
match ev { match ev {
Some(Ok(Event::Key(ev))) => { Some(Ok(Event::Key(ev))) => {
match ev { match ev {
KeyEvent {code:KeyCode::Esc, ..} => { break; }, KeyEvent {code:KeyCode::Esc, ..}
KeyEvent {code:KeyCode::Char('q'), ..} => { break; }, | KeyEvent {code:KeyCode::Char('q'), ..} => { break; },
KeyEvent {code:KeyCode::Char('l'), ..} => { KeyEvent {code:KeyCode::Char('l'), ..} => {
show_logs = !show_logs; show_logs = !show_logs;
} }
KeyEvent { code:KeyCode::Up, ..}
| KeyEvent { code:KeyCode::Char('j'), ..} => {
if selection > 0 {
selection -= 1;
}
}
KeyEvent { code:KeyCode::Down, ..}
| KeyEvent { code:KeyCode::Char('k'), ..} => {
if let Some(p) = &ports {
if selection != p.len() - 1 {
selection += 1;
}
}
}
KeyEvent { code:KeyCode::Enter, ..} => {
if let Some(p) = &ports {
if selection < p.len() {
_ = open::that(format!("http://127.0.0.1:{}/", p[selection].port));
}
}
}
_ => () _ => ()
} }
}, },
@ -86,7 +109,10 @@ async fn run_ui_core(
} }
pr = port_receiver.recv() => { pr = port_receiver.recv() => {
match pr { match pr {
Some(p) => { ports = Some(p); } Some(mut p) => {
p.sort_by(|a, b| a.port.partial_cmp(&b.port).unwrap());
ports = Some(p);
}
None => break, None => break,
} }
} }
@ -112,28 +138,25 @@ async fn run_ui_core(
let columns: usize = columns.into(); let columns: usize = columns.into();
let padding = 1; let padding = 1;
let port_width = 5; // 5 characters for 16-bit number let port_width = 5; // 5 characters for 16-bit number
let url_width = "http://127.0.0.1:/".len() + port_width;
let description_width = columns - (padding + port_width + padding + url_width + padding); let description_width = columns - (padding + padding + port_width + padding);
print!( print!(
"{}", "{}",
format!( format!(
" {port:>port_width$} {url:<url_width$} {description:<description_width$}\r\n", " {port:>port_width$} {description:<description_width$}\r\n",
port = "port", port = "port",
url = "url",
description = "description" description = "description"
) )
.negative() .negative()
); );
if let Some(ports) = &mut ports { if let Some(ports) = &mut ports {
ports.sort_by(|a, b| a.port.partial_cmp(&b.port).unwrap());
let max_ports: usize = if show_logs { (rows / 2) - 1 } else { rows - 2 }.into(); let max_ports: usize = if show_logs { (rows / 2) - 1 } else { rows - 2 }.into();
for port in ports.into_iter().take(max_ports) { for (index, port) in ports.into_iter().take(max_ports).enumerate() {
print!( print!(
" {:port_width$} {:url_width$} {:description_width$}\r\n", "{} {:port_width$} {:description_width$}\r\n",
if index == selection { "\u{2B46}" } else { " " },
port.port, port.port,
format!("http://127.0.0.1:{}/", port.port),
port.desc port.desc
); );
} }
@ -158,7 +181,11 @@ async fn run_ui_core(
queue!(stdout, MoveTo(0, rows - 1))?; queue!(stdout, MoveTo(0, rows - 1))?;
print!( print!(
"{}", "{}",
format!("{:columns$}", " Press ESC or q to quit | l - toggle log").negative() format!(
"{:columns$}",
" q - quit | l - toggle log | \u{2191}/\u{2193} - select port | <enter> - browse"
)
.negative()
); );
stdout.flush()?; stdout.flush()?;
} }