summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Zhao <jeff.no.zhao@gmail.com>2023-08-12 15:32:34 -0400
committerJeff Zhao <jeff.no.zhao@gmail.com>2023-08-12 15:32:34 -0400
commitf9ebd1055b916532e307e1b64be296d74e760d0b (patch)
treed50da96c6d04cedc7aad5975f7358e852309a1f0
parent77eac9f85535cf5e40818bb526d1f898ce4514e5 (diff)
add trash support via command line tools instead of library
-rw-r--r--Cargo.lock112
-rw-r--r--Cargo.toml4
-rw-r--r--docs/configuration/keymap.toml.md8
-rw-r--r--src/commands/delete_files.rs13
-rw-r--r--src/commands/file_ops.rs26
-rw-r--r--src/context/worker_context.rs6
-rw-r--r--src/error/error_kind.rs3
-rw-r--r--src/error/error_type.rs11
-rw-r--r--src/event/app_event.rs3
-rw-r--r--src/event/process_event.rs3
-rw-r--r--src/io/io_worker.rs72
11 files changed, 82 insertions, 179 deletions
diff --git a/Cargo.lock b/Cargo.lock
index bc0982a..961db46 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -306,15 +306,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
-name = "form_urlencoded"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
-dependencies = [
- "percent-encoding",
-]
-
-[[package]]
name = "fsevent-sys"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -391,7 +382,7 @@ dependencies = [
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
- "windows 0.48.0",
+ "windows",
]
[[package]]
@@ -404,16 +395,6 @@ dependencies = [
]
[[package]]
-name = "idna"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
-dependencies = [
- "unicode-bidi",
- "unicode-normalization",
-]
-
-[[package]]
name = "indexmap"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -497,7 +478,6 @@ dependencies = [
"structopt",
"termion",
"toml",
- "trash",
"unicode-segmentation",
"unicode-width",
"uuid",
@@ -560,15 +540,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
[[package]]
-name = "malloc_buf"
-version = "0.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
-dependencies = [
- "libc",
-]
-
-[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -657,15 +628,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
[[package]]
-name = "objc"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
-dependencies = [
- "malloc_buf",
-]
-
-[[package]]
name = "once_cell"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -710,12 +672,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
[[package]]
-name = "percent-encoding"
-version = "2.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
-
-[[package]]
name = "phf"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1160,21 +1116,6 @@ dependencies = [
]
[[package]]
-name = "tinyvec"
-version = "1.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
-dependencies = [
- "tinyvec_macros",
-]
-
-[[package]]
-name = "tinyvec_macros"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
-
-[[package]]
name = "toml"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1209,43 +1150,12 @@ dependencies = [
]
[[package]]
-name = "trash"
-version = "3.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af3663fb8f476d674b9c61d1d2796acec725bef6bec4b41402a904252a25971e"
-dependencies = [
- "chrono",
- "libc",
- "log",
- "objc",
- "once_cell",
- "scopeguard",
- "url",
- "windows 0.44.0",
-]
-
-[[package]]
-name = "unicode-bidi"
-version = "0.3.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
-
-[[package]]
name = "unicode-ident"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
[[package]]
-name = "unicode-normalization"
-version = "0.1.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
-dependencies = [
- "tinyvec",
-]
-
-[[package]]
name = "unicode-segmentation"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1258,17 +1168,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
-name = "url"
-version = "2.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb"
-dependencies = [
- "form_urlencoded",
- "idna",
- "percent-encoding",
-]
-
-[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1437,15 +1336,6 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
-version = "0.44.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b"
-dependencies = [
- "windows-targets 0.42.2",
-]
-
-[[package]]
-name = "windows"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
diff --git a/Cargo.toml b/Cargo.toml
index 3d3b796..b285561 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -32,7 +32,6 @@ signal-hook = "^0"
structopt = "^0"
termion = "^2"
toml = "^0"
-trash = { version = "^3", optional = true }
unicode-segmentation = "^1"
unicode-width = "^0"
whoami = "^1"
@@ -58,6 +57,5 @@ features = ["v4", "fast-rng", "macro-diagnostics"]
devicons = ["phf"]
file_mimetype = []
mouse = []
-recycle_bin = ["trash"]
syntax_highlight = ["ansi-to-tui"]
-default = ["devicons", "mouse", "recycle_bin", "syntax_highlight"]
+default = ["devicons", "mouse", "syntax_highlight"]
diff --git a/docs/configuration/keymap.toml.md b/docs/configuration/keymap.toml.md
index 6ef8dbf..bc50909 100644
--- a/docs/configuration/keymap.toml.md
+++ b/docs/configuration/keymap.toml.md
@@ -271,8 +271,12 @@ function joshuto() {
- `--permanently`: force permanent deletion regardless of `use_trash` value.
- will **_permanently_** delete files if `use_trash` is `false` in
[joshuto.toml](https://github.com/kamiyaa/joshuto)/wiki/Configuration#joshutotoml)
-- if `use_trash` is `true`, this might cause issues with deleting files
- on mounted filesystems such as on an external hard drive or tmpfs
+- if `use_trash` is `true`, `joshuto` will try to use
+ the following command-line tools to try to put the files in the trash can instead
+ of permanently deleting them
+ - `gio trash`
+ - `trash-put`: https://github.com/andreafrancia/trash-cli
+ - `trash`
### `rename`: rename the current file the cursor is on
diff --git a/src/commands/delete_files.rs b/src/commands/delete_files.rs
index 496bbc1..4f062bc 100644
--- a/src/commands/delete_files.rs
+++ b/src/commands/delete_files.rs
@@ -4,7 +4,7 @@ use std::sync::mpsc;
use termion::event::Key;
use crate::context::AppContext;
-use crate::error::JoshutoResult;
+use crate::error::{JoshutoError, JoshutoErrorKind, JoshutoResult};
use crate::history::DirectoryHistory;
use crate::io::{FileOperation, FileOperationOptions, IoWorkerThread};
use crate::ui::widgets::TuiPrompt;
@@ -15,7 +15,7 @@ fn delete_files(
backend: &mut AppBackend,
background: bool,
permanently: bool,
-) -> std::io::Result<()> {
+) -> JoshutoResult<()> {
let paths = context
.tab_context_ref()
.curr_tab_ref()
@@ -24,10 +24,11 @@ fn delete_files(
.unwrap_or_default();
let paths_len = paths.len();
if paths_len == 0 {
- return Err(std::io::Error::new(
- std::io::ErrorKind::Other,
- "no files selected",
- ));
+ let err = JoshutoError::new(
+ JoshutoErrorKind::InvalidParameters,
+ "no files selected".to_string(),
+ );
+ return Err(err);
}
let ch = {
diff --git a/src/commands/file_ops.rs b/src/commands/file_ops.rs
index e9d889a..f289323 100644
--- a/src/commands/file_ops.rs
+++ b/src/commands/file_ops.rs
@@ -1,5 +1,5 @@
use std::io;
-use std::process::Command;
+use std::process::{Command, Stdio};
use crate::context::{AppContext, LocalStateContext};
use crate::error::{JoshutoError, JoshutoErrorKind, JoshutoResult};
@@ -129,27 +129,27 @@ fn copy_string_to_buffer(string: String) -> JoshutoResult {
let clipboards = [
(
"wl-copy",
- format!("printf '%s' '{}' | {} 2> /dev/null", string, "wl-copy"),
- ),
- (
- "xsel",
- format!("printf '%s' '{}' | {} -ib 2> /dev/null", string, "xsel"),
- ),
- (
- "pbcopy",
- format!("printf '%s' '{}' | {} 2> /dev/null", string, "pbcopy"),
+ format!("printf '%s' '{}' | {}", string, "wl-copy"),
),
+ ("xsel", format!("printf '%s' '{}' | {} -ib", string, "xsel")),
+ ("pbcopy", format!("printf '%s' '{}' | {}", string, "pbcopy")),
(
"xclip",
format!(
- "printf '%s' '{}' | {} -selection clipboard 2> /dev/null",
+ "printf '%s' '{}' | {} -selection clipboard",
string, "xclip"
),
),
];
- for (_, command) in clipboards.iter() {
- match Command::new("sh").args(["-c", command.as_str()]).status() {
+ for (_, cmd) in clipboards.iter() {
+ let status = Command::new("sh")
+ .args(["-c", cmd.as_str()])
+ .stdout(Stdio::null())
+ .stderr(Stdio::null())
+ .status();
+
+ match status {
Ok(s) if s.success() => return Ok(()),
_ => {}
}
diff --git a/src/context/worker_context.rs b/src/context/worker_context.rs
index 5bdf055..be6329b 100644
--- a/src/context/worker_context.rs
+++ b/src/context/worker_context.rs
@@ -3,6 +3,7 @@ use std::collections::{HashMap, VecDeque};
use std::sync::mpsc;
use std::thread;
+use crate::error::{JoshutoError, JoshutoErrorKind};
use crate::event::AppEvent;
use crate::io::{FileOperationProgress, IoWorkerObserver, IoWorkerThread};
@@ -86,7 +87,10 @@ impl WorkerContext {
let _ = tx.send(AppEvent::IoWorkerResult(res));
}
Err(_) => {
- let err = std::io::Error::new(std::io::ErrorKind::Other, "Sending Error");
+ let err = JoshutoError::new(
+ JoshutoErrorKind::UnknownError,
+ "Sending Error".to_string(),
+ );
let _ = tx.send(AppEvent::IoWorkerResult(Err(err)));
}
}
diff --git a/src/error/error_kind.rs b/src/error/error_kind.rs
index 7260e2d..9afab66 100644
--- a/src/error/error_kind.rs
+++ b/src/error/error_kind.rs
@@ -14,7 +14,6 @@ pub enum JoshutoErrorKind {
ClipboardError,
TomlDeError(toml::de::Error),
- #[cfg(feature = "recycle_bin")]
TrashError,
Glob,
@@ -23,6 +22,8 @@ pub enum JoshutoErrorKind {
UnrecognizedArgument,
UnrecognizedCommand,
+
+ UnknownError,
}
impl From<io::ErrorKind> for JoshutoErrorKind {
diff --git a/src/error/error_type.rs b/src/error/error_type.rs
index 4e2eaad..a195ef6 100644
--- a/src/error/error_type.rs
+++ b/src/error/error_type.rs
@@ -56,17 +56,6 @@ impl From<std::env::VarError> for JoshutoError {
}
}
-#[cfg(feature = "recycle_bin")]
-impl From<trash::Error> for JoshutoError {
- fn from(err: trash::Error) -> Self {
- let cause = err.to_string();
- Self {
- _kind: JoshutoErrorKind::TrashError,
- _cause: cause,
- }
- }
-}
-
impl From<toml::de::Error> for JoshutoError {
fn from(err: toml::de::Error) -> Self {
let cause = err.to_string();
diff --git a/src/event/app_event.rs b/src/event/app_event.rs
index fd36224..c50a195 100644
--- a/src/event/app_event.rs
+++ b/src/event/app_event.rs
@@ -12,6 +12,7 @@ use termion::input::TermRead;
use uuid::Uuid;
+use crate::error::JoshutoResult;
use crate::fs::JoshutoDirList;
use crate::io::FileOperationProgress;
use crate::preview::preview_file::FilePreview;
@@ -24,7 +25,7 @@ pub enum AppEvent {
// background IO worker events
IoWorkerCreate,
FileOperationProgress(FileOperationProgress),
- IoWorkerResult(io::Result<FileOperationProgress>),
+ IoWorkerResult(JoshutoResult<FileOperationProgress>),
// forked process events
ChildProcessComplete(u32),
diff --git a/src/event/process_event.rs b/src/event/process_event.rs
index f215d9a..2b6b0ae 100644
--- a/src/event/process_event.rs
+++ b/src/event/process_event.rs
@@ -10,6 +10,7 @@ use uuid::Uuid;
use crate::commands::{cursor_move, parent_cursor_move, reload};
use crate::config::{AppKeyMapping, KeyMapping};
use crate::context::AppContext;
+use crate::error::JoshutoResult;
use crate::event::AppEvent;
use crate::fs::JoshutoDirList;
use crate::history::DirectoryHistory;
@@ -90,7 +91,7 @@ pub fn process_worker_progress(context: &mut AppContext, res: FileOperationProgr
pub fn process_finished_worker(
context: &mut AppContext,
- res: std::io::Result<FileOperationProgress>,
+ res: JoshutoResult<FileOperationProgress>,
) {
let worker_context = context.worker_context_mut();
let observer = worker_context.remove_worker().unwrap();
diff --git a/src/io/io_worker.rs b/src/io/io_worker.rs
index b8d5113..298c464 100644
--- a/src/io/io_worker.rs
+++ b/src/io/io_worker.rs
@@ -1,11 +1,15 @@
use std::fs;
use std::io;
use std::path;
+use std::process::{Command, Stdio};
use std::sync::mpsc;
#[cfg(unix)]
use std::os::unix;
+use crate::error::JoshutoError;
+use crate::error::JoshutoErrorKind;
+use crate::error::JoshutoResult;
use crate::io::{FileOperation, FileOperationOptions, FileOperationProgress};
use crate::util::fs::query_number_of_items;
use crate::util::name_resolution::rename_filename_conflict;
@@ -40,7 +44,7 @@ impl IoWorkerThread {
pub fn start(
&self,
tx: mpsc::Sender<FileOperationProgress>,
- ) -> io::Result<FileOperationProgress> {
+ ) -> JoshutoResult<FileOperationProgress> {
match self.kind() {
FileOperation::Cut => self.paste_cut(tx),
FileOperation::Copy => self.paste_copy(tx),
@@ -53,7 +57,7 @@ impl IoWorkerThread {
fn paste_copy(
&self,
tx: mpsc::Sender<FileOperationProgress>,
- ) -> io::Result<FileOperationProgress> {
+ ) -> JoshutoResult<FileOperationProgress> {
let (total_files, total_bytes) = query_number_of_items(&self.paths)?;
let mut progress = FileOperationProgress::new(
self.kind(),
@@ -79,7 +83,7 @@ impl IoWorkerThread {
fn paste_cut(
&self,
tx: mpsc::Sender<FileOperationProgress>,
- ) -> io::Result<FileOperationProgress> {
+ ) -> JoshutoResult<FileOperationProgress> {
let (total_files, total_bytes) = query_number_of_items(&self.paths)?;
let mut progress = FileOperationProgress::new(
self.kind(),
@@ -105,7 +109,7 @@ impl IoWorkerThread {
fn paste_link_absolute(
&self,
tx: mpsc::Sender<FileOperationProgress>,
- ) -> io::Result<FileOperationProgress> {
+ ) -> JoshutoResult<FileOperationProgress> {
let total_files = self.paths.len();
let total_bytes = total_files as u64;
let mut progress = FileOperationProgress::new(
@@ -137,7 +141,7 @@ impl IoWorkerThread {
fn paste_link_relative(
&self,
tx: mpsc::Sender<FileOperationProgress>,
- ) -> io::Result<FileOperationProgress> {
+ ) -> JoshutoResult<FileOperationProgress> {
let total_files = self.paths.len();
let total_bytes = total_files as u64;
let mut progress = FileOperationProgress::new(
@@ -190,7 +194,7 @@ impl IoWorkerThread {
fn delete(
&self,
_tx: mpsc::Sender<FileOperationProgress>,
- ) -> io::Result<FileOperationProgress> {
+ ) -> JoshutoResult<FileOperationProgress> {
let (total_files, total_bytes) = query_number_of_items(&self.paths)?;
let progress = FileOperationProgress::new(
self.kind(),
@@ -200,16 +204,12 @@ impl IoWorkerThread {
total_bytes,
total_bytes,
);
- #[cfg(feature = "recycle_bin")]
+
if self.options.permanently {
remove_files(&self.paths)?;
} else {
trash_files(&self.paths)?;
}
- #[cfg(not(feature = "recycle_bin"))]
- {
- remove_files(&self.paths)?;
- }
Ok(progress)
}
@@ -329,19 +329,6 @@ pub fn recursive_cut(
}
}
-#[cfg(feature = "recycle_bin")]
-fn trash_error_to_io_error(err: trash::Error) -> std::io::Error {
- match err {
- trash::Error::Unknown { description } => {
- std::io::Error::new(std::io::ErrorKind::Other, description)
- }
- trash::Error::TargetedRoot => {
- std::io::Error::new(std::io::ErrorKind::Other, "Targeted Root")
- }
- _ => std::io::Error::new(std::io::ErrorKind::Other, "Unknown Error"),
- }
-}
-
fn remove_files<P>(paths: &[P]) -> std::io::Result<()>
where
P: AsRef<path::Path>,
@@ -358,15 +345,42 @@ where
Ok(())
}
-#[cfg(feature = "recycle_bin")]
-fn trash_files<P>(paths: &[P]) -> std::io::Result<()>
+fn trash_files<P>(paths: &[P]) -> JoshutoResult
where
P: AsRef<path::Path>,
{
for path in paths {
- if let Err(e) = trash::delete(path) {
- return Err(trash_error_to_io_error(e));
- }
+ trash_file(path)?;
}
Ok(())
}
+
+fn trash_file<P>(file_path: P) -> JoshutoResult
+where
+ P: AsRef<path::Path>,
+{
+ let file_path_str = file_path.as_ref().as_os_str().to_string_lossy();
+
+ let clipboards = [
+ ("gio trash", format!("gio trash '{}'", file_path_str)),
+ ("trash-put", format!("trash-put '{}'", file_path_str)),
+ ("trash", format!("trash '{}'", file_path_str)),
+ ];
+
+ for (_, cmd) in clipboards.iter() {
+ let status = Command::new("sh")
+ .args(["-c", cmd.as_str()])
+ .stdout(Stdio::null())
+ .stderr(Stdio::null())
+ .status();
+
+ match status {
+ Ok(s) if s.success() => return Ok(()),
+ _ => {}
+ }
+ }
+ Err(JoshutoError::new(
+ JoshutoErrorKind::TrashError,
+ "Failed to trash file".to_string(),
+ ))
+}