Use key `tab` to select files in search mode

Select files fzf style in search mode, without losing the search input.

Also, make background tasks failsafe and measure ui rendering.
pull/130/head v0.7.1
Arijit Basu 3 years ago committed by Arijit Basu
parent 38812e733b
commit 9e89c6503d

2
Cargo.lock generated

@ -1630,7 +1630,7 @@ dependencies = [
[[package]]
name = "xplr"
version = "0.7.0"
version = "0.7.1"
dependencies = [
"anyhow",
"chrono",

@ -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 <sayanarijit@gmail.com>"]
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

@ -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::<Vec<String>>()
.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);

@ -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);

@ -6,7 +6,7 @@ use std::time::Duration;
pub fn start_auto_refreshing(tx: Sender<Task>) {
thread::spawn(move || loop {
tx.send(Task::new(MsgIn::External(ExternalMsg::Refresh), None))
.unwrap();
.unwrap_or_default();
thread::sleep(Duration::from_secs(1));
});
}

@ -1394,6 +1394,7 @@ impl Config {
pub fn is_compatible(&self) -> Result<bool> {
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<Option<&str>> {
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)

@ -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:

@ -14,17 +14,19 @@ pub fn keep_reading(tx_msg_in: Sender<Task>, rx_event_reader: Receiver<bool>) {
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<Task>, rx_event_reader: Receiver<bool>) {
MsgIn::External(ExternalMsg::LogError(e.to_string())),
None,
))
.unwrap();
.unwrap_or_default();
}
}
} else {

@ -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();
})
});

@ -24,14 +24,15 @@ pub fn keep_reading(pipe: String, tx: Sender<Task>) {
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<Task>) {
))),
None,
))
.unwrap();
.unwrap_or_default();
thread::sleep(Duration::from_secs(3));
}
});

@ -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));
}

Loading…
Cancel
Save