From 6d0ea06d7bc0918c5ea51309615963de1c9f0ad3 Mon Sep 17 00:00:00 2001 From: Arijit Basu Date: Fri, 9 Apr 2021 04:09:32 +0530 Subject: [PATCH] Add pwd watcher Also optimize the main thread. --- Cargo.lock | 247 ++++++++++++++++++++++++++++++++++++++---- Cargo.toml | 1 + benches/navigation.rs | 21 ++-- src/app.rs | 19 ++-- src/lib.rs | 1 + src/main.rs | 44 +++++--- src/pwd_watcher.rs | 38 +++++++ 7 files changed, 305 insertions(+), 66 deletions(-) create mode 100644 src/pwd_watcher.rs diff --git a/Cargo.lock b/Cargo.lock index 3991e6b..c3325f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,7 +28,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -126,6 +126,12 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "cfg-if" version = "1.0.0" @@ -143,7 +149,7 @@ dependencies = [ "num-traits", "serde", "time", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -205,7 +211,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "crossbeam-utils", ] @@ -215,7 +221,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "crossbeam-epoch", "crossbeam-utils", ] @@ -226,7 +232,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2584f639eb95fea8c798496315b297cf81b9b58b6d30ab066a75455333cf4b12" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "crossbeam-utils", "lazy_static", "memoffset", @@ -240,7 +246,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" dependencies = [ "autocfg", - "cfg-if", + "cfg-if 1.0.0", "lazy_static", ] @@ -254,10 +260,10 @@ dependencies = [ "crossterm_winapi", "lazy_static", "libc", - "mio", + "mio 0.7.11", "parking_lot", "signal-hook", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -266,7 +272,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2265c3f8e080075d9b6417aa72293fc71662f34b4af2612d8d1b074d29510db" dependencies = [ - "winapi", + "winapi 0.3.9", ] [[package]] @@ -317,7 +323,7 @@ checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" dependencies = [ "libc", "redox_users", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -338,6 +344,53 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +[[package]] +name = "filetime" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall 0.2.5", + "winapi 0.3.9", +] + +[[package]] +name = "fsevent" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6" +dependencies = [ + "bitflags", + "fsevent-sys", +] + +[[package]] +name = "fsevent-sys" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0" +dependencies = [ + "libc", +] + +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +dependencies = [ + "bitflags", + "fuchsia-zircon-sys", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + [[package]] name = "generic-array" version = "0.12.4" @@ -353,7 +406,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] @@ -387,13 +440,42 @@ dependencies = [ "libc", ] +[[package]] +name = "inotify" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f" +dependencies = [ + "bitflags", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + [[package]] name = "instant" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", +] + +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +dependencies = [ + "libc", ] [[package]] @@ -429,12 +511,28 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" version = "0.2.92" @@ -462,7 +560,7 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -502,6 +600,25 @@ dependencies = [ "unicase", ] +[[package]] +name = "mio" +version = "0.6.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +dependencies = [ + "cfg-if 0.1.10", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log", + "miow 0.2.2", + "net2", + "slab", + "winapi 0.2.8", +] + [[package]] name = "mio" version = "0.7.11" @@ -510,9 +627,33 @@ checksum = "cf80d3e903b34e0bd7282b218398aec54e082c840d9baf8339e0080a0c542956" dependencies = [ "libc", "log", - "miow", + "miow 0.3.7", "ntapi", - "winapi", + "winapi 0.3.9", +] + +[[package]] +name = "mio-extras" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" +dependencies = [ + "lazycell", + "log", + "mio 0.6.23", + "slab", +] + +[[package]] +name = "miow" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" +dependencies = [ + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", ] [[package]] @@ -521,7 +662,36 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" dependencies = [ - "winapi", + "winapi 0.3.9", +] + +[[package]] +name = "net2" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "winapi 0.3.9", +] + +[[package]] +name = "notify" +version = "4.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80ae4a7688d1fab81c5bf19c64fc8db920be8d519ce6336ed4e7efe024724dbd" +dependencies = [ + "bitflags", + "filetime", + "fsevent", + "fsevent-sys", + "inotify", + "libc", + "mio 0.6.23", + "mio-extras", + "walkdir", + "winapi 0.3.9", ] [[package]] @@ -530,7 +700,7 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" dependencies = [ - "winapi", + "winapi 0.3.9", ] [[package]] @@ -597,12 +767,12 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "instant", "libc", "redox_syscall 0.2.5", "smallvec", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -913,7 +1083,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e31d442c16f047a671b5a71e2161d6e68814012b7f5379d269ebd915fac2729" dependencies = [ "libc", - "mio", + "mio 0.7.11", "signal-hook-registry", ] @@ -926,6 +1096,12 @@ dependencies = [ "libc", ] +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" + [[package]] name = "smallvec" version = "1.6.1" @@ -972,7 +1148,7 @@ checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -1051,7 +1227,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" dependencies = [ "same-file", - "winapi", + "winapi 0.3.9", "winapi-util", ] @@ -1073,7 +1249,7 @@ version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "wasm-bindgen-macro", ] @@ -1131,6 +1307,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + [[package]] name = "winapi" version = "0.3.9" @@ -1141,6 +1323,12 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -1153,7 +1341,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi", + "winapi 0.3.9", ] [[package]] @@ -1162,6 +1350,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + [[package]] name = "xplr" version = "0.3.9" @@ -1173,6 +1371,7 @@ dependencies = [ "dirs", "handlebars", "mime_guess", + "notify", "serde", "serde_yaml", "termion", diff --git a/Cargo.toml b/Cargo.toml index 4c88e2e..37e402f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ handlebars = "3.5" mime_guess = "2.0.3" anyhow = "1.0" chrono = { version = "0.4", features = ["serde"] } +notify = "4.0.12" [dev-dependencies] criterion = "0.3" diff --git a/benches/navigation.rs b/benches/navigation.rs index eed97f9..4318d55 100644 --- a/benches/navigation.rs +++ b/benches/navigation.rs @@ -10,23 +10,21 @@ fn criterion_benchmark(c: &mut Criterion) { let app = app::App::create("/tmp/xplr_bench".into()) .expect("failed to create app") - .enqueue(app::Task::new( + .handle_task(app::Task::new( 1, app::MsgIn::External(app::ExternalMsg::ChangeDirectory("/tmp/xplr_bench".into())), None, )) - .mutate_or_sleep() .unwrap(); c.bench_function("focus next item", |b| { b.iter(|| { app.clone() - .enqueue(app::Task::new( + .handle_task(app::Task::new( 1, app::MsgIn::External(app::ExternalMsg::FocusNext), None, )) - .mutate_or_sleep() .unwrap() }) }); @@ -34,12 +32,11 @@ fn criterion_benchmark(c: &mut Criterion) { c.bench_function("focus previous item", |b| { b.iter(|| { app.clone() - .enqueue(app::Task::new( + .handle_task(app::Task::new( 1, app::MsgIn::External(app::ExternalMsg::FocusPrevious), None, )) - .mutate_or_sleep() .unwrap() }) }); @@ -47,12 +44,11 @@ fn criterion_benchmark(c: &mut Criterion) { c.bench_function("focus first item", |b| { b.iter(|| { app.clone() - .enqueue(app::Task::new( + .handle_task(app::Task::new( 1, app::MsgIn::External(app::ExternalMsg::FocusFirst), None, )) - .mutate_or_sleep() .unwrap() }) }); @@ -60,12 +56,11 @@ fn criterion_benchmark(c: &mut Criterion) { c.bench_function("focus last item", |b| { b.iter(|| { app.clone() - .enqueue(app::Task::new( + .handle_task(app::Task::new( 1, app::MsgIn::External(app::ExternalMsg::FocusLast), None, )) - .mutate_or_sleep() .unwrap() }) }); @@ -73,19 +68,17 @@ fn criterion_benchmark(c: &mut Criterion) { c.bench_function("leave and enter directory", |b| { b.iter(|| { app.clone() - .enqueue(app::Task::new( + .handle_task(app::Task::new( 1, app::MsgIn::External(app::ExternalMsg::Back), None, )) - .mutate_or_sleep() .unwrap() - .enqueue(app::Task::new( + .handle_task(app::Task::new( 1, app::MsgIn::External(app::ExternalMsg::Enter), None, )) - .mutate_or_sleep() .unwrap() }) }); diff --git a/src/app.rs b/src/app.rs index ad03016..249a4ce 100644 --- a/src/app.rs +++ b/src/app.rs @@ -12,7 +12,6 @@ use std::collections::VecDeque; use std::fs; use std::io; use std::path::PathBuf; -use std::time::Duration; pub const VERSION: &str = "v0.3.9"; // Update Cargo.toml and default.nix pub const TEMPLATE_TABLE_ROW: &str = "TEMPLATE_TABLE_ROW"; @@ -826,15 +825,10 @@ impl App { self } - pub fn mutate_or_sleep(mut self) -> Result { - if let Some(task) = self.tasks.pop() { - match task.msg { - MsgIn::Internal(msg) => self.handle_internal(msg), - MsgIn::External(msg) => self.handle_external(msg, task.key), - } - } else { - std::thread::sleep(Duration::from_millis(5)); - Ok(self) + pub fn handle_task(self, task: Task) -> Result { + match task.msg { + MsgIn::Internal(msg) => self.handle_internal(msg), + MsgIn::External(msg) => self.handle_external(msg, task.key), } } @@ -1430,4 +1424,9 @@ impl App { pub fn version(&self) -> &String { &self.version } + + /// Get a reference to the app's tasks. + pub fn pop_task_out(&mut self) -> Option { + self.tasks.pop() + } } diff --git a/src/lib.rs b/src/lib.rs index 4f03afb..bd6a0d8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,4 +9,5 @@ pub mod event_reader; pub mod explorer; pub mod input; pub mod pipe_reader; +pub mod pwd_watcher; pub mod ui; diff --git a/src/main.rs b/src/main.rs index 9e8772c..1d5cb30 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,11 +17,13 @@ use xplr::auto_refresher; use xplr::event_reader; use xplr::explorer; use xplr::pipe_reader; +use xplr::pwd_watcher; use xplr::ui; fn main() -> Result<()> { let (tx_msg_in, rx_msg_in) = mpsc::channel(); let (tx_event_reader, rx_event_reader) = mpsc::channel(); + let (tx_pwd_watcher, rx_pwd_watcher) = mpsc::channel(); let mut pwd = PathBuf::from(env::args().nth(1).unwrap_or_else(|| ".".into())) .canonicalize() @@ -93,15 +95,25 @@ fn main() -> Result<()> { auto_refresher::start_auto_refreshing(tx_msg_in.clone()); pipe_reader::keep_reading(app.pipe().msg_in.clone(), tx_msg_in.clone()); event_reader::keep_reading(tx_msg_in.clone(), rx_event_reader); + pwd_watcher::keep_watching(app.pwd(), tx_msg_in.clone(), rx_pwd_watcher)?; + + 'outer: for task in rx_msg_in { + let last_app = app.clone(); + + let (new_app, new_result) = match app.handle_task(task) { + Ok(a) => (a, Ok(())), + Err(err) => (last_app.clone(), Err(err)), + }; + + app = new_app; + result = new_result; + + if result.is_err() { + break; + } - let mut last_app = app.clone(); - 'outer: while result.is_ok() { while let Some(msg) = app.pop_msg_out() { match msg { - app::MsgOut::Debug(path) => { - fs::write(&path, serde_yaml::to_string(&app)?)?; - } - app::MsgOut::PrintResultAndQuit => { output = Some(app.result_str()); break 'outer; @@ -113,6 +125,10 @@ fn main() -> Result<()> { break 'outer; } + app::MsgOut::Debug(path) => { + fs::write(&path, serde_yaml::to_string(&app)?)?; + } + app::MsgOut::ClearScreen => { terminal.clear()?; } @@ -129,6 +145,7 @@ fn main() -> Result<()> { app::MsgOut::Refresh => { app = app.refresh_selection()?; if app.pwd() != last_app.pwd() { + tx_pwd_watcher.send(app.pwd().clone())?; explorer::explore( app.explorer_config().clone(), app.pwd().clone(), @@ -162,7 +179,7 @@ fn main() -> Result<()> { if app.result() != last_app.result() { fs::write(&app.pipe().result_out, app.result_str())?; - } + }; } app::MsgOut::Call(cmd) => { @@ -230,20 +247,11 @@ fn main() -> Result<()> { terminal.draw(|f| ui::draw(f, &app, &hb))?; } }; - last_app = app.clone(); } - for task in rx_msg_in.try_iter() { - app = app.enqueue(task); + while let Some(task) = app.pop_task_out() { + tx_msg_in.send(task)?; } - - let (new_app, new_result) = match app.clone().mutate_or_sleep() { - Ok(a) => (a, Ok(())), - Err(e) => (app, Err(e)), - }; - - app = new_app; - result = new_result; } terminal.clear()?; diff --git a/src/pwd_watcher.rs b/src/pwd_watcher.rs new file mode 100644 index 0000000..433a826 --- /dev/null +++ b/src/pwd_watcher.rs @@ -0,0 +1,38 @@ +use crate::app::Task; +use crate::app::{ExternalMsg, MsgIn}; +use anyhow::Result; +use notify::{watcher, RecursiveMode, Watcher}; +use std::sync::mpsc::{channel, Receiver, Sender}; +use std::thread; +use std::time::Duration; + +pub fn keep_watching( + pwd: &str, + tx_msg_in: Sender, + rx_pwd_watcher: Receiver, +) -> Result<()> { + let (tx, rx) = channel(); + let mut watcher = watcher(tx, Duration::from_secs(1))?; + watcher.watch(pwd, RecursiveMode::NonRecursive)?; + + let mut last_pwd = pwd.to_string(); + thread::spawn(move || loop { + if let Ok(new_pwd) = rx_pwd_watcher.try_recv() { + watcher.unwatch(&last_pwd).unwrap(); + watcher + .watch(&new_pwd, RecursiveMode::NonRecursive) + .unwrap(); + last_pwd = new_pwd; + } else { + thread::sleep(Duration::from_secs(1)); + } + + if rx.try_recv().is_ok() { + let msg = MsgIn::External(ExternalMsg::Explore); + tx_msg_in.send(Task::new(3, msg, None)).unwrap(); + } else { + thread::sleep(Duration::from_secs(1)); + } + }); + Ok(()) +}