summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiayi Zhao <jeff.no.zhao@gmail.com>2020-03-16 16:14:17 -0400
committerJiayi Zhao <jeff.no.zhao@gmail.com>2020-03-16 16:14:17 -0400
commitc6edd4e5d5cbcbc16063a10181aee9626822d273 (patch)
tree5524d52e5fb6f288be943c4882973dd1839a95f3
parent50f67156b783c3f533214ddfa8e79bd979d76278 (diff)
better error handling for threads
- code cleanup
-rw-r--r--src/commands/bulk_rename.rs6
-rw-r--r--src/commands/file_ops/paste_copy.rs2
-rw-r--r--src/commands/file_ops/paste_cut.rs2
-rw-r--r--src/commands/set_mode.rs3
-rw-r--r--src/commands/tab_operations.rs8
-rw-r--r--src/commands/tab_switch.rs2
-rw-r--r--src/config/mimetype.rs13
-rw-r--r--src/context.rs1
-rw-r--r--src/fs/dirlist.rs7
-rw-r--r--src/io/io_worker.rs25
-rw-r--r--src/run.rs117
-rw-r--r--src/ui/widgets/tui_dirlist_detailed.rs3
-rw-r--r--src/ui/widgets/tui_menu.rs18
-rw-r--r--src/ui/widgets/tui_prompt.rs1
-rw-r--r--src/ui/widgets/tui_textfield.rs96
-rw-r--r--src/util/event.rs20
16 files changed, 158 insertions, 166 deletions
diff --git a/src/commands/bulk_rename.rs b/src/commands/bulk_rename.rs
index b9f5cfc..e22be06 100644
--- a/src/commands/bulk_rename.rs
+++ b/src/commands/bulk_rename.rs
@@ -138,9 +138,9 @@ impl std::fmt::Display for BulkRename {
impl JoshutoRunnable for BulkRename {
fn execute(&self, context: &mut JoshutoContext, backend: &mut TuiBackend) -> JoshutoResult<()> {
backend.terminal_drop();
- Self::bulk_rename(context)?;
- backend.terminal_restore();
+ let res = Self::bulk_rename(context);
+ backend.terminal_restore()?;
ReloadDirList::reload(context.curr_tab_index, context)?;
- Ok(())
+ res
}
}
diff --git a/src/commands/file_ops/paste_copy.rs b/src/commands/file_ops/paste_copy.rs
index 943e14f..3a430d1 100644
--- a/src/commands/file_ops/paste_copy.rs
+++ b/src/commands/file_ops/paste_copy.rs
@@ -55,7 +55,7 @@ pub fn paste_copy(
rx_start.recv();
for path in paths {
total += recursive_copy(thread_dest.as_path(), path.as_path(), &options)?;
- tx.send(Event::IOWorkerProgress(total));
+ tx.send(total);
}
Ok(total)
});
diff --git a/src/commands/file_ops/paste_cut.rs b/src/commands/file_ops/paste_cut.rs
index 3d1b610..fb9dc72 100644
--- a/src/commands/file_ops/paste_cut.rs
+++ b/src/commands/file_ops/paste_cut.rs
@@ -63,7 +63,7 @@ pub fn paste_cut(
rx_start.recv();
for path in paths {
total += recursive_cut(thread_dest.as_path(), path.as_path(), &options)?;
- tx.send(Event::IOWorkerProgress(total));
+ tx.send(total);
}
Ok(total)
});
diff --git a/src/commands/set_mode.rs b/src/commands/set_mode.rs
index 7ce18a2..d23c366 100644
--- a/src/commands/set_mode.rs
+++ b/src/commands/set_mode.rs
@@ -1,7 +1,6 @@
use crate::commands::{CursorMoveDown, JoshutoCommand, JoshutoRunnable};
use crate::context::JoshutoContext;
use crate::error::JoshutoResult;
-use crate::fs::JoshutoDirEntry;
use crate::ui::widgets::TuiTextField;
use crate::ui::TuiBackend;
use crate::util::unix;
@@ -77,7 +76,7 @@ impl JoshutoRunnable for SetMode {
let s = &s[PREFIX.len()..];
let mode = Self::str_to_mode(s);
- let mut entry = context.tabs[context.curr_tab_index]
+ let entry = context.tabs[context.curr_tab_index]
.curr_list_mut()
.and_then(|x| x.get_curr_mut())
.unwrap();
diff --git a/src/commands/tab_operations.rs b/src/commands/tab_operations.rs
index 673502b..6c62d09 100644
--- a/src/commands/tab_operations.rs
+++ b/src/commands/tab_operations.rs
@@ -1,6 +1,6 @@
use std::path;
-use crate::commands::{JoshutoCommand, JoshutoRunnable, CursorMoveStub, Quit, TabSwitch};
+use crate::commands::{CursorMoveStub, JoshutoCommand, JoshutoRunnable, Quit, TabSwitch};
use crate::context::JoshutoContext;
use crate::error::JoshutoResult;
use crate::tab::JoshutoTab;
@@ -60,7 +60,7 @@ impl CloseTab {
"close_tab"
}
- pub fn close_tab(context: &mut JoshutoContext, backend: &mut TuiBackend) -> JoshutoResult<()> {
+ pub fn close_tab(context: &mut JoshutoContext) -> JoshutoResult<()> {
if context.tabs.len() <= 1 {
return Quit::quit(context);
}
@@ -83,7 +83,7 @@ impl std::fmt::Display for CloseTab {
}
impl JoshutoRunnable for CloseTab {
- fn execute(&self, context: &mut JoshutoContext, backend: &mut TuiBackend) -> JoshutoResult<()> {
- Self::close_tab(context, backend)
+ fn execute(&self, context: &mut JoshutoContext, _: &mut TuiBackend) -> JoshutoResult<()> {
+ Self::close_tab(context)
}
}
diff --git a/src/commands/tab_switch.rs b/src/commands/tab_switch.rs
index ef911f1..cc54f57 100644
--- a/src/commands/tab_switch.rs
+++ b/src/commands/tab_switch.rs
@@ -36,7 +36,7 @@ impl std::fmt::Display for TabSwitch {
}
impl JoshutoRunnable for TabSwitch {
- fn execute(&self, context: &mut JoshutoContext, backend: &mut TuiBackend) -> JoshutoResult<()> {
+ fn execute(&self, context: &mut JoshutoContext, _: &mut TuiBackend) -> JoshutoResult<()> {
let mut new_index = context.curr_tab_index as i32 + self.movement;
let tab_len = context.tabs.len() as i32;
while new_index < 0 {
diff --git a/src/config/mimetype.rs b/src/config/mimetype.rs
index 5538fb0..f6d81de 100644
--- a/src/config/mimetype.rs
+++ b/src/config/mimetype.rs
@@ -57,7 +57,7 @@ impl JoshutoMimetypeEntry {
self
}
- pub fn set_confirm_exit(mut self, confirm_exit: bool) -> Self {
+ pub fn confirm_exit(mut self, confirm_exit: bool) -> Self {
self._confirm_exit = confirm_exit;
self
}
@@ -125,14 +125,17 @@ impl std::fmt::Display for JoshutoMimetypeEntry {
.iter()
.for_each(|arg| write!(f, " {}", arg).unwrap());
- f.write_str("\t[").unwrap();
+ f.write_str("\t\t").unwrap();
if self.get_fork() {
- f.write_str("fork,").unwrap();
+ f.write_str("[fork]").unwrap();
}
if self.get_silent() {
- f.write_str("silent").unwrap();
+ f.write_str("[silent]").unwrap();
}
- f.write_str("]")
+ if self.get_confirm_exit() {
+ f.write_str("[confirm-exit]").unwrap();
+ }
+ f.write_str("")
}
}
diff --git a/src/context.rs b/src/context.rs
index 0135674..0370f1b 100644
--- a/src/context.rs
+++ b/src/context.rs
@@ -1,5 +1,4 @@
use std::collections::VecDeque;
-use std::sync::mpsc;
use crate::config;
use crate::io::IOWorkerThread;
diff --git a/src/fs/dirlist.rs b/src/fs/dirlist.rs
index 7d31814..283fd41 100644
--- a/src/fs/dirlist.rs
+++ b/src/fs/dirlist.rs
@@ -34,13 +34,6 @@ impl JoshutoDirList {
})
}
- pub fn sort<F>(&mut self, sort_func: F)
- where
- F: Fn(&JoshutoDirEntry, &JoshutoDirEntry) -> std::cmp::Ordering,
- {
- self.contents.sort_by(sort_func);
- }
-
pub fn depreciate(&mut self) {
self.content_outdated = true;
}
diff --git a/src/io/io_worker.rs b/src/io/io_worker.rs
index 382d6aa..a9d2726 100644
--- a/src/io/io_worker.rs
+++ b/src/io/io_worker.rs
@@ -32,18 +32,14 @@ impl IOWorkerObserver {
let handle = thread::spawn(move || {
worker.start();
- while let Ok(evt) = worker.recv() {
- let _ = event_tx.send(evt);
+ while let Ok(copied) = worker.recv() {
+ let _ = event_tx.send(Event::IOWorkerProgress(copied));
}
- worker.handle.join();
- let _ = event_tx.send(Event::IOWorkerResult);
+ let res = worker.join();
+ let _ = event_tx.send(Event::IOWorkerResult(res));
});
- Self {
- src,
- dest,
- handle,
- }
+ Self { src, dest, handle }
}
pub fn join(self) {
@@ -56,7 +52,7 @@ pub struct IOWorkerThread {
pub dest: path::PathBuf,
pub handle: thread::JoinHandle<std::io::Result<u64>>,
pub tx_start: mpsc::Sender<()>,
- pub rx: mpsc::Receiver<Event>,
+ pub rx: mpsc::Receiver<u64>,
}
impl IOWorkerThread {
@@ -64,7 +60,14 @@ impl IOWorkerThread {
self.tx_start.send(());
}
- pub fn recv(&self) -> Result<Event, mpsc::RecvError> {
+ pub fn recv(&self) -> Result<u64, mpsc::RecvError> {
self.rx.recv()
}
+
+ pub fn join(self) -> std::io::Result<u64> {
+ match self.handle.join() {
+ Ok(s) => s,
+ Err(_) => Ok(0),
+ }
+ }
}
diff --git a/src/run.rs b/src/run.rs
index 0291a34..e43ce84 100644
--- a/src/run.rs
+++ b/src/run.rs
@@ -1,14 +1,12 @@
-use std::thread;
-
use crate::commands::{CommandKeybind, CursorMoveStub, JoshutoRunnable};
use crate::config::{JoshutoCommandMapping, JoshutoConfig};
use crate::context::JoshutoContext;
+use crate::history::DirectoryHistory;
+use crate::io::IOWorkerObserver;
use crate::tab::JoshutoTab;
use crate::ui;
use crate::ui::widgets::{TuiCommandMenu, TuiView};
use crate::util::event::Event;
-use crate::history::DirectoryHistory;
-use crate::io::IOWorkerObserver;
pub fn run(config_t: JoshutoConfig, keymap_t: JoshutoCommandMapping) -> std::io::Result<()> {
let mut backend: ui::TuiBackend = ui::TuiBackend::new()?;
@@ -43,72 +41,73 @@ pub fn run(config_t: JoshutoConfig, keymap_t: JoshutoCommandMapping) -> std::io:
}
}
- match context.events.next() {
- Ok(event) => {
- match event {
- Event::IOWorkerProgress(p) => {
- context.worker_msg = Some(format!("bytes copied {}", p));
- }
- Event::IOWorkerResult => {
- match io_observer {
- Some(handle) => {
- let src = handle.src.clone();
- let dest = handle.dest.clone();
- handle.join();
- context
- .message_queue
- .push_back("io_worker done".to_string());
- let options = &context.config_t.sort_option;
- for tab in context.tabs.iter_mut() {
- tab.history.create_or_update(src.as_path(), options);
- tab.history.create_or_update(dest.as_path(), options);
- }
+ let event = match context.events.next() {
+ Ok(event) => event,
+ Err(e) => return Ok(()),
+ };
+
+ match event {
+ Event::IOWorkerProgress(p) => {
+ context.worker_msg = Some(format!("bytes copied {}", p));
+ }
+ Event::IOWorkerResult(res) => {
+ match io_observer {
+ Some(handle) => {
+ let src = handle.src.clone();
+ let dest = handle.dest.clone();
+ handle.join();
+ let msg = match res {
+ Ok(s) => {
+ format!("io_worker completed successfully: {} bytes processed", s)
}
- None => {}
+ Err(e) => format!("io_worker was not completed: {}", e.to_string()),
+ };
+ context.message_queue.push_back(msg);
+ let options = &context.config_t.sort_option;
+ for tab in context.tabs.iter_mut() {
+ tab.history.create_or_update(src.as_path(), options);
+ tab.history.create_or_update(dest.as_path(), options);
}
- io_observer = None;
- context.worker_msg = None;
}
- Event::Input(key) => {
- /* Message handling */
- if !context.message_queue.is_empty() {
- let _ = context.message_queue.pop_front();
+ None => {}
+ }
+ io_observer = None;
+ context.worker_msg = None;
+ }
+ Event::Input(key) => {
+ /* Message handling */
+ if !context.message_queue.is_empty() {
+ let _ = context.message_queue.pop_front();
+ }
+ match keymap_t.get(&key) {
+ None => {
+ context
+ .message_queue
+ .push_back(format!("Unknown keycode: {:?}", key));
+ }
+ Some(CommandKeybind::SimpleKeybind(command)) => {
+ if let Err(e) = command.execute(&mut context, &mut backend) {
+ context.message_queue.push_back(e.to_string());
}
- match keymap_t.get(&key) {
- None => {
- context
- .message_queue
- .push_back(format!("Unknown keycode: {:?}", key));
- }
- Some(CommandKeybind::SimpleKeybind(command)) => {
- if let Err(e) = command.execute(&mut context, &mut backend) {
- context.message_queue.push_back(e.to_string());
- }
- }
- Some(CommandKeybind::CompositeKeybind(m)) => {
- let cmd = {
- let mut menu = TuiCommandMenu::new();
- menu.get_input(&mut backend, &context, &m)
- };
+ }
+ Some(CommandKeybind::CompositeKeybind(m)) => {
+ let cmd = {
+ let mut menu = TuiCommandMenu::new();
+ menu.get_input(&mut backend, &context, &m)
+ };
- if let Some(command) = cmd {
- if let Err(e) = command.execute(&mut context, &mut backend) {
- context.message_queue.push_back(e.to_string());
- }
- }
+ if let Some(command) = cmd {
+ if let Err(e) = command.execute(&mut context, &mut backend) {
+ context.message_queue.push_back(e.to_string());
}
}
- context.events.flush();
}
}
- let mut view = TuiView::new(&context);
- backend.render(&mut view);
- }
- Err(e) => {
- context.message_queue.push_back(e.to_string());
- break;
+ context.events.flush();
}
}
+ let mut view = TuiView::new(&context);
+ backend.render(&mut view);
}
Ok(())
}
diff --git a/src/ui/widgets/tui_dirlist_detailed.rs b/src/ui/widgets/tui_dirlist_detailed.rs
index e0e580c..54de784 100644
--- a/src/ui/widgets/tui_dirlist_detailed.rs
+++ b/src/ui/widgets/tui_dirlist_detailed.rs
@@ -2,7 +2,7 @@ use tui::buffer::Buffer;
use tui::layout::Rect;
use tui::style::{Color, Modifier, Style};
use tui::widgets::Widget;
-use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
+use unicode_width::UnicodeWidthStr;
use crate::fs::JoshutoDirList;
use crate::util::format;
@@ -32,7 +32,6 @@ impl<'a> Widget for TuiDirListDetailed<'a> {
let x = area.left();
let y = area.top();
- let dir_len = self.dirlist.contents.len();
let curr_index = match self.dirlist.index {
Some(i) => i,
None => {
diff --git a/src/ui/widgets/tui_menu.rs b/src/ui/widgets/tui_menu.rs
index 4088d6d..efa8d7d 100644
--- a/src/ui/widgets/tui_menu.rs
+++ b/src/ui/widgets/tui_menu.rs
@@ -80,17 +80,15 @@ impl TuiCommandMenu {
Event::Input(key) => {
match key {
Key::Esc => return None,
- key => {
- match map.get(&key) {
- Some(CommandKeybind::SimpleKeybind(s)) => {
- return Some(s);
- }
- Some(CommandKeybind::CompositeKeybind(m)) => {
- map = m;
- }
- None => return None,
+ key => match map.get(&key) {
+ Some(CommandKeybind::SimpleKeybind(s)) => {
+ return Some(s);
}
- }
+ Some(CommandKeybind::CompositeKeybind(m)) => {
+ map = m;
+ }
+ None => return None,
+ },
}
context.events.flush();
}
diff --git a/src/ui/widgets/tui_prompt.rs b/src/ui/widgets/tui_prompt.rs
index 1f4826f..b9848d0 100644
--- a/src/ui/widgets/tui_prompt.rs
+++ b/src/ui/widgets/tui_prompt.rs
@@ -2,7 +2,6 @@ use termion::event::Key;
use tui::layout::Rect;
use tui::style::{Color, Style};
use tui::widgets::{Paragraph, Text, Widget};
-use unicode_width::UnicodeWidthStr;
use crate::context::JoshutoContext;
use crate::ui::TuiBackend;
diff --git a/src/ui/widgets/tui_textfield.rs b/src/ui/widgets/tui_textfield.rs
index c663b95..c72bc9b 100644
--- a/src/ui/widgets/tui_textfield.rs
+++ b/src/ui/widgets/tui_textfield.rs
@@ -92,53 +92,55 @@ impl<'a> TuiTextField<'a> {
}
loop {
- terminal.draw(|mut frame| {
- let f_size = frame.size();
- if f_size.height == 0 {
- return;
- }
-
- {
- let mut view = TuiView::new(&context);
- view.show_bottom_status = false;
- view.render(&mut frame, f_size);
- }
-
- if let Some(menu) = self._menu.as_mut() {
- let menu_len = menu.len();
- let menu_y = if menu_len + 2 > f_size.height as usize {
- 0
- } else {
- (f_size.height as usize - menu_len - 2) as u16
- };
+ terminal
+ .draw(|mut frame| {
+ let f_size = frame.size();
+ if f_size.height == 0 {
+ return;
+ }
- let rect = Rect {
- x: 0,
- y: menu_y,
- width: f_size.width,
- height: menu_len as u16,
- };
- menu.render(&mut frame, rect);
- }
+ {
+ let mut view = TuiView::new(&context);
+ view.show_bottom_status = false;
+ view.render(&mut frame, f_size);
+ }
- let cmd_prompt_style = Style::default().fg(Color::LightGreen);
+ if let Some(menu) = self._menu.as_mut() {
+ let menu_len = menu.len();
+ let menu_y = if menu_len + 2 > f_size.height as usize {
+ 0
+ } else {
+ (f_size.height as usize - menu_len - 2) as u16
+ };
+
+ let rect = Rect {
+ x: 0,
+ y: menu_y,
+ width: f_size.width,
+ height: menu_len as u16,
+ };
+ menu.render(&mut frame, rect);
+ }
- let text = [
- Text::styled(self._prompt, cmd_prompt_style),
- Text::raw(line_buffer.as_str()),
- ];
+ let cmd_prompt_style = Style::default().fg(Color::LightGreen);
- let textfield_rect = Rect {
- x: 0,
- y: f_size.height - 1,
- width: f_size.width,
- height: 1,
- };
+ let text = [
+ Text::styled(self._prompt, cmd_prompt_style),
+ Text::raw(line_buffer.as_str()),
+ ];
- Paragraph::new(text.iter())
- .wrap(true)
- .render(&mut frame, textfield_rect);
- });
+ let textfield_rect = Rect {
+ x: 0,
+ y: f_size.height - 1,
+ width: f_size.width,
+ height: 1,
+ };
+
+ Paragraph::new(text.iter())
+ .wrap(true)
+ .render(&mut frame, textfield_rect);
+ })
+ .unwrap();
if let Ok(event) = context.events.next() {
match event {
@@ -180,8 +182,8 @@ impl<'a> TuiTextField<'a> {
}
Key::Char('\t') => {
if completion_tracker.is_none() {
- let res =
- completer.complete_path(line_buffer.as_str(), line_buffer.pos());
+ let res = completer
+ .complete_path(line_buffer.as_str(), line_buffer.pos());
if let Ok((pos, mut candidates)) = res {
candidates.sort_by(|x, y| {
x.display()
@@ -200,7 +202,11 @@ impl<'a> TuiTextField<'a> {
if let Some(ref mut s) = completion_tracker {
if s.index < s.candidates.len() {
let candidate = &s.candidates[s.index];
- completer.update(&mut line_buffer, s.pos, candidate.display());
+ completer.update(
+ &mut line_buffer,
+ s.pos,
+ candidate.display(),
+ );
s.index += 1;
}
}
diff --git a/src/util/event.rs b/src/util/event.rs
index 9ec41f7..b3955a6 100644
--- a/src/util/event.rs
+++ b/src/util/event.rs
@@ -9,7 +9,7 @@ use termion::input::TermRead;
pub enum Event {
Input(Key),
IOWorkerProgress(u64),
- IOWorkerResult,
+ IOWorkerResult(std::io::Result<u64>),
}
#[derive(Debug, Clone, Copy)]
@@ -24,7 +24,6 @@ impl Default for Config {
/// A small event handler that wrap termion input and tick events. Each event
/// type is handled in its own thread and returned to a common `Receiver`
pub struct Events {
- prefix: &'static str,
pub event_tx: mpsc::Sender<Event>,
event_rx: mpsc::Receiver<Event>,
pub input_tx: mpsc::SyncSender<()>,
@@ -33,14 +32,10 @@ pub struct Events {
impl Events {
pub fn new() -> Self {
- Events::with_config("")
- }
- pub fn with_debug(s: &'static str) -> Self {
- let event = Events::with_config(s);
- event
+ Events::with_config()
}
- pub fn with_config(prefix: &'static str) -> Self {
+ pub fn with_config() -> Self {
let (input_tx, input_rx) = mpsc::sync_channel(1);
let (event_tx, event_rx) = mpsc::channel();
@@ -53,12 +48,12 @@ impl Events {
Some(key) => match key {
Ok(key) => {
if let Err(e) = event_tx.send(Event::Input(key)) {
- eprintln!("[{}] Input thread send err: {:#?}", prefix, e);
+ eprintln!("Input thread send err: {:#?}", e);
return;
}
}
_ => return,
- }
+ },
_ => return,
}
@@ -66,7 +61,7 @@ impl Events {
if let Some(key) = keys.next() {
if let Ok(key) = key {
if let Err(e) = event_tx.send(Event::Input(key)) {
- eprintln!("[{}] Input thread send err: {:#?}", prefix, e);
+ eprintln!("Input thread send err: {:#?}", e);
return;
}
}
@@ -79,7 +74,6 @@ impl Events {
event_tx,
event_rx,
input_tx,
- prefix,
}
}
@@ -89,6 +83,6 @@ impl Events {
}
pub fn flush(&self) {
- self.input_tx.send(());
+ let _ = self.input_tx.send(());
}
}