Switch up ui::Drawable write command and run UI in separate thread

This commit is contained in:
Michael Zhang 2021-02-26 00:26:37 -06:00
parent aa796e533e
commit deca53e834
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
9 changed files with 332 additions and 40 deletions

259
Cargo.lock generated
View file

@ -71,6 +71,26 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9"
[[package]]
name = "async-io"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9315f8f07556761c3e48fec2e6b276004acf426e6dc068b2c2251854d65ee0fd"
dependencies = [
"concurrent-queue",
"fastrand",
"futures-lite",
"libc",
"log",
"nb-connect",
"once_cell",
"parking",
"polling",
"vec-arena",
"waker-fn",
"winapi",
]
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.42" version = "0.1.42"
@ -253,6 +273,12 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040"
[[package]]
name = "cache-padded"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba"
[[package]] [[package]]
name = "cast5" name = "cast5"
version = "0.8.0" version = "0.8.0"
@ -345,6 +371,15 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "concurrent-queue"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3"
dependencies = [
"cache-padded",
]
[[package]] [[package]]
name = "constant_time_eq" name = "constant_time_eq"
version = "0.1.5" version = "0.1.5"
@ -473,13 +508,14 @@ dependencies = [
] ]
[[package]] [[package]]
name = "dbus" name = "derivative"
version = "0.9.2" version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f597e08dfa79b593f23bbfc7840b23b2c5aa2e3a98d8e68b67b5b9ff800dc0db" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
dependencies = [ dependencies = [
"libc", "proc-macro2",
"libdbus-sys", "quote 1.0.9",
"syn 1.0.60",
] ]
[[package]] [[package]]
@ -570,12 +606,42 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "enumflags2"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83c8d82922337cd23a15f88b70d8e4ef5f11da38dd7cdb55e84dd5de99695da0"
dependencies = [
"enumflags2_derive",
"serde",
]
[[package]]
name = "enumflags2_derive"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "946ee94e3dbf58fdd324f9ce245c7b238d46a66f00e86a020b71996349e46cce"
dependencies = [
"proc-macro2",
"quote 1.0.9",
"syn 1.0.60",
]
[[package]] [[package]]
name = "fake-simd" name = "fake-simd"
version = "0.1.2" version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]]
name = "fastrand"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca5faf057445ce5c9d4329e382b2ce7ca38550ef3b73a5348362d5f24e0c7fe3"
dependencies = [
"instant",
]
[[package]] [[package]]
name = "fern" name = "fern"
version = "0.6.0" version = "0.6.0"
@ -674,6 +740,21 @@ version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59" checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59"
[[package]]
name = "futures-lite"
version = "1.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4481d0cd0de1d204a4fa55e7d45f07b1d958abcb06714b3446438e2eff695fb"
dependencies = [
"fastrand",
"futures-core",
"futures-io",
"memchr",
"parking",
"pin-project-lite",
"waker-fn",
]
[[package]] [[package]]
name = "futures-macro" name = "futures-macro"
version = "0.3.13" version = "0.3.13"
@ -870,15 +951,6 @@ version = "0.2.86"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c"
[[package]]
name = "libdbus-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc12a3bc971424edbbf7edaf6e5740483444db63aa8e23d3751ff12a30f306f0"
dependencies = [
"pkg-config",
]
[[package]] [[package]]
name = "libm" name = "libm"
version = "0.2.1" version = "0.2.1"
@ -980,6 +1052,29 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "nb-connect"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670361df1bc2399ee1ff50406a0d422587dd3bb0da596e1978fe8e05dabddf4f"
dependencies = [
"libc",
"socket2",
]
[[package]]
name = "nix"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363"
dependencies = [
"bitflags 1.2.1",
"cc",
"cfg-if 0.1.10",
"libc",
"void",
]
[[package]] [[package]]
name = "nom" name = "nom"
version = "4.2.3" version = "4.2.3"
@ -996,9 +1091,12 @@ version = "4.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95a3a5dd7b4b415b112ce0fae1988f3e6dee90a96918bf3950b5f2289b19a04b" checksum = "95a3a5dd7b4b415b112ce0fae1988f3e6dee90a96918bf3950b5f2289b19a04b"
dependencies = [ dependencies = [
"dbus",
"mac-notification-sys", "mac-notification-sys",
"serde",
"winrt-notification", "winrt-notification",
"zbus",
"zvariant",
"zvariant_derive",
] ]
[[package]] [[package]]
@ -1200,6 +1298,12 @@ dependencies = [
name = "panorama-smtp" name = "panorama-smtp"
version = "0.1.0" version = "0.1.0"
[[package]]
name = "parking"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.11.1" version = "0.11.1"
@ -1361,10 +1465,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]] [[package]]
name = "pkg-config" name = "polling"
version = "0.3.19" version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" checksum = "a2a7bc6b2a29e632e45451c941832803a18cce6781db04de8a04696cdca8bde4"
dependencies = [
"cfg-if 0.1.10",
"libc",
"log",
"wepoll-sys",
"winapi",
]
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
@ -1372,6 +1483,15 @@ version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
name = "proc-macro-crate"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
dependencies = [
"toml",
]
[[package]] [[package]]
name = "proc-macro-error" name = "proc-macro-error"
version = "0.4.12" version = "0.4.12"
@ -1653,6 +1773,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "scoped-tls"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.1.0" version = "1.1.0"
@ -1712,6 +1838,17 @@ dependencies = [
"syn 1.0.60", "syn 1.0.60",
] ]
[[package]]
name = "serde_repr"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dc6b7951b17b051f3210b063f12cc17320e2fe30ae05b0fe2a3abb068551c76"
dependencies = [
"proc-macro2",
"quote 1.0.9",
"syn 1.0.60",
]
[[package]] [[package]]
name = "sha-1" name = "sha-1"
version = "0.8.2" version = "0.8.2"
@ -2131,6 +2268,12 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "vec-arena"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eafc1b9b2dfc6f5529177b62cf806484db55b32dc7c9658a118e11bbeb33061d"
[[package]] [[package]]
name = "vec_map" name = "vec_map"
version = "0.8.2" version = "0.8.2"
@ -2149,6 +2292,18 @@ version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]]
name = "waker-fn"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.9.0+wasi-snapshot-preview1" version = "0.9.0+wasi-snapshot-preview1"
@ -2244,6 +2399,15 @@ dependencies = [
"webpki", "webpki",
] ]
[[package]]
name = "wepoll-sys"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fcb14dea929042224824779fbc82d9fab8d2e6d3cbc0ac404de8edf489e77ff"
dependencies = [
"cc",
]
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"
@ -2314,6 +2478,41 @@ dependencies = [
"bitflags 0.9.1", "bitflags 0.9.1",
] ]
[[package]]
name = "zbus"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40b4d4aa39daed4e32aed75f0c37b969184949a0fdfd5f2e1277abfda61f02a8"
dependencies = [
"async-io",
"byteorder",
"derivative",
"enumflags2",
"fastrand",
"futures",
"nb-connect",
"nix",
"once_cell",
"polling",
"scoped-tls",
"serde",
"serde_repr",
"zbus_macros",
"zvariant",
]
[[package]]
name = "zbus_macros"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87cc141cda72384bef359badf1808e391d3968f9299e8f3c3cbb78dafa1e0930"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote 1.0.9",
"syn 1.0.60",
]
[[package]] [[package]]
name = "zeroize" name = "zeroize"
version = "1.2.0" version = "1.2.0"
@ -2334,3 +2533,27 @@ dependencies = [
"syn 1.0.60", "syn 1.0.60",
"synstructure", "synstructure",
] ]
[[package]]
name = "zvariant"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fc67d552ac18ccd9e440f062f5b32c46776f96073122a8da2fe0c533833a213"
dependencies = [
"byteorder",
"enumflags2",
"serde",
"zvariant_derive",
]
[[package]]
name = "zvariant_derive"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaee686340b5bff077d52423d8cc4f0f7cb323fe3f31ef676b8a3a2810bc53c5"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote 1.0.9",
"syn 1.0.60",
]

View file

@ -22,7 +22,7 @@ format-bytes = "0.2.0"
futures = "0.3.13" futures = "0.3.13"
inotify = { version = "0.9.2", features = ["stream"] } inotify = { version = "0.9.2", features = ["stream"] }
log = "0.4.14" log = "0.4.14"
notify-rust = "4.2.2" notify-rust = { version = "4.2.2", default-features = false, features = ["z"] }
parking_lot = "0.11.1" parking_lot = "0.11.1"
pgp = "0.7.1" pgp = "0.7.1"
pin-project = "1.0.5" pin-project = "1.0.5"

View file

@ -148,7 +148,7 @@ where
let q = self.results.clone(); let q = self.results.clone();
// let end = Box::new(end_rx.map_err(|err| Error::from).map(move |resp| resp)); // let end = Box::new(end_rx.map_err(|err| Error::from).map(move |resp| resp));
let end = Box::new(end_rx.map_err(Error::from).map(move | resp | { let end = Box::new(end_rx.map_err(Error::from).map(move |resp| {
// pop the first entry from the list // pop the first entry from the list
let mut results = q.write(); let mut results = q.write();
results.pop_front(); results.pop_front();

View file

@ -1,7 +1,7 @@
use std::fmt; use std::fmt;
/// Commands, without the tag part. /// Commands, without the tag part.
#[derive(Clone)] #[derive(Clone, Debug)]
pub enum Command { pub enum Command {
Capability, Capability,
Starttls, Starttls,

View file

@ -2,13 +2,18 @@
extern crate log; extern crate log;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::thread;
use anyhow::Result; use anyhow::Result;
use fern::colors::{Color, ColoredLevelConfig}; use fern::colors::{Color, ColoredLevelConfig};
use futures::future::TryFutureExt; use futures::future::TryFutureExt;
use panorama::{config::spawn_config_watcher_system, mail, report_err, ui}; use panorama::{config::spawn_config_watcher_system, mail, report_err, ui};
use structopt::StructOpt; use structopt::StructOpt;
use tokio::{runtime::Runtime, sync::mpsc}; use tokio::{
runtime::{Builder as RuntimeBuilder, Runtime},
sync::mpsc,
task::LocalSet,
};
use xdg::BaseDirectories; use xdg::BaseDirectories;
#[derive(Debug, StructOpt)] #[derive(Debug, StructOpt)]
@ -58,8 +63,7 @@ async fn run(opt: Opt) -> Result<()> {
}); });
if !opt.headless { if !opt.headless {
let stdout = std::io::stdout(); run_ui(exit_tx);
tokio::spawn(ui::run_ui(stdout, exit_tx).unwrap_or_else(report_err));
} }
exit_rx.recv().await; exit_rx.recv().await;
@ -71,6 +75,26 @@ async fn run(opt: Opt) -> Result<()> {
// Ok(()) // Ok(())
} }
// Spawns the entire UI in a different thread, since it must be thread-local
fn run_ui(exit_tx: mpsc::Sender<()>) {
let stdout = std::io::stdout();
let rt = RuntimeBuilder::new_current_thread()
.enable_all()
.build()
.unwrap();
thread::spawn(move || {
let localset = LocalSet::new();
localset.spawn_local(async {
ui::run_ui(stdout, exit_tx).unwrap_or_else(report_err).await;
});
rt.block_on(localset);
});
}
fn setup_logger(log_file: Option<impl AsRef<Path>>) -> Result<()> { fn setup_logger(log_file: Option<impl AsRef<Path>>) -> Result<()> {
let now = chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"); let now = chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]");
let colors = ColoredLevelConfig::new() let colors = ColoredLevelConfig::new()

View file

@ -1 +1,13 @@
pub trait Drawable {} use std::io::Write;
use anyhow::Result;
use super::{Rect, Screen};
pub trait Drawable {
/// Draws this UI element to the screen
fn draw(&self, w: &mut Screen, rect: Rect) -> Result<()>;
/// Invalidates this UI element, queueing it for redraw
fn invalidate(&mut self);
}

View file

@ -5,7 +5,7 @@ mod table;
mod tabs; mod tabs;
use std::fmt::Debug; use std::fmt::Debug;
use std::io::Write; use std::io::{Stdout, Write};
use std::time::Duration; use std::time::Duration;
use anyhow::Result; use anyhow::Result;
@ -20,25 +20,30 @@ use tokio::time;
use crate::ExitSender; use crate::ExitSender;
use self::drawable::Drawable;
use self::table::Table; use self::table::Table;
use self::tabs::Tabs;
const FRAME_DURATION: Duration = Duration::from_millis(20); const FRAME_DURATION: Duration = Duration::from_millis(20);
/// Type alias for the screen object we're drawing to
pub type Screen = Stdout;
/// X Y W H /// X Y W H
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct Rect(u16, u16, u16, u16); pub struct Rect(u16, u16, u16, u16);
/// UI entrypoint. /// UI entrypoint.
pub async fn run_ui(mut w: impl Write + Debug, exit: ExitSender) -> Result<()> { pub async fn run_ui(mut w: Stdout, exit: ExitSender) -> Result<()> {
execute!(w, cursor::Hide, terminal::EnterAlternateScreen)?; execute!(w, cursor::Hide, terminal::EnterAlternateScreen)?;
terminal::enable_raw_mode()?; terminal::enable_raw_mode()?;
let mut tabs = Tabs::new();
let mut table = Table::default(); let mut table = Table::default();
table.push_row(vec!["ur mom Lol!".to_owned()]); table.push_row(vec!["ur mom Lol!".to_owned()]);
table.push_row(vec!["hek".to_owned()]); table.push_row(vec!["hek".to_owned()]);
let dirty = false;
loop { loop {
queue!( queue!(
w, w,

View file

@ -7,7 +7,7 @@ use crossterm::{
style::{self, Color}, style::{self, Color},
}; };
use super::Rect; use super::{Drawable, Rect, Screen};
#[derive(Default)] #[derive(Default)]
pub struct Table { pub struct Table {
@ -36,10 +36,16 @@ impl Table {
} }
} }
pub fn draw<W>(&self, w: &mut W, rect: Rect) -> Result<()> pub fn push_row(&mut self, row: Vec<String>) {
where self.rows.push(row);
W: Write, if self.selected_row.is_none() {
{ self.selected_row = Some(0);
}
}
}
impl Drawable for Table {
fn draw(&self, w: &mut Screen, rect: Rect) -> Result<()> {
if !self.rows.is_empty() { if !self.rows.is_empty() {
let mut columns = Vec::new(); let mut columns = Vec::new();
for row in self.rows.iter() { for row in self.rows.iter() {
@ -102,10 +108,7 @@ impl Table {
Ok(()) Ok(())
} }
pub fn push_row(&mut self, row: Vec<String>) { fn invalidate(&mut self) {
self.rows.push(row); // TODO: do something
if self.selected_row.is_none() {
self.selected_row = Some(0);
}
} }
} }

View file

@ -1 +1,26 @@
pub struct Tabs {} use std::collections::HashMap;
use std::io::Write;
use anyhow::Result;
use super::{Drawable, Rect, Screen};
pub struct Tabs {
tabs: HashMap<String, Box<dyn Drawable>>,
}
impl Drawable for Tabs {
fn draw(&self, w: &mut Screen, rect: Rect) -> Result<()> {
Ok(())
}
fn invalidate(&mut self) {}
}
impl Tabs {
pub fn new() -> Self {
Tabs {
tabs: HashMap::new(),
}
}
}