diff options
author | Jiayi Zhao <jeff.no.zhao@gmail.com> | 2020-02-09 12:39:31 -0500 |
---|---|---|
committer | Jiayi Zhao <jeff.no.zhao@gmail.com> | 2020-02-09 13:07:31 -0500 |
commit | becbb90b2f22d58c98693d653f55ba604bb03f75 (patch) | |
tree | 085b9ac9b197a9ad3f0dd20df36848c5619adefe /src | |
parent | 656582a6c867c25667661be9b327b4cc73859d7d (diff) |
rework input thread and file operations
- no longer depend on fs_extra for copy/paste files
- in house solution preserves permissions
- ioworkers are now queued, no more parallel io tasks
- input thread now listens for ioworker threads as well
- cargo fmt
Diffstat (limited to 'src')
-rw-r--r-- | src/commands/delete_files.rs | 35 | ||||
-rw-r--r-- | src/commands/file_operations.rs | 251 | ||||
-rw-r--r-- | src/commands/file_ops/copy.rs | 36 | ||||
-rw-r--r-- | src/commands/file_ops/cut.rs | 36 | ||||
-rw-r--r-- | src/commands/file_ops/local_state.rs | 56 | ||||
-rw-r--r-- | src/commands/file_ops/mod.rs | 11 | ||||
-rw-r--r-- | src/commands/file_ops/name_resolution.rs | 15 | ||||
-rw-r--r-- | src/commands/file_ops/paste.rs | 55 | ||||
-rw-r--r-- | src/commands/file_ops/paste_copy.rs | 68 | ||||
-rw-r--r-- | src/commands/file_ops/paste_cut.rs | 76 | ||||
-rw-r--r-- | src/commands/mod.rs | 12 | ||||
-rw-r--r-- | src/commands/open_file.rs | 6 | ||||
-rw-r--r-- | src/commands/quit.rs | 2 | ||||
-rw-r--r-- | src/config/keymap.rs | 11 | ||||
-rw-r--r-- | src/context.rs | 18 | ||||
-rw-r--r-- | src/fs/fs_extra_extra.rs | 323 | ||||
-rw-r--r-- | src/fs/mod.rs | 1 | ||||
-rw-r--r-- | src/io/io_worker.rs | 34 | ||||
-rw-r--r-- | src/io/mod.rs | 3 | ||||
-rw-r--r-- | src/main.rs | 9 | ||||
-rw-r--r-- | src/run.rs | 152 | ||||
-rw-r--r-- | src/textfield.rs | 2 | ||||
-rw-r--r-- | src/ui.rs | 20 | ||||
-rw-r--r-- | src/util/event.rs | 102 | ||||
-rw-r--r-- | src/util/key_mapping.rs | 2 | ||||
-rw-r--r-- | src/util/mod.rs | 76 | ||||
-rw-r--r-- | src/window/panel.rs | 1 |
27 files changed, 582 insertions, 831 deletions
diff --git a/src/commands/delete_files.rs b/src/commands/delete_files.rs index adaed07..c726dd4 100644 --- a/src/commands/delete_files.rs +++ b/src/commands/delete_files.rs @@ -35,32 +35,23 @@ impl DeleteFiles { fn delete_files(context: &mut JoshutoContext, view: &JoshutoView) -> std::io::Result<()> { ui::wprint_msg(&view.bot_win, "Delete selected files? (Y/n)"); - ncurses::timeout(-1); ncurses::doupdate(); let curr_tab = &mut context.tabs[context.curr_tab_index]; - let mut ch = ncurses::getch(); - if ch == 'y' as i32 || ch == KEYMAP_T.enter { - let paths = curr_tab.curr_list.get_selected_paths(); - if paths.is_empty() { - return Err(std::io::Error::new( - std::io::ErrorKind::Other, - "no files selected", - )); - } - if paths.len() > 1 { - ui::wprint_msg(&view.bot_win, "Are you sure? (y/N)"); - ncurses::doupdate(); - ch = ncurses::getch(); - } else { - ch = 'y' as i32; - } - if ch == 'y' as i32 { - Self::remove_files(&paths)?; - ui::wprint_msg(&view.bot_win, "Deleted files"); - ReloadDirList::reload(context.curr_tab_index, context)?; - } + let paths = curr_tab.curr_list.get_selected_paths(); + if paths.is_empty() { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + "no files selected", + )); + } + if paths.len() > 1 { + ui::wprint_msg(&view.bot_win, "Are you sure? (y/N)"); + } else { } + Self::remove_files(&paths)?; + ui::wprint_msg(&view.bot_win, "Deleted files"); + ReloadDirList::reload(context.curr_tab_index, context)?; Ok(()) } } diff --git a/src/commands/file_operations.rs b/src/commands/file_operations.rs deleted file mode 100644 index a701473..0000000 --- a/src/commands/file_operations.rs +++ /dev/null @@ -1,251 +0,0 @@ -use lazy_static::lazy_static; -use std::path; -use std::sync::{atomic, mpsc, Mutex}; -use std::thread; -use std::time; - -use crate::commands::{JoshutoCommand, JoshutoRunnable}; -use crate::context::JoshutoContext; -use crate::error::JoshutoResult; -use crate::fs::{fs_extra_extra, JoshutoDirList}; -use crate::window::JoshutoView; - -lazy_static! { - static ref SELECTED_FILES: Mutex<Option<Vec<path::PathBuf>>> = Mutex::new(None); - static ref FILE_OPERATION: Mutex<FileOp> = Mutex::new(FileOp::Copy); - static ref TAB_SRC: atomic::AtomicUsize = atomic::AtomicUsize::new(0); -} - -enum FileOp { - Cut, - Copy, -} - -struct LocalState; - -impl LocalState { - pub fn set_file_op(operation: FileOp) { - let mut data = FILE_OPERATION.lock().unwrap(); - *data = operation; - } - - pub fn set_tab_src(tab_index: usize) { - TAB_SRC.store(tab_index, atomic::Ordering::Release); - } - - pub fn repopulated_selected_files(dirlist: &JoshutoDirList) -> std::io::Result<()> { - let selected = dirlist.get_selected_paths(); - if selected.is_empty() { - Err(std::io::Error::new( - std::io::ErrorKind::Other, - "no files selected", - )) - } else { - let selected_clone: Vec<path::PathBuf> = - selected.iter().map(|p| (*p).clone()).collect(); - let mut data = SELECTED_FILES.lock().unwrap(); - *data = Some(selected_clone); - Ok(()) - } - } -} - -pub struct FileOperationThread<T, Q> { - pub tab_src: usize, - pub tab_dest: usize, - pub handle: thread::JoinHandle<std::io::Result<T>>, - pub recv: mpsc::Receiver<Q>, -} - -impl<T, Q> FileOperationThread<T, Q> { - pub fn recv_timeout( - &self, - wait_duration: &time::Duration, - ) -> Result<Q, mpsc::RecvTimeoutError> { - self.recv.recv_timeout(*wait_duration) - } -} - -#[derive(Clone, Debug)] -pub struct CutFiles; - -impl CutFiles { - pub fn new() -> Self { - CutFiles - } - pub const fn command() -> &'static str { - "cut_files" - } -} - -impl JoshutoCommand for CutFiles {} - -impl std::fmt::Display for CutFiles { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.write_str(Self::command()) - } -} - -impl JoshutoRunnable for CutFiles { - fn execute(&self, context: &mut JoshutoContext, _: &JoshutoView) -> JoshutoResult<()> { - let curr_tab = context.curr_tab_ref(); - LocalState::repopulated_selected_files(&curr_tab.curr_list)?; - LocalState::set_file_op(FileOp::Cut); - LocalState::set_tab_src(context.curr_tab_index); - Ok(()) - } -} - -#[derive(Clone, Debug)] -pub struct CopyFiles; - -impl CopyFiles { - pub fn new() -> Self { - CopyFiles - } - pub const fn command() -> &'static str { - "copy_files" - } -} - -impl JoshutoCommand for CopyFiles {} - -impl std::fmt::Display for CopyFiles { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.write_str(Self::command()) - } -} - -impl JoshutoRunnable for CopyFiles { - fn execute(&self, context: &mut JoshutoContext, _: &JoshutoView) -> JoshutoResult<()> { - let curr_tab = context.curr_tab_ref(); - LocalState::repopulated_selected_files(&curr_tab.curr_list)?; - LocalState::set_file_op(FileOp::Copy); - LocalState::set_tab_src(context.curr_tab_index); - Ok(()) - } -} - -pub struct PasteFiles { - options: fs_extra::dir::CopyOptions, -} - -impl JoshutoCommand for PasteFiles {} - -impl std::fmt::Display for PasteFiles { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!( - f, - "{} overwrite={} skip_exist={}", - Self::command(), - self.options.overwrite, - self.options.skip_exist, - ) - } -} - -impl std::fmt::Debug for PasteFiles { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.write_str(Self::command()) - } -} - -impl JoshutoRunnable for PasteFiles { - fn execute(&self, context: &mut JoshutoContext, _: &JoshutoView) -> JoshutoResult<()> { - let file_operation = FILE_OPERATION.lock().unwrap(); - - let thread = match *file_operation { - FileOp::Copy => self.copy_paste(context), - FileOp::Cut => self.cut_paste(context), - }?; - - context.threads.push(thread); - Ok(()) - } -} - -impl PasteFiles { - pub fn new(options: fs_extra::dir::CopyOptions) -> Self { - PasteFiles { options } - } - pub const fn command() -> &'static str { - "paste_files" - } - - fn cut_paste( - &self, - context: &mut JoshutoContext, - ) -> std::io::Result<FileOperationThread<u64, fs_extra::TransitProcess>> { - let paths = - SELECTED_FILES.lock().unwrap().take().ok_or_else(|| { - std::io::Error::new(std::io::ErrorKind::Other, "no files selected") - })?; - if paths.is_empty() { - return Err(std::io::Error::new( - std::io::ErrorKind::Other, - "no files selected", - )); - } - - let tab_src = TAB_SRC.load(atomic::Ordering::SeqCst); - let tab_dest = context.curr_tab_index; - let destination = context.tabs[tab_dest].curr_path.clone(); - - let options = self.options.clone(); - let (tx, rx) = mpsc::channel(); - - let handle = thread::spawn(move || { - let progress_handle = |process_info: fs_extra::TransitProcess| { - tx.send(process_info); - fs_extra::dir::TransitProcessResult::ContinueOrAbort - }; - fs_extra_extra::fs_cut_with_progress(&paths, &destination, options, progress_handle) - }); - - let thread = FileOperationThread { - tab_src, - tab_dest, - handle, - recv: rx, - }; - Ok(thread) - } - - fn copy_paste( - &self, - context: &mut JoshutoContext, - ) -> std::io::Result<FileOperationThread<u64, fs_extra::TransitProcess>> { - let paths = - SELECTED_FILES.lock().unwrap().take().ok_or_else(|| { - std::io::Error::new(std::io::ErrorKind::Other, "no files selected") - })?; - if paths.is_empty() { - return Err(std::io::Error::new( - std::io::ErrorKind::Other, - "no files selected", - )); - } - - let tab_src = TAB_SRC.load(atomic::Ordering::SeqCst); - let tab_dest = context.curr_tab_index; - let destination = context.tabs[tab_dest].curr_path.clone(); - - let options = self.options.clone(); - let (tx, rx) = mpsc::channel(); - let handle = thread::spawn(move || { - let progress_handle = |process_info: fs_extra::TransitProcess| { - tx.send(process_info); - fs_extra::dir::TransitProcessResult::ContinueOrAbort - }; - fs_extra_extra::fs_copy_with_progress(&paths, &destination, options, progress_handle) - }); - - let thread = FileOperationThread { - tab_src, - tab_dest, - handle, - recv: rx, - }; - Ok(thread) - } -} diff --git a/src/commands/file_ops/copy.rs b/src/commands/file_ops/copy.rs new file mode 100644 index 0000000..a1a562e --- /dev/null +++ b/src/commands/file_ops/copy.rs @@ -0,0 +1,36 @@ +use crate::commands::{JoshutoCommand, JoshutoRunnable}; +use crate::context::JoshutoContext; +use crate::error::JoshutoResult; +use crate::window::JoshutoView; + +use super::local_state::{FileOp, LocalState}; + +#[derive(Clone, Debug)] +pub struct CopyFiles; + +impl CopyFiles { + pub fn new() -> Self { + CopyFiles + } + pub const fn command() -> &'static str { + "copy_files" + } +} + +impl JoshutoCommand for CopyFiles {} + +impl std::fmt::Display for CopyFiles { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.write_str(Self::command()) + } +} + +impl JoshutoRunnable for CopyFiles { + fn execute(&self, context: &mut JoshutoContext, _: &JoshutoView) -> JoshutoResult<()> { + let curr_tab = context.curr_tab_ref(); + LocalState::repopulated_selected_files(&curr_tab.curr_list)?; + LocalState::set_file_op(FileOp::Copy); + LocalState::set_tab_src(context.curr_tab_index); + Ok(()) + } +} diff --git a/src/commands/file_ops/cut.rs b/src/commands/file_ops/cut.rs new file mode 100644 index 0000000..f466ca7 --- /dev/null +++ b/src/commands/file_ops/cut.rs @@ -0,0 +1,36 @@ +use crate::commands::{JoshutoCommand, JoshutoRunnable}; +use crate::context::JoshutoContext; +use crate::error::JoshutoResult; +use crate::window::JoshutoView; + +use super::local_state::{FileOp, LocalState}; + +#[derive(Clone, Debug)] +pub struct CutFiles; + +impl CutFiles { + pub fn new() -> Self { + CutFiles + } + pub const fn command() -> &'static str { + "cut_files" + } +} + +impl JoshutoCommand for CutFiles {} + +impl std::fmt::Display for CutFiles { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.write_str(Self::command()) + } +} + +impl JoshutoRunnable for CutFiles { + fn execute(&self, context: &mut JoshutoContext, _: &JoshutoView) -> JoshutoResult<()> { + let curr_tab = context.curr_tab_ref(); + LocalState::repopulated_selected_files(&curr_tab.curr_list)?; + LocalState::set_file_op(FileOp::Cut); + LocalState::set_tab_src(context.curr_tab_index); + Ok(()) + } +} diff --git a/src/commands/file_ops/local_state.rs b/src/commands/file_ops/local_state.rs new file mode 100644 index 0000000..2849893 --- /dev/null +++ b/src/commands/file_ops/local_state.rs @@ -0,0 +1,56 @@ +use lazy_static::lazy_static; + +use std::path; +use std::sync::{atomic, Mutex}; + +use crate::fs::JoshutoDirList; + +lazy_static! { + static ref SELECTED_FILES: Mutex<Option<Vec<path::PathBuf>>> = Mutex::new(None); + static ref FILE_OPERATION: Mutex<FileOp> = Mutex::new(FileOp::Copy); + static ref TAB_SRC: atomic::AtomicUsize = atomic::AtomicUsize::new(0); +} + +#[derive(Clone, Debug)] +pub enum FileOp { + Cut, + Copy, +} + +pub struct LocalState; + +impl LocalState { + pub fn set_file_op(operation: FileOp) { + let mut data = FILE_OPERATION.lock().unwrap(); + *data = operation; + } + + pub fn set_tab_src(tab_index: usize) { + TAB_SRC.store(tab_index, atomic::Ordering::Release); + } + + pub fn repopulated_selected_files(dirlist: &JoshutoDirList) -> std::io::Result<()> { + let selected = dirlist.get_selected_paths(); + if selected.is_empty() { + Err(std::io::Error::new( + std::io::ErrorKind::Other, + "no files selected", + )) + } else { + let selected_clone: Vec<path::PathBuf> = + selected.iter().map(|p| (*p).clone()).collect(); + let mut data = SELECTED_FILES.lock().unwrap(); + *data = Some(selected_clone); + Ok(()) + } + } + + pub fn take_selected_files() -> Option<Vec<path::PathBuf>> { + let paths = SELECTED_FILES.lock().unwrap().take(); + paths + } + + pub fn get_file_operation() -> FileOp { + (*FILE_OPERATION.lock().unwrap()).clone() + } +} diff --git a/src/commands/file_ops/mod.rs b/src/commands/file_ops/mod.rs new file mode 100644 index 0000000..e4a0da3 --- /dev/null +++ b/src/commands/file_ops/mod.rs @@ -0,0 +1,11 @@ +mod copy; +mod cut; +mod local_state; +mod name_resolution; +mod paste; +mod paste_copy; +mod paste_cut; + +pub use self::copy::CopyFiles; +pub use self::cut::CutFiles; +pub use self::paste::PasteFiles; diff --git a/src/commands/file_ops/name_resolution.rs b/src/commands/file_ops/name_resolution.rs new file mode 100644 index 0000000..a8e520b --- /dev/null +++ b/src/commands/file_ops/name_resolution.rs @@ -0,0 +1,15 @@ +use std::path; + +pub fn rename_filename_conflict(path: &mut path::PathBuf) { + let file_name = path.file_name().unwrap().to_os_string(); + for i in 0.. { + if !path.exists() { + break; + } + path.pop(); + + let mut file_name = file_name.clone(); + file_name.push(&format!("_{}", i)); + path.push(file_name); + } +} diff --git a/src/commands/file_ops/paste.rs b/src/commands/file_ops/paste.rs new file mode 100644 index 0000000..ba5dc43 --- /dev/null +++ b/src/commands/file_ops/paste.rs @@ -0,0 +1,55 @@ +use crate::commands::{JoshutoCommand, JoshutoRunnable}; +use crate::context::JoshutoContext; +use crate::error::JoshutoResult; +use crate::io::Options; +use crate::window::JoshutoView; + +use super::local_state::{FileOp, LocalState}; +use super::paste_copy::paste_copy; +use super::paste_cut::paste_cut; + +pub struct PasteFiles { + options: Options, +} + +impl JoshutoCommand for PasteFiles {} + +impl std::fmt::Display for PasteFiles { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!( + f, + "{} overwrite={} skip_exist={}", + Self::command(), + self.options.overwrite, + self.options.skip_exist, + ) + } +} + +impl std::fmt::Debug for PasteFiles { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.write_str(Self::command()) + } +} + +impl JoshutoRunnable for PasteFiles { + fn execute(&self, context: &mut JoshutoContext, _: &JoshutoView) -> JoshutoResult<()> { + let file_operation = LocalState::get_file_operation(); + let thread = match file_operation { + FileOp::Copy => paste_copy(context, self.options.clone()), + FileOp::Cut => paste_cut(context, self.options.clone()), + }; + let thread = thread?; + context.add_new_worker(thread); + Ok(()) + } +} + +impl PasteFiles { + pub fn new(options: Options) -> Self { + PasteFiles { options } + } + pub const fn command() -> &'static str { + "paste_files" + } +} diff --git a/src/commands/file_ops/paste_copy.rs b/src/commands/file_ops/paste_copy.rs new file mode 100644 index 0000000..26f0e5c --- /dev/null +++ b/src/commands/file_ops/paste_copy.rs @@ -0,0 +1,68 @@ +use std::fs; +use std::path::Path; +use std::sync::mpsc; +use std::thread; + +use crate::context::JoshutoContext; +use crate::io::{IOWorkerThread, Options}; +use crate::util::event::Event; + +use super::local_state::LocalState; +use super::name_resolution::rename_filename_conflict; + +pub fn recursive_copy(dest: &Path, src: &Path, options: &Options) -> std::io::Result<u64> { + let mut dest_buf = dest.to_path_buf(); + if let Some(s) = src.file_name() { + dest_buf.push(s); + } + rename_filename_conflict(&mut dest_buf); + if !src.is_dir() { + std::fs::copy(src, dest_buf) + } else { + fs::create_dir(dest_buf.as_path())?; + let mut total = 0; + for entry in fs::read_dir(src)? { + let entry = entry?; + let entry_path = entry.path(); + total += recursive_copy(dest_buf.as_path(), entry_path.as_path(), options)?; + } + Ok(total) + } +} + +pub fn paste_copy( + context: &mut JoshutoContext, + options: Options, +) -> std::io::Result<IOWorkerThread> { + let paths = LocalState::take_selected_files() + .ok_or_else(|| std::io::Error::new(std::io::ErrorKind::Other, "no files selected"))?; + if paths.is_empty() { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + "no files selected", + )); + } + + let tab_dest = context.curr_tab_index; + let dest = context.tabs[tab_dest].curr_path.clone(); + + let (tx_start, rx_start) = mpsc::channel(); + let (tx, rx) = mpsc::channel(); + let handle: thread::JoinHandle<std::io::Result<u64>> = thread::spawn(move || { + let mut total = 0; + rx_start.recv(); + for path in paths { + total += recursive_copy(dest.as_path(), path.as_path(), &options)?; + tx.send(Event::IOWorkerProgress(total)); + } + Ok(total) + }); + + let thread = IOWorkerThread { + handle, + tx_start, + rx, + }; + + Ok(thread) +} diff --git a/src/commands/file_ops/paste_cut.rs b/src/commands/file_ops/paste_cut.rs new file mode 100644 index 0000000..1177f12 --- /dev/null +++ b/src/commands/file_ops/paste_cut.rs @@ -0,0 +1,76 @@ +use std::fs; +use std::path::Path; +use std::sync::mpsc; +use std::thread; + +use crate::context::JoshutoContext; +use crate::io::{IOWorkerThread, Options}; +use crate::util::event::Event; + +use super::local_state::LocalState; +use super::name_resolution::rename_filename_conflict; + +pub fn recursive_cut(dest: &Path, src: &Path, options: &Options) -> std::io::Result<u64> { + let mut dest_buf = dest.to_path_buf(); + if let Some(s) = src.file_name() { + dest_buf.push(s); + } + rename_filename_conflict(&mut dest_buf); + if !src.is_dir() { + let metadata = src.metadata()?; + match std::fs::rename(src, dest_buf.as_path()) { + Err(_) => { + std::fs::copy(src, dest_buf.as_path())?; + std::fs::remove_file(src)?; + } + _ => {} + } + Ok(metadata.len()) + } else { + fs::create_dir(dest_buf.as_path())?; + let mut total = 0; + for entry in fs::read_dir(src)? { + let entry = entry?; + let entry_path = entry.path(); + total += recursive_cut(dest_buf.as_path(), entry_path.as_path(), options)?; + } + Ok(total) + } +} + +pub fn paste_cut( + context: &mut JoshutoContext, + options: Options, +) -> std::io::Result<IOWorkerThread> { + let paths = LocalState::take_selected_files() + .ok_or_else(|| std::io::Error::new(std::io::ErrorKind::Other, "no files selected"))?; + if paths.is_empty() { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + "no files selected", + )); + } + + let tab_dest = context.curr_tab_index; + let dest = context.tabs[tab_dest].curr_path.clone(); + + let (tx_start, rx_start) = mpsc::channel(); + let (tx, rx) = mpsc::channel(); + let handle: thread::JoinHandle<std::io::Result<u64>> = thread::spawn(move || { + let mut total = 0; + rx_start.recv(); + for path in paths { + total += recursive_cut(dest.as_path(), path.as_path(), &options)?; + tx.send(Event::IOWorkerProgress(total)); + } + Ok(total) + }); + + let thread = IOWorkerThread { + handle, + tx_start, + rx, + }; + + Ok(thread) +} diff --git a/src/commands/mod.rs b/src/commands/mod.rs index ad60802..eecf257 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -3,7 +3,7 @@ mod change_directory; mod command_line; mod cursor_move; mod delete_files; -mod file_operations; +mod file_ops; mod new_directory; mod open_file; mod parent_directory; @@ -25,7 +25,7 @@ pub use self::cursor_move::{ CursorMoveUp, }; pub use self::delete_files::DeleteFiles; -pub use self::file_operations::{CopyFiles, CutFiles, FileOperationThread, PasteFiles}; +pub use self::file_ops::{CopyFiles, CutFiles, PasteFiles}; pub use self::new_directory::NewDirectory; pub use self::open_file::{OpenFile, OpenFileWith}; pub use self::parent_directory::ParentDirectory; @@ -45,13 +45,14 @@ use std::path::PathBuf; use crate::config::JoshutoCommandMapping; use crate::context::JoshutoContext; use crate::error::{JoshutoError, JoshutoErrorKind, JoshutoResult}; +use crate::io::Options; use crate::window::JoshutoView; use crate::HOME_DIR; #[derive(Debug)] pub enum CommandKeybind { - SimpleKeybind(Box<JoshutoCommand>), + SimpleKeybind(Box<dyn JoshutoCommand>), CompositeKeybind(JoshutoCommandMapping), } @@ -70,7 +71,7 @@ pub trait JoshutoRunnable { pub trait JoshutoCommand: JoshutoRunnable + std::fmt::Display + std::fmt::Debug {} -pub fn from_args(command: String, args: Vec<String>) -> JoshutoResult<Box<JoshutoCommand>> { +pub fn from_args(command: String, args: Vec<String>) -> JoshutoResult<Box<dyn JoshutoCommand>> { match command.as_str() { "bulk_rename" => Ok(Box::new(self::BulkRename::new())), "cd" => match args.len() { @@ -156,8 +157,7 @@ pub fn from_args(command: String, args: Vec<String>) -> JoshutoResult<Box<Joshut "open_file" => Ok(Box::new(self::OpenFile::new())), "open_file_with" => Ok(Box::new(self::OpenFileWith::new())), "paste_files" => { - let mut options = fs_extra::dir::CopyOptions::new(); - options.buffer_size = 1024 * 1024 * 4; + let mut options = Options::default(); for arg in args { match arg.as_str() { "--overwrite" => options.overwrite = true, diff --git a/src/commands/open_file.rs b/src/commands/open_file.rs index 6651e3c..60dafe5 100644 --- a/src/commands/open_file.rs +++ b/src/commands/open_file.rs @@ -71,13 +71,15 @@ impl OpenFile { /* try executing with user defined entries */ if !mimetype_options.is_empty() { mimetype_options[0].execute_with(&paths)?; - } else if context.config_t.xdg_open { // try system defined entries + } else if context.config_t.xdg_open { + // try system defined entries ncurses::savetty(); ncurses::endwin(); open::that(paths[0]).unwrap(); ncurses::resetty(); ncurses::refresh(); - } else { // ask user for command + } else { + // ask user for command OpenFileWith::open_with(&paths)?; } let curr_tab = &mut context.tabs[context.curr_tab_index]; diff --git a/src/commands/quit.rs b/src/commands/quit.rs index cdeca68..77732d4 100644 --- a/src/commands/quit.rs +++ b/src/commands/quit.rs @@ -15,7 +15,7 @@ impl Quit { } pub fn quit(context: &mut JoshutoContext) -> JoshutoResult<()> { - if !context.threads.is_empty() { + if !context.worker_queue.is_empty() { Err(JoshutoError::new( JoshutoErrorKind::IOOther, String::from("operations running in background, use force_quit to quit"), diff --git a/src/config/keymap.rs b/src/config/keymap.rs index e8b4120..7d3713d 100644 --- a/src/config/keymap.rs +++ b/src/config/keymap.rs @@ -1,5 +1,4 @@ use std::collections::{hash_map::Entry, HashMap}; -use std::process::exit; use serde_derive::Deserialize; @@ -155,7 +154,7 @@ impl Flattenable<JoshutoCommandMapping> for JoshutoRawCommandMapping { let result = insert_keycommand(&mut keymaps, command, &keycodes); match result { - Ok(_) => {}, + Ok(_) => {} Err(e) => eprintln!("{}", e), } } @@ -175,7 +174,7 @@ impl ConfigStructure for JoshutoCommandMapping { fn insert_keycommand( keymap: &mut JoshutoCommandMapping, - keycommand: Box<JoshutoCommand>, + keycommand: Box<dyn JoshutoCommand>, keycodes: &[&str], ) -> Result<(), String> { let keycode_len = keycodes.len(); @@ -186,12 +185,14 @@ fn insert_keycommand( let key = match str_to_key(keycodes[0]) { Some(k) => k, - None => return Err(format!("Unknown keycode: {}", keycodes[0])) + None => return Err(format!("Unknown keycode: {}", keycodes[0])), }; if keycode_len == 1 { match keymap.entry(key) { - Entry::Occupied(_) => return Err(format!("Error: Keybindings ambiguous for {}", keycommand)), + Entry::Occupied(_) => { + return Err(format!("Error: Keybindings ambiguous for {}", keycommand)) + } Entry::Vacant(entry) => entry.insert(CommandKeybind::SimpleKeybind(keycommand)), }; return Ok(()); diff --git a/src/context.rs b/src/context.rs index 35b9da0..8f2ce4a 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,12 +1,19 @@ -use crate::commands::FileOperationThread; +use std::collections::VecDeque; +use std::sync::mpsc; + use crate::config; +use crate::io::IOWorkerThread; use crate::tab::JoshutoTab; +use crate::util::event::Events; pub struct JoshutoContext { pub exit: bool, pub curr_tab_index: usize, pub tabs: Vec<JoshutoTab>, - pub threads: Vec<FileOperationThread<u64, fs_extra::TransitProcess>>, + pub worker_queue: VecDeque<IOWorkerThread>, + pub trx: (mpsc::SyncSender<u64>, mpsc::Receiver<u64>), + + pub events: Events, pub config_t: config::JoshutoConfig, } @@ -17,7 +24,9 @@ impl JoshutoConte |