diff options
author | Jiayi Zhao <jeff.no.zhao@gmail.com> | 2020-03-16 16:14:17 -0400 |
---|---|---|
committer | Jiayi Zhao <jeff.no.zhao@gmail.com> | 2020-03-16 16:14:17 -0400 |
commit | c6edd4e5d5cbcbc16063a10181aee9626822d273 (patch) | |
tree | 5524d52e5fb6f288be943c4882973dd1839a95f3 | |
parent | 50f67156b783c3f533214ddfa8e79bd979d76278 (diff) |
better error handling for threads
- code cleanup
-rw-r--r-- | src/commands/bulk_rename.rs | 6 | ||||
-rw-r--r-- | src/commands/file_ops/paste_copy.rs | 2 | ||||
-rw-r--r-- | src/commands/file_ops/paste_cut.rs | 2 | ||||
-rw-r--r-- | src/commands/set_mode.rs | 3 | ||||
-rw-r--r-- | src/commands/tab_operations.rs | 8 | ||||
-rw-r--r-- | src/commands/tab_switch.rs | 2 | ||||
-rw-r--r-- | src/config/mimetype.rs | 13 | ||||
-rw-r--r-- | src/context.rs | 1 | ||||
-rw-r--r-- | src/fs/dirlist.rs | 7 | ||||
-rw-r--r-- | src/io/io_worker.rs | 25 | ||||
-rw-r--r-- | src/run.rs | 117 | ||||
-rw-r--r-- | src/ui/widgets/tui_dirlist_detailed.rs | 3 | ||||
-rw-r--r-- | src/ui/widgets/tui_menu.rs | 18 | ||||
-rw-r--r-- | src/ui/widgets/tui_prompt.rs | 1 | ||||
-rw-r--r-- | src/ui/widgets/tui_textfield.rs | 96 | ||||
-rw-r--r-- | src/util/event.rs | 20 |
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), + } + } } @@ -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(()); } } |