Improve input reading by eliminating pause

Stop the thread instead of pausing it. This improves the CPU usage and
responsiveness a slightly.
pull/350/head
Arijit Basu 3 years ago committed by Arijit Basu
parent ac1b40799a
commit bec80e98df

2
Cargo.lock generated

@ -1091,7 +1091,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]] [[package]]
name = "xplr" name = "xplr"
version = "0.15.0" version = "0.15.1"
dependencies = [ dependencies = [
"ansi-to-tui", "ansi-to-tui",
"anyhow", "anyhow",

@ -1,6 +1,6 @@
[package] [package]
name = "xplr" name = "xplr"
version = "0.15.0" # Update lua.rs version = "0.15.1" # Update lua.rs
authors = ["Arijit Basu <sayanarijit@gmail.com>"] authors = ["Arijit Basu <sayanarijit@gmail.com>"]
edition = "2018" edition = "2018"
description = "A hackable, minimal, fast TUI file explorer" description = "A hackable, minimal, fast TUI file explorer"

@ -45,7 +45,7 @@ compatibility.
### Instructions ### Instructions
#### [v0.14.7][3] -> [v0.15.0][43] #### [v0.14.7][3] -> [v0.15.1][43]
- Deprecated `config` field from `CallLua` argument. Use the globally available - Deprecated `config` field from `CallLua` argument. Use the globally available
`xplr.config` instead. `xplr.config` instead.
@ -277,4 +277,4 @@ Else do the following:
[40]: https://github.com/sayanarijit/xplr/releases/tag/v0.3.8 [40]: https://github.com/sayanarijit/xplr/releases/tag/v0.3.8
[41]: https://github.com/sayanarijit/xplr/releases/tag/v0.3.0 [41]: https://github.com/sayanarijit/xplr/releases/tag/v0.3.0
[42]: https://github.com/sayanarijit/xplr/releases/tag/v0.14.4 [42]: https://github.com/sayanarijit/xplr/releases/tag/v0.14.4
[43]: https://github.com/sayanarijit/xplr/releases/tag/v0.15.0 [43]: https://github.com/sayanarijit/xplr/releases/tag/v0.15.1

@ -1,77 +1,86 @@
use crate::app::Task; use crate::app::Task;
use crate::app::{ExternalMsg, InternalMsg, MsgIn}; use crate::app::{ExternalMsg, InternalMsg, MsgIn};
use crate::input::Key; use crate::input::Key;
use anyhow::Result;
use crossterm::event::{self, Event, MouseEventKind}; use crossterm::event::{self, Event, MouseEventKind};
use std::sync::mpsc;
use std::sync::mpsc::{Receiver, Sender}; use std::sync::mpsc::{Receiver, Sender};
use std::thread; use std::thread;
pub fn pause_reading(tx_event_reader: &Sender<bool>, rx_loop_waiter: &Receiver<()>) -> Result<()> { pub(crate) struct EventReader {
tx_event_reader.send(true)?; task_sender: Sender<Task>,
rx_loop_waiter.recv()?; stopper: Option<(Sender<bool>, Receiver<()>)>,
Ok(())
} }
pub fn resume_reading(tx_event_reader: &Sender<bool>, rx_loop_waiter: &Receiver<()>) -> Result<()> { impl EventReader {
tx_event_reader.send(false)?; pub(crate) fn new(task_sender: Sender<Task>) -> Self {
rx_loop_waiter.recv()?; Self {
Ok(()) task_sender,
} stopper: None,
}
}
pub fn keep_reading( pub(crate) fn start(&mut self) {
tx_msg_in: Sender<Task>, let sender = self.task_sender.clone();
rx_event_reader: Receiver<bool>, let (tx_stopper, rx_stopper) = mpsc::channel();
tx_loop_waiter: Sender<()>, let (tx_ack, rx_ack) = mpsc::channel();
) { self.stopper = Some((tx_stopper, rx_ack));
thread::spawn(move || {
let mut is_paused = false;
loop {
if let Ok(paused) = rx_event_reader.try_recv() {
is_paused = paused;
tx_loop_waiter.send(()).unwrap();
};
if is_paused { thread::spawn(move || {
thread::sleep(std::time::Duration::from_millis(200)); keep_reading(sender, rx_stopper, tx_ack);
} else if event::poll(std::time::Duration::from_millis(150)).unwrap_or_default() { });
// NOTE: The poll timeout need to stay low, else spawning sub subshell }
// and start typing immediately will cause panic.
// To reproduce, press `:`, then press and hold `!`.
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();
}
Ok(Event::Mouse(evt)) => match evt.kind { pub(crate) fn stop(&self) {
MouseEventKind::ScrollUp => { if let Some((stopper, ack)) = &self.stopper {
let msg = MsgIn::External(ExternalMsg::FocusPrevious); stopper.send(true).unwrap();
tx_msg_in.send(Task::new(msg, None)).unwrap(); ack.recv().unwrap();
} }
}
}
MouseEventKind::ScrollDown => { fn keep_reading(tx_msg_in: Sender<Task>, rx_stopper: Receiver<bool>, tx_ack: Sender<()>) {
let msg = MsgIn::External(ExternalMsg::FocusNext); loop {
tx_msg_in.send(Task::new(msg, None)).unwrap(); if rx_stopper.try_recv().unwrap_or(false) {
} tx_ack.send(()).unwrap();
_ => {} break;
}, } else if event::poll(std::time::Duration::from_millis(150)).unwrap_or_default() {
// NOTE: The poll timeout need to stay low, else spawning sub subshell
// and start typing immediately will cause panic.
// To reproduce, press `:`, then press and hold `!`.
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();
}
Ok(Event::Resize(_, _)) => { Ok(Event::Mouse(evt)) => match evt.kind {
let msg = MsgIn::External(ExternalMsg::Refresh); MouseEventKind::ScrollUp => {
let msg = MsgIn::External(ExternalMsg::FocusPrevious);
tx_msg_in.send(Task::new(msg, None)).unwrap(); tx_msg_in.send(Task::new(msg, None)).unwrap();
} }
Err(e) => { MouseEventKind::ScrollDown => {
tx_msg_in let msg = MsgIn::External(ExternalMsg::FocusNext);
.send(Task::new( tx_msg_in.send(Task::new(msg, None)).unwrap();
MsgIn::External(ExternalMsg::LogError(e.to_string())),
None,
))
.unwrap();
} }
_ => {}
},
Ok(Event::Resize(_, _)) => {
let msg = MsgIn::External(ExternalMsg::Refresh);
tx_msg_in.send(Task::new(msg, None)).unwrap();
}
Err(e) => {
tx_msg_in
.send(Task::new(
MsgIn::External(ExternalMsg::LogError(e.to_string())),
None,
))
.unwrap();
} }
} }
} }
}); }
} }

@ -133,25 +133,25 @@ mod test {
assert!(check_version(VERSION, "foo path").is_ok()); assert!(check_version(VERSION, "foo path").is_ok());
// Current release if OK // Current release if OK
assert!(check_version("0.15.0", "foo path").is_ok()); assert!(check_version("0.15.1", "foo path").is_ok());
// Prev major release is ERR // Prev major release is ERR
// - Not yet // - Not yet
// Prev minor release is ERR (Change when we get to v1) // Prev minor release is ERR (Change when we get to v1)
assert!(check_version("0.14.0", "foo path").is_err()); assert!(check_version("0.14.1", "foo path").is_err());
// Prev bugfix release is OK // Prev bugfix release is OK
// assert!(check_version("0.15.-1", "foo path").is_ok()); assert!(check_version("0.15.0", "foo path").is_ok());
// Next major release is ERR // Next major release is ERR
assert!(check_version("1.15.0", "foo path").is_err()); assert!(check_version("1.15.1", "foo path").is_err());
// Next minor release is ERR // Next minor release is ERR
assert!(check_version("0.16.7", "foo path").is_err()); assert!(check_version("0.16.1", "foo path").is_err());
// Next bugfix release is ERR (Change when we get to v1) // Next bugfix release is ERR (Change when we get to v1)
assert!(check_version("0.15.8", "foo path").is_err()); assert!(check_version("0.15.2", "foo path").is_err());
} }
#[test] #[test]

@ -2,7 +2,7 @@
use crate::app; use crate::app;
use crate::cli::Cli; use crate::cli::Cli;
use crate::event_reader; use crate::event_reader::EventReader;
use crate::explorer; use crate::explorer;
use crate::lua; use crate::lua;
use crate::pipe_reader; use crate::pipe_reader;
@ -146,8 +146,6 @@ impl Runner {
fs::create_dir_all(app.session_path())?; fs::create_dir_all(app.session_path())?;
let (tx_msg_in, rx_msg_in) = mpsc::channel(); let (tx_msg_in, rx_msg_in) = mpsc::channel();
let (tx_event_reader, rx_event_reader) = mpsc::channel();
let (tx_loop_waiter, rx_loop_waiter) = mpsc::channel();
let (tx_pwd_watcher, rx_pwd_watcher) = mpsc::channel(); let (tx_pwd_watcher, rx_pwd_watcher) = mpsc::channel();
app = app.explore_pwd()?; app = app.explore_pwd()?;
@ -208,8 +206,9 @@ impl Runner {
terminal.hide_cursor()?; terminal.hide_cursor()?;
// Threads // Threads
event_reader::keep_reading(tx_msg_in.clone(), rx_event_reader, tx_loop_waiter);
pwd_watcher::keep_watching(app.pwd(), tx_msg_in.clone(), rx_pwd_watcher)?; pwd_watcher::keep_watching(app.pwd(), tx_msg_in.clone(), rx_pwd_watcher)?;
let mut event_reader = EventReader::new(tx_msg_in.clone());
event_reader.start();
// Enqueue on_load messages // Enqueue on_load messages
for msg in self.on_load { for msg in self.on_load {
@ -435,7 +434,7 @@ impl Runner {
execute!(terminal.backend_mut(), event::DisableMouseCapture) execute!(terminal.backend_mut(), event::DisableMouseCapture)
.unwrap_or_default(); .unwrap_or_default();
event_reader::pause_reading(&tx_event_reader, &rx_loop_waiter)?; event_reader.stop();
terminal.clear()?; terminal.clear()?;
terminal.set_cursor(0, 0)?; terminal.set_cursor(0, 0)?;
@ -460,7 +459,7 @@ impl Runner {
terminal.clear()?; terminal.clear()?;
term::enable_raw_mode()?; term::enable_raw_mode()?;
terminal.hide_cursor()?; terminal.hide_cursor()?;
event_reader::resume_reading(&tx_event_reader, &rx_loop_waiter)?; event_reader.start();
if mouse_enabled { if mouse_enabled {
match execute!( match execute!(
@ -481,7 +480,7 @@ impl Runner {
execute!(terminal.backend_mut(), event::DisableMouseCapture) execute!(terminal.backend_mut(), event::DisableMouseCapture)
.unwrap_or_default(); .unwrap_or_default();
event_reader::pause_reading(&tx_event_reader, &rx_loop_waiter)?; event_reader.stop();
terminal.clear()?; terminal.clear()?;
terminal.set_cursor(0, 0)?; terminal.set_cursor(0, 0)?;
@ -522,7 +521,7 @@ impl Runner {
terminal.clear()?; terminal.clear()?;
term::enable_raw_mode()?; term::enable_raw_mode()?;
terminal.hide_cursor()?; terminal.hide_cursor()?;
event_reader::resume_reading(&tx_event_reader, &rx_loop_waiter)?; event_reader.start();
if mouse_enabled { if mouse_enabled {
match execute!( match execute!(

Loading…
Cancel
Save