From 8ef1082a4ca6cf018ccb1ab7da7c96096c2ee303 Mon Sep 17 00:00:00 2001 From: RipleyTom Date: Sat, 18 Jul 2026 19:13:12 +0200 Subject: [PATCH 1/2] fix: not all files directory are trash --- src/tab.rs | 22 ++++++++++++++++++---- src/trash.rs | 25 +++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/tab.rs b/src/tab.rs index b3a0ede..33e3339 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -939,11 +939,24 @@ fn item_from_trash_child( metadata: fs::Metadata, sizes: IconSizes, ) -> Option { - let original_path = crate::trash::original_path_for_trash_child(&path)?; + let Some(original_path) = crate::trash::original_path_for_trash_child(&path) else { + log::warn!( + "failed to resolve original path for trash item {}, skipping entry", + path.display() + ); + return None; + }; + let Some(original_parent) = original_path.parent() else { + log::warn!( + "trash item {} has no original parent, skipping entry", + path.display() + ); + return None; + }; let entry = trash::TrashItem { id: path.as_os_str().to_os_string(), name: std::ffi::OsString::from(&name), - original_parent: original_path.parent()?.to_path_buf(), + original_parent: original_parent.to_path_buf(), time_deleted: 0, }; let size = if metadata.is_dir() { @@ -1033,6 +1046,7 @@ pub fn scan_path(tab_path: &PathBuf, sizes: IconSizes) -> Vec { if !remote_scannable { match fs::read_dir(tab_path) { Ok(entries) => { + let trash = crate::trash::is_trash_path(tab_path); items = entries .filter_map(|entry_res| { let entry = entry_res @@ -1073,7 +1087,6 @@ pub fn scan_path(tab_path: &PathBuf, sizes: IconSizes) -> Vec { }) .ok()?; - let trash = crate::trash::is_trash_path(tab_path); if trash { item_from_trash_child(path, name, metadata, sizes) } else { @@ -7003,7 +7016,8 @@ impl Tab { let path = path.clone(); // Acquire semaphore permit - _ = THUMB_SEMAPHORE.acquire().await; + let _permit = + THUMB_SEMAPHORE.acquire().await.unwrap(); tokio::task::spawn_blocking(move || { let start = Instant::now(); diff --git a/src/trash.rs b/src/trash.rs index d8bccca..bb9f99a 100644 --- a/src/trash.rs +++ b/src/trash.rs @@ -2,6 +2,7 @@ use cosmic::widget; use regex::Regex; use std::collections::HashSet; use std::path::{Path, PathBuf}; +use std::sync::LazyLock; use crate::config::IconSizes; use crate::tab::{Item, SearchItem}; @@ -89,7 +90,7 @@ pub fn trash_item_path(item: &trash::TrashItem) -> Option { /// - Read `~/.local/share/Trash/info/folder.trashinfo` to get the original path /// - Compute: `/sub/file.txt` pub fn original_path_for_trash_child(p: &Path) -> Option { - let files = p.ancestors().find(|a| a.ends_with("files"))?; + let files = trash_files_dir(p)?; let root = files.parent()?; let top = p.strip_prefix(files).ok()?.components().next()?; let info = @@ -103,9 +104,29 @@ pub fn original_path_for_trash_child(p: &Path) -> Option { Some(result) } +static TRASH_FOLDERS: LazyLock> = LazyLock::new(|| { + Trash::folders().unwrap_or_else(|e| { + log::warn!("failed to list trash folders: {}", e); + HashSet::new() + }) +}); + +fn is_trash_root(root: &Path) -> bool { + if TRASH_FOLDERS.is_empty() { + root.join("info").is_dir() + } else { + TRASH_FOLDERS.contains(root) + } +} + +fn trash_files_dir(path: &Path) -> Option<&Path> { + path.ancestors() + .find(|a| a.ends_with("files") && a.parent().is_some_and(is_trash_root)) +} + /// Check whether a path is inside any trash `files/` directory. pub fn is_trash_path(path: &Path) -> bool { - path.ancestors().any(|a| a.ends_with("files")) + trash_files_dir(path).is_some() } pub struct Trash; From dc36bdc8d3805b2b938b1337b4238d8a6f1178f1 Mon Sep 17 00:00:00 2001 From: RipleyTom Date: Sun, 19 Jul 2026 14:03:04 +0200 Subject: [PATCH 2/2] fix: fixes original_path_for_trash_child --- src/trash.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/trash.rs b/src/trash.rs index bb9f99a..d33fd69 100644 --- a/src/trash.rs +++ b/src/trash.rs @@ -93,8 +93,9 @@ pub fn original_path_for_trash_child(p: &Path) -> Option { let files = trash_files_dir(p)?; let root = files.parent()?; let top = p.strip_prefix(files).ok()?.components().next()?; - let info = - std::fs::read_to_string(root.join("info").join(top).with_extension("trashinfo")).ok()?; + let mut trashinfo_name = top.as_os_str().to_os_string(); + trashinfo_name.push(".trashinfo"); + let info = std::fs::read_to_string(root.join("info").join(trashinfo_name)).ok()?; let orig = percent_decode(info.lines().find_map(|l| l.strip_prefix("Path="))?.trim())?; let rel = p.strip_prefix(files.join(top)).ok()?; let mut result = PathBuf::from(&orig);