diff --git a/Cargo.lock b/Cargo.lock index 490cbce..ec6bc79 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1630,7 +1630,7 @@ dependencies = [ [[package]] name = "xplr" -version = "0.7.0" +version = "0.7.1" dependencies = [ "anyhow", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 9f555d2..1803b49 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xplr" -version = "0.7.0" # Update config.yml, config.rs and default.nix +version = "0.7.1" # Update config.yml, config.rs and default.nix authors = ["Arijit Basu "] edition = "2018" description = "A hackable, minimal, fast TUI file explorer" @@ -37,5 +37,5 @@ rspec = "1.0" serde_json = "1.0" [[bench]] -name = "navigation" +name = "criterion" harness = false diff --git a/benches/criterion.rs b/benches/criterion.rs new file mode 100644 index 0000000..2c09144 --- /dev/null +++ b/benches/criterion.rs @@ -0,0 +1,154 @@ +use crate::app; +use crate::ui; +use anyhow::Result; +use criterion::{criterion_group, criterion_main, Criterion}; +use crossterm::execute; +use crossterm::terminal as term; +use handlebars::{handlebars_helper, Handlebars}; +use humansize::{file_size_opts as options, FileSize}; +use std::fs; +use std::io::prelude::*; +use termion::get_tty; +use tui::backend::CrosstermBackend; +use tui::Terminal; +use xplr::*; + +const PWD: &str = "/tmp/xplr_bench"; + +handlebars_helper!(to_humansize: |size: i64| size.file_size(options::CONVENTIONAL).unwrap_or_default()); + +fn navigation_benchmark(c: &mut Criterion) { + fs::create_dir_all(PWD).unwrap(); + (1..10000).for_each(|i| { + fs::File::create(std::path::Path::new(PWD).join(i.to_string())).unwrap(); + }); + + let mut app = app::App::create(PWD.into()).expect("failed to create app"); + + app = app + .clone() + .handle_task(app::Task::new( + app::MsgIn::External(app::ExternalMsg::ChangeDirectory(PWD.into())), + None, + )) + .unwrap(); + + c.bench_function("focus next item", |b| { + b.iter(|| { + app.clone() + .handle_task(app::Task::new( + app::MsgIn::External(app::ExternalMsg::FocusNext), + None, + )) + .unwrap() + }) + }); + + c.bench_function("focus previous item", |b| { + b.iter(|| { + app.clone() + .handle_task(app::Task::new( + app::MsgIn::External(app::ExternalMsg::FocusPrevious), + None, + )) + .unwrap() + }) + }); + + c.bench_function("focus first item", |b| { + b.iter(|| { + app.clone() + .handle_task(app::Task::new( + app::MsgIn::External(app::ExternalMsg::FocusFirst), + None, + )) + .unwrap() + }) + }); + + c.bench_function("focus last item", |b| { + b.iter(|| { + app.clone() + .handle_task(app::Task::new( + app::MsgIn::External(app::ExternalMsg::FocusLast), + None, + )) + .unwrap() + }) + }); + + c.bench_function("leave and enter directory", |b| { + b.iter(|| { + app.clone() + .handle_task(app::Task::new( + app::MsgIn::External(app::ExternalMsg::Back), + None, + )) + .unwrap() + .handle_task(app::Task::new( + app::MsgIn::External(app::ExternalMsg::Enter), + None, + )) + .unwrap() + }) + }); +} + +fn draw_benchmark(c: &mut Criterion) { + fs::create_dir_all(PWD).unwrap(); + (1..10000).for_each(|i| { + fs::File::create(std::path::Path::new(PWD).join(i.to_string())).unwrap(); + }); + + let mut app = app::App::create(PWD.into()).expect("failed to create app"); + + app = app + .clone() + .handle_task(app::Task::new( + app::MsgIn::External(app::ExternalMsg::ChangeDirectory(PWD.into())), + None, + )) + .unwrap(); + + let mut hb = Handlebars::new(); + hb.register_helper("humansize", Box::new(to_humansize)); + hb.register_template_string( + app::TEMPLATE_TABLE_ROW, + &app.config() + .general() + .table() + .row() + .cols() + .clone() + .unwrap_or_default() + .iter() + .map(|c| c.format().clone().unwrap_or_default()) + .collect::>() + .join("\t"), + ) + .unwrap(); + + term::enable_raw_mode().unwrap(); + let mut stdout = get_tty().unwrap(); + // let mut stdout = stdout.lock(); + execute!(stdout, term::EnterAlternateScreen).unwrap(); + // let stdout = MouseTerminal::from(stdout); + let backend = CrosstermBackend::new(stdout); + let mut terminal = Terminal::new(backend).unwrap(); + terminal.hide_cursor().unwrap(); + + c.bench_function("draw on terminal", |b| { + b.iter(|| { + terminal.draw(|f| ui::draw(f, &app, &hb)).unwrap(); + }) + }); + + terminal.clear().unwrap(); + terminal.set_cursor(0, 0).unwrap(); + execute!(terminal.backend_mut(), term::LeaveAlternateScreen).unwrap(); + term::disable_raw_mode().unwrap(); + terminal.show_cursor().unwrap(); +} + +criterion_group!(benches, navigation_benchmark, draw_benchmark); +criterion_main!(benches); diff --git a/benches/navigation.rs b/benches/navigation.rs deleted file mode 100644 index 0902bec..0000000 --- a/benches/navigation.rs +++ /dev/null @@ -1,82 +0,0 @@ -use criterion::{criterion_group, criterion_main, Criterion}; -use std::fs; -use xplr::*; - -fn criterion_benchmark(c: &mut Criterion) { - fs::create_dir_all("/tmp/xplr_bench").unwrap(); - (1..10000).for_each(|i| { - fs::File::create(format!("/tmp/xplr_bench/{}", i)).unwrap(); - }); - - let mut app = app::App::create("/tmp/xplr_bench".into()).expect("failed to create app"); - - app = app - .clone() - .handle_task(app::Task::new( - app::MsgIn::External(app::ExternalMsg::ChangeDirectory("/tmp/xplr_bench".into())), - None, - )) - .unwrap(); - - c.bench_function("focus next item", |b| { - b.iter(|| { - app.clone() - .handle_task(app::Task::new( - app::MsgIn::External(app::ExternalMsg::FocusNext), - None, - )) - .unwrap() - }) - }); - - c.bench_function("focus previous item", |b| { - b.iter(|| { - app.clone() - .handle_task(app::Task::new( - app::MsgIn::External(app::ExternalMsg::FocusPrevious), - None, - )) - .unwrap() - }) - }); - - c.bench_function("focus first item", |b| { - b.iter(|| { - app.clone() - .handle_task(app::Task::new( - app::MsgIn::External(app::ExternalMsg::FocusFirst), - None, - )) - .unwrap() - }) - }); - - c.bench_function("focus last item", |b| { - b.iter(|| { - app.clone() - .handle_task(app::Task::new( - app::MsgIn::External(app::ExternalMsg::FocusLast), - None, - )) - .unwrap() - }) - }); - - c.bench_function("leave and enter directory", |b| { - b.iter(|| { - app.clone() - .handle_task(app::Task::new( - app::MsgIn::External(app::ExternalMsg::Back), - None, - )) - .unwrap() - .handle_task(app::Task::new( - app::MsgIn::External(app::ExternalMsg::Enter), - None, - )) - .unwrap() - }) - }); -} -criterion_group!(benches, criterion_benchmark); -criterion_main!(benches); diff --git a/src/auto_refresher.rs b/src/auto_refresher.rs index 99c42ed..4c794d0 100644 --- a/src/auto_refresher.rs +++ b/src/auto_refresher.rs @@ -6,7 +6,7 @@ use std::time::Duration; pub fn start_auto_refreshing(tx: Sender) { thread::spawn(move || loop { tx.send(Task::new(MsgIn::External(ExternalMsg::Refresh), None)) - .unwrap(); + .unwrap_or_default(); thread::sleep(Duration::from_secs(1)); }); } diff --git a/src/config.rs b/src/config.rs index ee6a20c..0036555 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1394,6 +1394,7 @@ impl Config { pub fn is_compatible(&self) -> Result { let result = match self.parsed_version()? { + (0, 7, 1) => true, (0, 7, 0) => true, (_, _, _) => false, }; @@ -1403,8 +1404,11 @@ impl Config { pub fn upgrade_notification(&self) -> Result> { let result = match self.parsed_version()? { + (0, 7, 1) => None, + (0, 7, 0) => { + Some("App version updated. Use `tab` to select files while in search mode") + } (_, _, _) => None, - // (_, _, _) => Some("App version updated. New: added sort and filter support and some hacks: https://github.com/sayanarijit/xplr/wiki/Hacks"), }; Ok(result) diff --git a/src/config.yml b/src/config.yml index 243e156..5106bff 100644 --- a/src/config.yml +++ b/src/config.yml @@ -1,4 +1,4 @@ -version: v0.7.0 +version: v0.7.1 layouts: custom: {} builtin: @@ -1155,6 +1155,11 @@ modes: ctrl-n: down ctrl-p: up on_key: + tab: + help: select + messages: + - Select + - FocusNext backspace: help: remove last character messages: diff --git a/src/event_reader.rs b/src/event_reader.rs index 3ebba55..42fd9f4 100644 --- a/src/event_reader.rs +++ b/src/event_reader.rs @@ -14,17 +14,19 @@ pub fn keep_reading(tx_msg_in: Sender, rx_event_reader: Receiver) { is_paused = paused; }; - if !is_paused && event::poll(std::time::Duration::from_millis(1)).unwrap() { + if !is_paused && event::poll(std::time::Duration::from_millis(1)).unwrap_or_default() { match event::read() { Ok(Event::Key(key)) => { let key = Key::from_event(key); let msg = MsgIn::Internal(InternalMsg::HandleKey(key)); - tx_msg_in.send(Task::new(msg, Some(key))).unwrap(); + tx_msg_in + .send(Task::new(msg, Some(key))) + .unwrap_or_default(); } Ok(Event::Resize(_, _)) => { let msg = MsgIn::External(ExternalMsg::Refresh); - tx_msg_in.send(Task::new(msg, None)).unwrap(); + tx_msg_in.send(Task::new(msg, None)).unwrap_or_default(); } Ok(_) => {} Err(e) => { @@ -33,7 +35,7 @@ pub fn keep_reading(tx_msg_in: Sender, rx_event_reader: Receiver) { MsgIn::External(ExternalMsg::LogError(e.to_string())), None, )) - .unwrap(); + .unwrap_or_default(); } } } else { diff --git a/src/explorer.rs b/src/explorer.rs index 3bf7b15..2ef9b21 100644 --- a/src/explorer.rs +++ b/src/explorer.rs @@ -51,14 +51,14 @@ pub fn explore( MsgIn::Internal(InternalMsg::AddDirectory(parent, dir)), None, )) - .unwrap(); + .unwrap_or_default(); }) .unwrap_or_else(|e| { tx.send(Task::new( MsgIn::External(ExternalMsg::LogError(e.to_string())), None, )) - .unwrap(); + .unwrap_or_default(); }) }); diff --git a/src/pipe_reader.rs b/src/pipe_reader.rs index 34e92bc..dd80b08 100644 --- a/src/pipe_reader.rs +++ b/src/pipe_reader.rs @@ -24,14 +24,15 @@ pub fn keep_reading(pipe: String, tx: Sender) { msgs.for_each(|msg| match msg { Ok(m) => { - tx.send(Task::new(MsgIn::External(m), None)).unwrap(); + tx.send(Task::new(MsgIn::External(m), None)) + .unwrap_or_default(); } Err(e) => { tx.send(Task::new( MsgIn::External(ExternalMsg::LogError(e.to_string())), None, )) - .unwrap(); + .unwrap_or_default(); } }); } else { @@ -45,7 +46,7 @@ pub fn keep_reading(pipe: String, tx: Sender) { ))), None, )) - .unwrap(); + .unwrap_or_default(); thread::sleep(Duration::from_secs(3)); } }); diff --git a/src/pwd_watcher.rs b/src/pwd_watcher.rs index 142a246..46d06f2 100644 --- a/src/pwd_watcher.rs +++ b/src/pwd_watcher.rs @@ -24,7 +24,7 @@ pub fn keep_watching( MsgIn::External(ExternalMsg::LogError(e.to_string())), None, )) - .unwrap(); + .unwrap_or_default(); }); watcher .watch(&new_pwd, RecursiveMode::NonRecursive) @@ -34,7 +34,7 @@ pub fn keep_watching( MsgIn::External(ExternalMsg::LogError(e.to_string())), None, )) - .unwrap(); + .unwrap_or_default(); }); last_pwd = new_pwd; } else { @@ -43,7 +43,7 @@ pub fn keep_watching( if rx.try_recv().is_ok() { let msg = MsgIn::External(ExternalMsg::Explore); - tx_msg_in.send(Task::new(msg, None)).unwrap(); + tx_msg_in.send(Task::new(msg, None)).unwrap_or_default(); } else { thread::sleep(Duration::from_secs(1)); }