From deca53e83489987117e4173d4ce90b4c4681859f Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Fri, 26 Feb 2021 00:26:37 -0600 Subject: [PATCH] Switch up ui::Drawable write command and run UI in separate thread --- Cargo.lock | 259 ++++++++++++++++++++++++++++++++++++--- Cargo.toml | 2 +- imap/src/client/inner.rs | 2 +- imap/src/command/mod.rs | 2 +- src/main.rs | 30 ++++- src/ui/drawable.rs | 14 ++- src/ui/mod.rs | 13 +- src/ui/table.rs | 23 ++-- src/ui/tabs.rs | 27 +++- 9 files changed, 332 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 67683ab..5a9a6bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,6 +71,26 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "async-trait" version = "0.1.42" @@ -253,6 +273,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" +[[package]] +name = "cache-padded" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" + [[package]] name = "cast5" version = "0.8.0" @@ -345,6 +371,15 @@ dependencies = [ "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]] name = "constant_time_eq" version = "0.1.5" @@ -473,13 +508,14 @@ dependencies = [ ] [[package]] -name = "dbus" -version = "0.9.2" +name = "derivative" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f597e08dfa79b593f23bbfc7840b23b2c5aa2e3a98d8e68b67b5b9ff800dc0db" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "libc", - "libdbus-sys", + "proc-macro2", + "quote 1.0.9", + "syn 1.0.60", ] [[package]] @@ -570,12 +606,42 @@ dependencies = [ "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]] name = "fake-simd" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +[[package]] +name = "fastrand" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca5faf057445ce5c9d4329e382b2ce7ca38550ef3b73a5348362d5f24e0c7fe3" +dependencies = [ + "instant", +] + [[package]] name = "fern" version = "0.6.0" @@ -674,6 +740,21 @@ version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "futures-macro" version = "0.3.13" @@ -870,15 +951,6 @@ version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "libm" version = "0.2.1" @@ -980,6 +1052,29 @@ dependencies = [ "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]] name = "nom" version = "4.2.3" @@ -996,9 +1091,12 @@ version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95a3a5dd7b4b415b112ce0fae1988f3e6dee90a96918bf3950b5f2289b19a04b" dependencies = [ - "dbus", "mac-notification-sys", + "serde", "winrt-notification", + "zbus", + "zvariant", + "zvariant_derive", ] [[package]] @@ -1200,6 +1298,12 @@ dependencies = [ name = "panorama-smtp" version = "0.1.0" +[[package]] +name = "parking" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" + [[package]] name = "parking_lot" version = "0.11.1" @@ -1361,10 +1465,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] -name = "pkg-config" -version = "0.3.19" +name = "polling" +version = "2.0.2" 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]] name = "ppv-lite86" @@ -1372,6 +1483,15 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "proc-macro-error" version = "0.4.12" @@ -1653,6 +1773,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "scoped-tls" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" + [[package]] name = "scopeguard" version = "1.1.0" @@ -1712,6 +1838,17 @@ dependencies = [ "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]] name = "sha-1" version = "0.8.2" @@ -2131,6 +2268,12 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "vec-arena" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eafc1b9b2dfc6f5529177b62cf806484db55b32dc7c9658a118e11bbeb33061d" + [[package]] name = "vec_map" version = "0.8.2" @@ -2149,6 +2292,18 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -2244,6 +2399,15 @@ dependencies = [ "webpki", ] +[[package]] +name = "wepoll-sys" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcb14dea929042224824779fbc82d9fab8d2e6d3cbc0ac404de8edf489e77ff" +dependencies = [ + "cc", +] + [[package]] name = "winapi" version = "0.3.9" @@ -2314,6 +2478,41 @@ dependencies = [ "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]] name = "zeroize" version = "1.2.0" @@ -2334,3 +2533,27 @@ dependencies = [ "syn 1.0.60", "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", +] diff --git a/Cargo.toml b/Cargo.toml index 8b86b4d..2921577 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ format-bytes = "0.2.0" futures = "0.3.13" inotify = { version = "0.9.2", features = ["stream"] } 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" pgp = "0.7.1" pin-project = "1.0.5" diff --git a/imap/src/client/inner.rs b/imap/src/client/inner.rs index 946751b..30a9d9c 100644 --- a/imap/src/client/inner.rs +++ b/imap/src/client/inner.rs @@ -148,7 +148,7 @@ where 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(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 let mut results = q.write(); results.pop_front(); diff --git a/imap/src/command/mod.rs b/imap/src/command/mod.rs index c9c7b4b..cc99bcc 100644 --- a/imap/src/command/mod.rs +++ b/imap/src/command/mod.rs @@ -1,7 +1,7 @@ use std::fmt; /// Commands, without the tag part. -#[derive(Clone)] +#[derive(Clone, Debug)] pub enum Command { Capability, Starttls, diff --git a/src/main.rs b/src/main.rs index 1b93c41..4bc6a89 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,13 +2,18 @@ extern crate log; use std::path::{Path, PathBuf}; +use std::thread; use anyhow::Result; use fern::colors::{Color, ColoredLevelConfig}; use futures::future::TryFutureExt; use panorama::{config::spawn_config_watcher_system, mail, report_err, ui}; use structopt::StructOpt; -use tokio::{runtime::Runtime, sync::mpsc}; +use tokio::{ + runtime::{Builder as RuntimeBuilder, Runtime}, + sync::mpsc, + task::LocalSet, +}; use xdg::BaseDirectories; #[derive(Debug, StructOpt)] @@ -58,8 +63,7 @@ async fn run(opt: Opt) -> Result<()> { }); if !opt.headless { - let stdout = std::io::stdout(); - tokio::spawn(ui::run_ui(stdout, exit_tx).unwrap_or_else(report_err)); + run_ui(exit_tx); } exit_rx.recv().await; @@ -71,6 +75,26 @@ async fn run(opt: Opt) -> Result<()> { // 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>) -> Result<()> { let now = chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"); let colors = ColoredLevelConfig::new() diff --git a/src/ui/drawable.rs b/src/ui/drawable.rs index 94f3bf1..14cad8a 100644 --- a/src/ui/drawable.rs +++ b/src/ui/drawable.rs @@ -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); +} diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 87531a9..616c056 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -5,7 +5,7 @@ mod table; mod tabs; use std::fmt::Debug; -use std::io::Write; +use std::io::{Stdout, Write}; use std::time::Duration; use anyhow::Result; @@ -20,25 +20,30 @@ use tokio::time; use crate::ExitSender; +use self::drawable::Drawable; use self::table::Table; +use self::tabs::Tabs; 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 #[derive(Copy, Clone)] pub struct Rect(u16, u16, u16, u16); /// 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)?; terminal::enable_raw_mode()?; + let mut tabs = Tabs::new(); + let mut table = Table::default(); table.push_row(vec!["ur mom Lol!".to_owned()]); table.push_row(vec!["hek".to_owned()]); - let dirty = false; - loop { queue!( w, diff --git a/src/ui/table.rs b/src/ui/table.rs index fce71a8..8d769c0 100644 --- a/src/ui/table.rs +++ b/src/ui/table.rs @@ -7,7 +7,7 @@ use crossterm::{ style::{self, Color}, }; -use super::Rect; +use super::{Drawable, Rect, Screen}; #[derive(Default)] pub struct Table { @@ -36,10 +36,16 @@ impl Table { } } - pub fn draw(&self, w: &mut W, rect: Rect) -> Result<()> - where - W: Write, - { + pub fn push_row(&mut self, row: Vec) { + self.rows.push(row); + 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() { let mut columns = Vec::new(); for row in self.rows.iter() { @@ -102,10 +108,7 @@ impl Table { Ok(()) } - pub fn push_row(&mut self, row: Vec) { - self.rows.push(row); - if self.selected_row.is_none() { - self.selected_row = Some(0); - } + fn invalidate(&mut self) { + // TODO: do something } } diff --git a/src/ui/tabs.rs b/src/ui/tabs.rs index aaf1bee..4decd9b 100644 --- a/src/ui/tabs.rs +++ b/src/ui/tabs.rs @@ -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>, +} + +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(), + } + } +}