diff options
author | Jiayi Zhao <jeff.no.zhao@gmail.com> | 2020-12-26 21:45:46 -0500 |
---|---|---|
committer | Jiayi Zhao <jeff.no.zhao@gmail.com> | 2020-12-26 21:45:46 -0500 |
commit | 2b2672123d31bdcfd579916fa3fdc6cd961008a3 (patch) | |
tree | 3537f86ff7e4eb7b0851db7974138edc3e105556 | |
parent | 883a20d31a05ca0b3eac09ee1952904ec0b2131a (diff) |
add support for trashing files instead of permanently deleting
-rw-r--r-- | Cargo.lock | 10 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | config/joshuto.toml | 1 | ||||
-rw-r--r-- | src/commands/delete_files.rs | 44 | ||||
-rw-r--r-- | src/config/config.rs | 5 |
5 files changed, 56 insertions, 5 deletions
@@ -195,6 +195,7 @@ dependencies = [ "structopt", "termion", "toml", + "trash", "tui", "unicode-width", "users", @@ -592,6 +593,15 @@ dependencies = [ ] [[package]] +name = "trash" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbf511f5673142be74cd6a46cfb7e3da8d2b95bc08d2d46c072798e6ce8b5b9f" +dependencies = [ + "winapi", +] + +[[package]] name = "tui" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -21,6 +21,7 @@ serde_derive = "^1" shell-words = "^1" structopt = "^0" termion = "^1" +trash = "^1" toml = "^0" tui = "^0" unicode-width = "^0" diff --git a/config/joshuto.toml b/config/joshuto.toml index b47d547..c44ff26 100644 --- a/config/joshuto.toml +++ b/config/joshuto.toml @@ -8,6 +8,7 @@ scroll_offset = 6 show_preview = true xdg_open = false +use_trash = true max_preview_size = 2097152 # 2MB # lexical, mtime, natural diff --git a/src/commands/delete_files.rs b/src/commands/delete_files.rs index ed73e18..443875e 100644 --- a/src/commands/delete_files.rs +++ b/src/commands/delete_files.rs @@ -11,9 +11,26 @@ use crate::util::load_child::LoadChild; use super::reload; -pub fn remove_files<'a, I>(paths: I) -> std::io::Result<()> +fn trash_error_to_io_error(err: trash::Error) -> std::io::Error { + match err { + trash::Error::Unknown => std::io::Error::new(std::io::ErrorKind::Other, "Unknown Error"), + trash::Error::TargetedRoot => { + std::io::Error::new(std::io::ErrorKind::Other, "Targeted Root") + } + trash::Error::CanonicalizePath { code: _ } => { + std::io::Error::new(std::io::ErrorKind::NotFound, "Not found") + } + trash::Error::Remove { code: Some(1) } => std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Cannot move files to trash from mounted system", + ), + _ => std::io::Error::new(std::io::ErrorKind::Other, "Unknown Error"), + } +} + +pub fn remove_files<P>(paths: &[P]) -> std::io::Result<()> where - I: Iterator<Item = &'a path::Path>, + P: AsRef<path::Path>, { for path in paths { if let Ok(metadata) = fs::symlink_metadata(path) { @@ -27,6 +44,18 @@ where Ok(()) } +pub fn trash_files<P>(paths: &[P]) -> std::io::Result<()> +where + P: AsRef<path::Path>, +{ + for path in paths { + if let Err(e) = trash::delete(path) { + return Err(trash_error_to_io_error(e)); + } + } + Ok(()) +} + fn delete_files(context: &mut JoshutoContext, backend: &mut TuiBackend) -> std::io::Result<()> { let tab_index = context.tab_context_ref().get_index(); let paths = match context.tab_context_ref().curr_tab_ref().curr_list_ref() { @@ -34,7 +63,6 @@ fn delete_files(context: &mut JoshutoContext, backend: &mut TuiBackend) -> std:: None => vec![], }; let paths_len = paths.len(); - if paths_len == 0 { return Err(std::io::Error::new( std::io::ErrorKind::Other, @@ -42,6 +70,12 @@ fn delete_files(context: &mut JoshutoContext, backend: &mut TuiBackend) -> std:: )); } + let delete_func = if context.config_ref().use_trash { + trash_files + } else { + remove_files + }; + let ch = { let prompt_str = format!("Delete {} files? (Y/n)", paths_len); let mut prompt = TuiPrompt::new(&prompt_str); @@ -56,13 +90,13 @@ fn delete_files(context: &mut JoshutoContext, backend: &mut TuiBackend) -> std:: prompt.get_key(backend, context) }; if ch == Key::Char('y') { - remove_files(paths.iter().map(|p| p.as_path()))?; + delete_func(&paths)?; reload::reload(context, tab_index)?; let msg = format!("Deleted {} files", paths_len); context.push_msg(msg); } } else { - remove_files(paths.iter().map(|p| p.as_path()))?; + delete_func(&paths)?; reload::reload(context, tab_index)?; let msg = format!("Deleted {} files", paths_len); context.push_msg(msg); diff --git a/src/config/config.rs b/src/config/config.rs index c4a3fcc..0604123 100644 --- a/src/config/config.rs +++ b/src/config/config.rs @@ -69,6 +69,8 @@ pub struct JoshutoRawConfig { collapse_preview: bool, #[serde(default)] xdg_open: bool, + #[serde(default = "default_true")] + use_trash: bool, #[serde(default = "default_max_preview_size")] max_preview_size: u64, column_ratio: Option<[usize; 3]>, @@ -99,6 +101,7 @@ impl Flattenable<JoshutoConfig> for JoshutoRawConfig { show_preview: self.show_preview, collapse_preview: self.collapse_preview, xdg_open: self.xdg_open, + use_trash: self.use_trash, max_preview_size: self.max_preview_size, column_ratio, sort_option, @@ -113,6 +116,7 @@ pub struct JoshutoConfig { pub show_preview: bool, pub collapse_preview: bool, pub xdg_open: bool, + pub use_trash: bool, pub max_preview_size: u64, pub sort_option: sort::SortOption, pub column_ratio: (usize, usize, usize), @@ -135,6 +139,7 @@ impl std::default::Default for JoshutoConfig { show_preview: true, collapse_preview: true, xdg_open: false, + use_trash: true, max_preview_size: default_max_preview_size(), sort_option, column_ratio: default_column_ratio(), |