From 1e25e7dd69b109bb71359ee0e0288e82e90694be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vuka=C5=A1in=20Vojinovi=C4=87?= <150025636+git-f0x@users.noreply.github.com> Date: Sat, 24 Jan 2026 17:03:31 +0100 Subject: [PATCH 1/2] chore: clippy --- src/app.rs | 748 ++++++++++++++++++------------------- src/dialog.rs | 296 ++++++++------- src/large_image.rs | 26 +- src/localize.rs | 8 +- src/mime_app.rs | 4 +- src/mounter/gvfs.rs | 26 +- src/mouse_area.rs | 166 ++++---- src/operation/mod.rs | 8 +- src/operation/recursive.rs | 8 +- src/tab.rs | 621 +++++++++++++++--------------- src/thumbnail_cacher.rs | 8 +- 11 files changed, 938 insertions(+), 981 deletions(-) diff --git a/src/app.rs b/src/app.rs index 869c426..a85b098 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1230,11 +1230,11 @@ impl App { }; for item in items { if item.selected { - if let Some(path) = item.path_opt() { - if op_sel.selected.contains(path) || op_sel.ignored.contains(path) { - // Ignore if path in selected or ignored paths - continue; - } + if let Some(path) = item.path_opt() + && (op_sel.selected.contains(path) || op_sel.ignored.contains(path)) + { + // Ignore if path in selected or ignored paths + continue; } // Return if there is a previous selection not matching @@ -1891,50 +1891,47 @@ impl App { children.push(item.preview_view(Some(&self.mime_app_cache), military_time)); } PreviewKind::Location(location) => { - if let Some(tab) = self.tab_model.data::(entity) { - if let Some(items) = tab.items_opt() { - for item in items { - if item.location_opt.as_ref() == Some(location) { - children.push( - item.preview_view(Some(&self.mime_app_cache), military_time), - ); - // Only show one property view to avoid issues like hangs when generating - // preview images on thousands of files - break; - } + if let Some(tab) = self.tab_model.data::(entity) + && let Some(items) = tab.items_opt() + { + for item in items { + if item.location_opt.as_ref() == Some(location) { + children + .push(item.preview_view(Some(&self.mime_app_cache), military_time)); + // Only show one property view to avoid issues like hangs when generating + // preview images on thousands of files + break; } } } } PreviewKind::Selected => { - if let Some(tab) = self.tab_model.data::(entity) { - if let Some(items) = tab.items_opt() { - let preview_opt = { - let mut selected = items.iter().filter(|item| item.selected); + if let Some(tab) = self.tab_model.data::(entity) + && let Some(items) = tab.items_opt() + { + let preview_opt = { + let mut selected = items.iter().filter(|item| item.selected); - match (selected.next(), selected.next()) { - // At least two selected items - (Some(_), Some(_)) => Some(tab.multi_preview_view()), - // Exactly one selected item - (Some(item), None) => Some( - item.preview_view(Some(&self.mime_app_cache), military_time), - ), - // No selected items - _ => None, + match (selected.next(), selected.next()) { + // At least two selected items + (Some(_), Some(_)) => Some(tab.multi_preview_view()), + // Exactly one selected item + (Some(item), None) => { + Some(item.preview_view(Some(&self.mime_app_cache), military_time)) } - }; - - if let Some(preview) = preview_opt { - children.push(preview); + // No selected items + _ => None, } + }; - if children.is_empty() { - if let Some(item) = &tab.parent_item_opt { - children.push( - item.preview_view(Some(&self.mime_app_cache), military_time), - ); - } - } + if let Some(preview) = preview_opt { + children.push(preview); + } + + if children.is_empty() + && let Some(item) = &tab.parent_item_opt + { + children.push(item.preview_view(Some(&self.mime_app_cache), military_time)); } } } @@ -2062,11 +2059,11 @@ impl App { .map(|favorite| { if let Favorite::Path(path) = favorite { for (from, to) in path_changes.iter().map(|(f, t)| (f.as_ref(), t.as_ref())) { - if path.starts_with(from) { - if let Ok(relative) = path.strip_prefix(from) { - favorites_changed = true; - return Favorite::from_path(to.join(relative)); - } + if path.starts_with(from) + && let Ok(relative) = path.strip_prefix(from) + { + favorites_changed = true; + return Favorite::from_path(to.join(relative)); } } } @@ -2235,17 +2232,16 @@ impl Application for App { let mut commands = vec![app.update_config()]; for location in flags.locations { - if let Some(path) = location.path_opt() { - if path.is_file() { - if let Some(parent) = path.parent() { - commands.push(app.open_tab( - Location::Path(parent.to_path_buf()), - true, - Some(vec![path.clone()]), - )); - continue; - } - } + if let Some(path) = location.path_opt() + && path.is_file() + && let Some(parent) = path.parent() + { + commands.push(app.open_tab( + Location::Path(parent.to_path_buf()), + true, + Some(vec![path.clone()]), + )); + continue; } commands.push(app.open_tab(location, true, None)); } @@ -2405,14 +2401,13 @@ impl Application for App { // TODO do we need to choose the correct mounter? self.mounter_items.keys().copied().next() }) + && let Some(mounter) = MOUNTERS.get(&key) { - if let Some(mounter) = MOUNTERS.get(&key) { - return mounter.network_drive(uri.clone()).map(move |()| { - cosmic::Action::App(Message::NetworkDriveOpenEntityAfterMount { - entity, - }) - }); - } + return mounter.network_drive(uri.clone()).map(move |()| { + cosmic::Action::App(Message::NetworkDriveOpenEntityAfterMount { + entity, + }) + }); } log::warn!( @@ -2468,12 +2463,12 @@ impl Application for App { return self.update(message); } } - if let Some(data) = self.nav_model.data::(entity) { - if let Some(mounter) = MOUNTERS.get(&data.0) { - return mounter - .mount(data.1.clone()) - .map(|()| cosmic::action::none()); - } + if let Some(data) = self.nav_model.data::(entity) + && let Some(mounter) = MOUNTERS.get(&data.0) + { + return mounter + .mount(data.1.clone()) + .map(|()| cosmic::action::none()); } Task::none() } @@ -2505,11 +2500,11 @@ impl Application for App { } // Close gallery mode if open - if let Some(tab) = self.tab_model.data_mut::(entity) { - if tab.gallery { - tab.gallery = false; - return Task::none(); - } + if let Some(tab) = self.tab_model.data_mut::(entity) + && tab.gallery + { + tab.gallery = false; + return Task::none(); } // Close menus and context panes in order per message @@ -2635,22 +2630,22 @@ impl Application for App { } Message::Compress(entity_opt) => { let paths: Box<[_]> = self.selected_paths(entity_opt).collect(); - if let Some(current_path) = paths.first() { - if let Some(destination) = current_path.parent().zip(current_path.file_stem()) { - let to = destination.0.to_path_buf(); - let name = destination.1.to_str().unwrap_or_default().to_string(); - let archive_type = ArchiveType::default(); - return self.push_dialog( - DialogPage::Compress { - paths, - to, - name, - archive_type, - password: None, - }, - Some(self.dialog_text_input.clone()), - ); - } + if let Some(current_path) = paths.first() + && let Some(destination) = current_path.parent().zip(current_path.file_stem()) + { + let to = destination.0.to_path_buf(); + let name = destination.1.to_str().unwrap_or_default().to_string(); + let archive_type = ArchiveType::default(); + return self.push_dialog( + DialogPage::Compress { + paths, + to, + name, + archive_type, + password: None, + }, + Some(self.dialog_text_input.clone()), + ); } } Message::Config(config) => { @@ -2664,10 +2659,10 @@ impl Application for App { } } Message::Copy(entity_opt) => { - if let Some(entity) = entity_opt { - if let Some(tab) = self.tab_model.data_mut::(entity) { - tab.refresh_cut(&[]); - } + if let Some(entity) = entity_opt + && let Some(tab) = self.tab_model.data_mut::(entity) + { + tab.refresh_cut(&[]); } let paths = self.selected_paths(entity_opt); let contents = ClipboardCopy::new(ClipboardKind::Copy, paths); @@ -2975,22 +2970,21 @@ impl Application for App { DialogResult::Cancel => {} DialogResult::Open(selected_paths) => { let mut archive_paths = None; - if let Some(file_dialog) = &self.file_dialog_opt { - if let Some(window) = self.windows.remove(&file_dialog.window_id()) { - if let WindowKind::FileDialog(paths) = window.kind { - archive_paths = paths; - } - } + if let Some(file_dialog) = &self.file_dialog_opt + && let Some(window) = self.windows.remove(&file_dialog.window_id()) + && let WindowKind::FileDialog(paths) = window.kind + { + archive_paths = paths; } - if let Some(archive_paths) = archive_paths { - if !selected_paths.is_empty() { - self.file_dialog_opt = None; - return self.operation(Operation::Extract { - paths: archive_paths, - to: selected_paths[0].clone(), - password: None, - }); - } + if let Some(archive_paths) = archive_paths + && !selected_paths.is_empty() + { + self.file_dialog_opt = None; + return self.operation(Operation::Extract { + paths: archive_paths, + to: selected_paths[0].clone(), + password: None, + }); } } } @@ -3020,56 +3014,53 @@ impl Application for App { && !modifiers.control() && !modifiers.alt() && matches!(key, Key::Character(_)) + && let Some(text) = text { - if let Some(text) = text { - match self.config.type_to_search { - TypeToSearch::Recursive => { - let mut term = - self.search_get().unwrap_or_default().to_string(); - term.push_str(&text); - return self.search_set_active(Some(term)); - } - TypeToSearch::EnterPath => { - if let Some(tab) = self.tab_model.data_mut::(entity) { - let location = tab - .edit_location - .as_ref() - .map_or_else(|| &tab.location, |x| &x.location); - // Try to add text to end of location - if let Location::Network(uri, ..) = location { - let mut uri_string = uri.clone(); - uri_string.push_str(&text); - tab.edit_location = - Some(location.with_uri(uri_string).into()); - } else if let Some(path) = location.path_opt() { - let mut path_string = - path.to_string_lossy().into_owned(); - path_string.push_str(&text); - tab.edit_location = - Some(location.with_path(path_string.into()).into()); - } + match self.config.type_to_search { + TypeToSearch::Recursive => { + let mut term = self.search_get().unwrap_or_default().to_string(); + term.push_str(&text); + return self.search_set_active(Some(term)); + } + TypeToSearch::EnterPath => { + if let Some(tab) = self.tab_model.data_mut::(entity) { + let location = tab + .edit_location + .as_ref() + .map_or_else(|| &tab.location, |x| &x.location); + // Try to add text to end of location + if let Location::Network(uri, ..) = location { + let mut uri_string = uri.clone(); + uri_string.push_str(&text); + tab.edit_location = + Some(location.with_uri(uri_string).into()); + } else if let Some(path) = location.path_opt() { + let mut path_string = path.to_string_lossy().into_owned(); + path_string.push_str(&text); + tab.edit_location = + Some(location.with_path(path_string.into()).into()); } } - TypeToSearch::SelectByPrefix => { - // Reset buffer if timeout elapsed - if let Some(last_key) = self.type_select_last_key { - if last_key.elapsed() >= tab::TYPE_SELECT_TIMEOUT { - self.type_select_prefix.clear(); - } - } + } + TypeToSearch::SelectByPrefix => { + // Reset buffer if timeout elapsed + if let Some(last_key) = self.type_select_last_key + && last_key.elapsed() >= tab::TYPE_SELECT_TIMEOUT + { + self.type_select_prefix.clear(); + } - // Accumulate character and select - self.type_select_prefix.push_str(&text.to_lowercase()); - self.type_select_last_key = Some(Instant::now()); + // Accumulate character and select + self.type_select_prefix.push_str(&text.to_lowercase()); + self.type_select_last_key = Some(Instant::now()); - if let Some(tab) = self.tab_model.data_mut::(entity) { - tab.select_by_prefix(&self.type_select_prefix); - if let Some(offset) = tab.select_focus_scroll() { - return scrollable::scroll_to( - tab.scrollable_id.clone(), - offset, - ); - } + if let Some(tab) = self.tab_model.data_mut::(entity) { + tab.select_by_prefix(&self.type_select_prefix); + if let Some(offset) = tab.select_focus_scroll() { + return scrollable::scroll_to( + tab.scrollable_id.clone(), + offset, + ); } } } @@ -3106,21 +3097,22 @@ impl Application for App { let mut unmounted = Vec::new(); if let Some(old_items) = self.mounter_items.get(&mounter_key) { for old_item in old_items { - if let Some(old_path) = old_item.path() { - if old_item.is_mounted() { - let mut still_mounted = false; - for item in &mounter_items { - if let Some(path) = item.path() { - if path == old_path && item.is_mounted() { - still_mounted = true; - break; - } - } - } - if !still_mounted { - unmounted.push(old_path); + if let Some(old_path) = old_item.path() + && old_item.is_mounted() + { + let mut still_mounted = false; + for item in &mounter_items { + if let Some(path) = item.path() + && path == old_path + && item.is_mounted() + { + still_mounted = true; + break; } } + if !still_mounted { + unmounted.push(old_path); + } } } } @@ -3254,17 +3246,17 @@ impl Application for App { } Message::NewItem(entity_opt, dir) => { let entity = entity_opt.unwrap_or_else(|| self.tab_model.active()); - if let Some(tab) = self.tab_model.data_mut::(entity) { - if let Some(path) = tab.location.path_opt() { - return Task::batch([ - self.dialog_pages.push_back(DialogPage::NewItem { - parent: path.clone(), - name: String::new(), - dir, - }), - widget::text_input::focus(self.dialog_text_input.clone()), - ]); - } + if let Some(tab) = self.tab_model.data_mut::(entity) + && let Some(path) = tab.location.path_opt() + { + return Task::batch([ + self.dialog_pages.push_back(DialogPage::NewItem { + parent: path.clone(), + name: String::new(), + dir, + }), + widget::text_input::focus(self.dialog_text_input.clone()), + ]); } } #[cfg(feature = "notify")] @@ -3277,57 +3269,57 @@ impl Application for App { let mut needs_reload = Vec::new(); let entities: Box<[_]> = self.tab_model.iter().collect(); for entity in entities { - if let Some(tab) = self.tab_model.data_mut::(entity) { - if let Some(path) = tab.location.path_opt() { - let mut contains_change = false; - for event in &events { - for event_path in &event.paths { - if event_path.starts_with(path) { - if let notify::EventKind::Modify( - notify::event::ModifyKind::Metadata(_) - | notify::event::ModifyKind::Data(_), - ) = event.kind - { - // If metadata or data changed, find the matching item and reload it - //TODO: this could be further optimized by looking at what exactly changed - if let Some(items) = &mut tab.items_opt { - for item in items.iter_mut() { - if item.path_opt() == Some(event_path) { - //TODO: reload more, like mime types? - match fs::metadata(event_path) { - Ok(new_metadata) => { - if let ItemMetadata::Path { - metadata, - .. - } = &mut item.metadata - { - *metadata = new_metadata; - } - } - - Err(err) => { - log::warn!( - "failed to reload metadata for {}: {}", - path.display(), - err - ); + if let Some(tab) = self.tab_model.data_mut::(entity) + && let Some(path) = tab.location.path_opt() + { + let mut contains_change = false; + for event in &events { + for event_path in &event.paths { + if event_path.starts_with(path) { + if let notify::EventKind::Modify( + notify::event::ModifyKind::Metadata(_) + | notify::event::ModifyKind::Data(_), + ) = event.kind + { + // If metadata or data changed, find the matching item and reload it + //TODO: this could be further optimized by looking at what exactly changed + if let Some(items) = &mut tab.items_opt { + for item in items.iter_mut() { + if item.path_opt() == Some(event_path) { + //TODO: reload more, like mime types? + match fs::metadata(event_path) { + Ok(new_metadata) => { + if let ItemMetadata::Path { + metadata, + .. + } = &mut item.metadata + { + *metadata = new_metadata; } } - //TODO item.thumbnail_opt = + + Err(err) => { + log::warn!( + "failed to reload metadata for {}: {}", + path.display(), + err + ); + } } + //TODO item.thumbnail_opt = } } - } else { - // Any other events reload the whole tab - contains_change = true; - break; } + } else { + // Any other events reload the whole tab + contains_change = true; + break; } } } - if contains_change { - needs_reload.push((entity, tab.location.clone())); - } + } + if contains_change { + needs_reload.push((entity, tab.location.clone())); } } } @@ -3351,20 +3343,21 @@ impl Application for App { if let Some(terminal) = self.mime_app_cache.terminal() { let mut paths = Box::from([]); let entity = entity_opt.unwrap_or_else(|| self.tab_model.active()); - if let Some(tab) = self.tab_model.data_mut::(entity) { - if let Some(path) = tab.location.path_opt() { - if let Some(items) = tab.items_opt() { - paths = - items - .iter() - .filter_map(|item| { - if item.selected { item.path_opt() } else { None } - }) - .collect(); - } - if paths.is_empty() { - paths = Box::from([path]); - } + if let Some(tab) = self.tab_model.data_mut::(entity) + && let Some(path) = tab.location.path_opt() + { + if let Some(items) = tab.items_opt() { + paths = items + .iter() + .filter_map( + |item| { + if item.selected { item.path_opt() } else { None } + }, + ) + .collect(); + } + if paths.is_empty() { + paths = Box::from([path]); } } for path in paths { @@ -3454,30 +3447,30 @@ impl Application for App { }, Message::OpenWithDialog(entity_opt) => { let entity = entity_opt.unwrap_or_else(|| self.tab_model.active()); - if let Some(tab) = self.tab_model.data::(entity) { - if let Some(items) = tab.items_opt() { - for item in items { - if !item.selected { - continue; - } - let Some(path) = item.path_opt() else { - continue; - }; - return self.push_dialog( - DialogPage::OpenWith { - path: path.clone(), - mime: item.mime.clone(), - selected: 0, - store_opt: "x-scheme-handler/mime" - .parse::() - .ok() - .and_then(|mime| { - self.mime_app_cache.get(&mime).first().cloned() - }), - }, - Some(CONFIRM_OPEN_WITH_BUTTON_ID.clone()), - ); + if let Some(tab) = self.tab_model.data::(entity) + && let Some(items) = tab.items_opt() + { + for item in items { + if !item.selected { + continue; } + let Some(path) = item.path_opt() else { + continue; + }; + return self.push_dialog( + DialogPage::OpenWith { + path: path.clone(), + mime: item.mime.clone(), + selected: 0, + store_opt: "x-scheme-handler/mime" + .parse::() + .ok() + .and_then(|mime| { + self.mime_app_cache.get(&mime).first().cloned() + }), + }, + Some(CONFIRM_OPEN_WITH_BUTTON_ID.clone()), + ); } } } @@ -3488,19 +3481,18 @@ impl Application for App { } Message::Paste(entity_opt) => { let entity = entity_opt.unwrap_or_else(|| self.tab_model.active()); - if let Some(tab) = self.tab_model.data_mut::(entity) { - if let Some(path) = tab.location.path_opt() { - let to = path.clone(); - return clipboard::read_data::().map(move |contents_opt| { - match contents_opt { - Some(contents) => cosmic::action::app(Message::PasteContents( - to.clone(), - contents, - )), - None => cosmic::action::none(), + if let Some(tab) = self.tab_model.data_mut::(entity) + && let Some(path) = tab.location.path_opt() + { + let to = path.clone(); + return clipboard::read_data::().map(move |contents_opt| { + match contents_opt { + Some(contents) => { + cosmic::action::app(Message::PasteContents(to.clone(), contents)) } - }); - } + None => cosmic::action::none(), + } + }); } } Message::PasteContents(to, mut contents) => { @@ -3733,38 +3725,38 @@ impl Application for App { } Message::Rename(entity_opt) => { let entity = entity_opt.unwrap_or_else(|| self.tab_model.active()); - if let Some(tab) = self.tab_model.data_mut::(entity) { - if let Some(items) = tab.items_opt() { - let selected: Box<[_]> = items - .iter() - .filter_map(|item| { - if item.selected { - item.path_opt().cloned() - } else { - None - } + if let Some(tab) = self.tab_model.data_mut::(entity) + && let Some(items) = tab.items_opt() + { + let selected: Box<[_]> = items + .iter() + .filter_map(|item| { + if item.selected { + item.path_opt().cloned() + } else { + None + } + }) + .collect(); + if !selected.is_empty() { + //TODO: batch rename + let tasks = selected + .into_iter() + .filter_map(|path| { + let parent = path.parent()?.to_path_buf(); + let name = path.file_name()?.to_str()?.to_string(); + let dir = path.is_dir(); + Some(self.dialog_pages.push_back(DialogPage::RenameItem { + from: path, + parent, + name, + dir, + })) }) - .collect(); - if !selected.is_empty() { - //TODO: batch rename - let tasks = selected - .into_iter() - .filter_map(|path| { - let parent = path.parent()?.to_path_buf(); - let name = path.file_name()?.to_str()?.to_string(); - let dir = path.is_dir(); - Some(self.dialog_pages.push_back(DialogPage::RenameItem { - from: path, - parent, - name, - dir, - })) - }) - .chain(std::iter::once(widget::text_input::focus( - self.dialog_text_input.clone(), - ))); - return Task::batch(tasks); - } + .chain(std::iter::once(widget::text_input::focus( + self.dialog_text_input.clone(), + ))); + return Task::batch(tasks); } } } @@ -3787,15 +3779,15 @@ impl Application for App { Message::RestoreFromTrash(entity_opt) => { let mut trash_items = Vec::new(); let entity = entity_opt.unwrap_or_else(|| self.tab_model.active()); - if let Some(tab) = self.tab_model.data_mut::(entity) { - if let Some(items) = tab.items_opt() { - for item in items { - if item.selected { - if let ItemMetadata::Trash { entry, .. } = &item.metadata { - trash_items.push(entry.clone()); - } else { - //TODO: error on trying to restore non-trash file? - } + if let Some(tab) = self.tab_model.data_mut::(entity) + && let Some(items) = tab.items_opt() + { + for item in items { + if item.selected { + if let ItemMetadata::Trash { entry, .. } = &item.metadata { + trash_items.push(entry.clone()); + } else { + //TODO: error on trying to restore non-trash file? } } } @@ -3840,13 +3832,13 @@ impl Application for App { // Close old context menu let active = self.tab_model.active(); - if let Some(tab) = self.tab_model.data_mut::(active) { - if tab.context_menu.is_some() { - tasks.push(self.update(Message::TabMessage( - Some(active), - tab::Message::ContextMenu(None, None), - ))); - } + if let Some(tab) = self.tab_model.data_mut::(active) + && tab.context_menu.is_some() + { + tasks.push(self.update(Message::TabMessage( + Some(active), + tab::Message::ContextMenu(None, None), + ))); } // Activate new tab @@ -4042,10 +4034,10 @@ impl Application for App { // Destroy previous popup let mut window_ids = Vec::new(); for (window_id, window) in &self.windows { - if let WindowKind::ContextMenu(e, _) = &window.kind { - if *e == entity { - window_ids.push(*window_id); - } + if let WindowKind::ContextMenu(e, _) = &window.kind + && *e == entity + { + window_ids.push(*window_id); } } for window_id in window_ids { @@ -4453,12 +4445,12 @@ impl Application for App { } } Message::NavBarClose(entity) => { - if let Some(data) = self.nav_model.data::(entity) { - if let Some(mounter) = MOUNTERS.get(&data.0) { - return mounter - .unmount(data.1.clone()) - .map(|()| cosmic::action::none()); - } + if let Some(data) = self.nav_model.data::(entity) + && let Some(mounter) = MOUNTERS.get(&data.0) + { + return mounter + .unmount(data.1.clone()) + .map(|()| cosmic::action::none()); } } Message::NavBarContext(entity) => { @@ -4755,15 +4747,14 @@ impl Application for App { if let Some(p) = paths.next() { { for (k, mounter_items) in &self.mounter_items { - if let Some(mounter) = MOUNTERS.get(k) { - if let Some(item) = mounter_items + if let Some(mounter) = MOUNTERS.get(k) + && let Some(item) = mounter_items .iter() .find(|&item| item.path().is_some_and(|path| path == p)) - { - return mounter - .unmount(item.clone()) - .map(|()| cosmic::action::none()); - } + { + return mounter + .unmount(item.clone()) + .map(|()| cosmic::action::none()); } } } @@ -4786,15 +4777,14 @@ impl Application for App { } Message::SaveSortNames => { self.must_save_sort_names = false; - if let Some(state_handler) = self.state_handler.as_ref() { - if let Err(err) = state_handler + if let Some(state_handler) = self.state_handler.as_ref() + && let Err(err) = state_handler .set::<&FxOrderMap>( "sort_names", &self.state.sort_names, ) - { - log::warn!("Failed to save sort names: {err:?}"); - } + { + log::warn!("Failed to save sort names: {err:?}"); } } Message::NetworkDriveOpenEntityAfterMount { entity } => { @@ -4890,13 +4880,13 @@ impl Application for App { fn dialog(&self) -> Option> { //TODO: should gallery view just be a dialog? let entity = self.tab_model.active(); - if let Some(tab) = self.tab_model.data::(entity) { - if tab.gallery { - return Some( - tab.gallery_view() - .map(move |x| Message::TabMessage(Some(entity), x)), - ); - } + if let Some(tab) = self.tab_model.data::(entity) + && tab.gallery + { + return Some( + tab.gallery_view() + .map(move |x| Message::TabMessage(Some(entity), x)), + ); } let dialog_page = self.dialog_pages.front()?; @@ -5778,19 +5768,19 @@ impl Application for App { let mut tab_column = widget::column::with_capacity(4); - if self.core.is_condensed() { - if let Some(term) = self.search_get() { - tab_column = tab_column.push( - widget::container( - widget::text_input::search_input("", term) - .width(Length::Fill) - .id(self.search_id.clone()) - .on_clear(Message::SearchClear) - .on_input(Message::SearchInput), - ) - .padding(space_xxs), - ); - } + if self.core.is_condensed() + && let Some(term) = self.search_get() + { + tab_column = tab_column.push( + widget::container( + widget::text_input::search_input("", term) + .width(Length::Fill) + .id(self.search_id.clone()) + .on_clear(Message::SearchClear) + .on_input(Message::SearchInput), + ) + .padding(space_xxs), + ); } if self.tab_model.len() > 1 { @@ -6088,14 +6078,14 @@ impl Application for App { let should_rescan = events.iter().any(|event| !event.kind.is_access()); - if should_rescan { - if let Err(e) = futures::executor::block_on(async { + if should_rescan + && let Err(e) = futures::executor::block_on(async { output.send(Message::RescanTrash).await - }) { - log::warn!( - "trash needs to be rescanned but sending message failed: {e:?}" - ); - } + }) + { + log::warn!( + "trash needs to be rescanned but sending message failed: {e:?}" + ); } } Err(e) => { @@ -6173,14 +6163,12 @@ impl Application for App { || kind.is_modify() || kind.is_remove() || kind.is_other() + }) && let Err(e) = futures::executor::block_on(async { + output.send(Message::RescanRecents).await }) { - if let Err(e) = futures::executor::block_on(async { - output.send(Message::RescanRecents).await - }) { - log::warn!( - "open recents tabs need to be updated but sending message failed: {e:?}" - ); - } + log::warn!( + "open recents tabs need to be updated but sending message failed: {e:?}" + ); } } Err(e) => { @@ -6297,17 +6285,16 @@ impl Application for App { let mut selected_previews = Vec::new(); match self.mode { Mode::App => { - if self.core.window.show_context { - if let ContextPage::Preview(entity_opt, PreviewKind::Selected) = + if self.core.window.show_context + && let ContextPage::Preview(entity_opt, PreviewKind::Selected) = self.context_page - { - selected_previews - .push(Some(entity_opt.unwrap_or_else(|| self.tab_model.active()))); - } + { + selected_previews + .push(Some(entity_opt.unwrap_or_else(|| self.tab_model.active()))); } } Mode::Desktop => { - for window_kind in self.windows.iter().map(|(_, window)| &window.kind) { + for window_kind in self.windows.values().map(|window| &window.kind) { if let WindowKind::Preview(entity_opt, _) = window_kind { selected_previews .push(Some(entity_opt.unwrap_or_else(|| self.tab_model.active()))); @@ -6322,8 +6309,7 @@ impl Application for App { tab.subscription( selected_previews .iter() - .find(|preview| preview.as_ref() == Some(entity).as_ref()) - .is_some(), + .any(|preview| preview.as_ref() == Some(entity).as_ref()), ) .with(entity) .map(|(entity, tab_msg)| Message::TabMessage(Some(entity), tab_msg)), diff --git a/src/dialog.rs b/src/dialog.rs index 4f36ae0..feaa2e5 100644 --- a/src/dialog.rs +++ b/src/dialog.rs @@ -179,11 +179,11 @@ impl> From for DialogLabel { }); } - if let Some(span) = spans.last_mut() { - if underline == span.underline { - span.text.push(c); - continue; - } + if let Some(span) = spans.last_mut() + && underline == span.underline + { + span.text.push(c); + continue; } spans.push(DialogLabelSpan { @@ -718,10 +718,10 @@ impl App { children.push(preview); } - if children.is_empty() { - if let Some(item) = &self.tab.parent_item_opt { - children.push(item.preview_view(None, military_time)); - } + if children.is_empty() + && let Some(item) = &self.tab.parent_item_opt + { + children.push(item.preview_view(None, military_time)); } } } @@ -1279,12 +1279,12 @@ impl Application for App { return self.update(message); } - if let Some(data) = self.nav_model.data::(entity) { - if let Some(mounter) = MOUNTERS.get(&data.0) { - return mounter - .mount(data.1.clone()) - .map(|()| cosmic::action::none()); - } + if let Some(data) = self.nav_model.data::(entity) + && let Some(mounter) = MOUNTERS.get(&data.0) + { + return mounter + .mount(data.1.clone()) + .map(|()| cosmic::action::none()); } Task::none() } @@ -1322,10 +1322,10 @@ impl Application for App { // Close the dialog if the focused widget is the dialog's main text input instead of // unfocussing the widget. - if let operation::Outcome::Some(focused) = operation::focusable::find_focused().finish() { - if self.dialog_text_input == focused { - return self.update(Message::Cancel); - } + if let operation::Outcome::Some(focused) = operation::focusable::find_focused().finish() + && self.dialog_text_input == focused + { + return self.update(Message::Cancel); } self.update(Message::Cancel) @@ -1419,14 +1419,14 @@ impl Application for App { } // Check key binds from accept label - if let Some(key_bind) = &self.accept_label.key_bind_opt { - if key_bind.matches(modifiers, &key) { - return self.update(if self.flags.kind.save() { - Message::Save(false) - } else { - Message::Open - }); - } + if let Some(key_bind) = &self.accept_label.key_bind_opt + && key_bind.matches(modifiers, &key) + { + return self.update(if self.flags.kind.save() { + Message::Save(false) + } else { + Message::Open + }); } // Uncaptured keys with only shift modifiers go to the search or location box @@ -1434,45 +1434,44 @@ impl Application for App { && !modifiers.control() && !modifiers.alt() && matches!(key, Key::Character(_)) + && let Some(text) = text { - if let Some(text) = text { - match self.flags.config.type_to_search { - TypeToSearch::Recursive => { - let mut term = self.search_get().unwrap_or_default().to_string(); - term.push_str(&text); - return self.search_set(Some(term)); + match self.flags.config.type_to_search { + TypeToSearch::Recursive => { + let mut term = self.search_get().unwrap_or_default().to_string(); + term.push_str(&text); + return self.search_set(Some(term)); + } + TypeToSearch::EnterPath => { + let location = (self.tab.edit_location) + .as_ref() + .map_or_else(|| &self.tab.location, |x| &x.location); + // Try to add text to end of location + if let Some(path) = location.path_opt() { + let mut path_string = path.to_string_lossy().to_string(); + path_string.push_str(&text); + self.tab.edit_location = + Some(location.with_path(PathBuf::from(path_string)).into()); } - TypeToSearch::EnterPath => { - let location = (self.tab.edit_location) - .as_ref() - .map_or_else(|| &self.tab.location, |x| &x.location); - // Try to add text to end of location - if let Some(path) = location.path_opt() { - let mut path_string = path.to_string_lossy().to_string(); - path_string.push_str(&text); - self.tab.edit_location = - Some(location.with_path(PathBuf::from(path_string)).into()); - } + } + TypeToSearch::SelectByPrefix => { + // Reset buffer if timeout elapsed + if let Some(last_key) = self.type_select_last_key + && last_key.elapsed() >= tab::TYPE_SELECT_TIMEOUT + { + self.type_select_prefix.clear(); } - TypeToSearch::SelectByPrefix => { - // Reset buffer if timeout elapsed - if let Some(last_key) = self.type_select_last_key { - if last_key.elapsed() >= tab::TYPE_SELECT_TIMEOUT { - self.type_select_prefix.clear(); - } - } - // Accumulate character and select - self.type_select_prefix.push_str(&text.to_lowercase()); - self.type_select_last_key = Some(Instant::now()); + // Accumulate character and select + self.type_select_prefix.push_str(&text.to_lowercase()); + self.type_select_last_key = Some(Instant::now()); - self.tab.select_by_prefix(&self.type_select_prefix); - if let Some(offset) = self.tab.select_focus_scroll() { - return scrollable::scroll_to( - self.tab.scrollable_id.clone(), - offset, - ); - } + self.tab.select_by_prefix(&self.type_select_prefix); + if let Some(offset) = self.tab.select_focus_scroll() { + return scrollable::scroll_to( + self.tab.scrollable_id.clone(), + offset, + ); } } } @@ -1486,21 +1485,22 @@ impl Application for App { let mut unmounted = Vec::new(); if let Some(old_items) = self.mounter_items.get(&mounter_key) { for old_item in old_items { - if let Some(old_path) = old_item.path() { - if old_item.is_mounted() { - let mut still_mounted = false; - for item in &mounter_items { - if let Some(path) = item.path() { - if path == old_path && item.is_mounted() { - still_mounted = true; - break; - } - } - } - if !still_mounted { - unmounted.push(Location::Path(old_path)); + if let Some(old_path) = old_item.path() + && old_item.is_mounted() + { + let mut still_mounted = false; + for item in &mounter_items { + if let Some(path) = item.path() + && path == old_path + && item.is_mounted() + { + still_mounted = true; + break; } } + if !still_mounted { + unmounted.push(Location::Path(old_path)); + } } } } @@ -1601,16 +1601,16 @@ impl Application for App { let mut paths = Vec::new(); if let Some(items) = self.tab.items_opt() { for item in items { - if item.selected { - if let Some(path) = item.path_opt() { - paths.push(path.clone()); - let _ = update_recently_used( - path, - Self::APP_ID.to_string(), - "cosmic-files".to_string(), - None, - ); - } + if item.selected + && let Some(path) = item.path_opt() + { + paths.push(path.clone()); + let _ = update_recently_used( + path, + Self::APP_ID.to_string(), + "cosmic-files".to_string(), + None, + ); } } } @@ -1640,11 +1640,11 @@ impl Application for App { } // If we are in directory mode, return the current directory - if self.flags.kind.is_dir() { - if let Location::Path(tab_path) = &self.tab.location { - self.result_opt = Some(DialogResult::Open(vec![tab_path.clone()])); - return window::close(self.flags.window_id); - } + if self.flags.kind.is_dir() + && let Location::Path(tab_path) = &self.tab.location + { + self.result_opt = Some(DialogResult::Open(vec![tab_path.clone()])); + return window::close(self.flags.window_id); } } Message::Preview => { @@ -1654,26 +1654,24 @@ impl Application for App { }); } Message::Save(replace) => { - if let DialogKind::SaveFile { filename } = &self.flags.kind { - if !filename.is_empty() { - if let Some(tab_path) = self.tab.location.path_opt() { - let path = tab_path.join(filename); - if path.is_dir() { - // cd to directory - let message = Message::TabMessage(tab::Message::Location( - Location::Path(path), - )); - return self.update(message); - } else if !replace && path.exists() { - self.dialog_pages.push_back(DialogPage::Replace { - filename: filename.clone(), - }); - return widget::button::focus(REPLACE_BUTTON_ID.clone()); - } - self.result_opt = Some(DialogResult::Open(vec![path])); - return window::close(self.flags.window_id); - } + if let DialogKind::SaveFile { filename } = &self.flags.kind + && !filename.is_empty() + && let Some(tab_path) = self.tab.location.path_opt() + { + let path = tab_path.join(filename); + if path.is_dir() { + // cd to directory + let message = + Message::TabMessage(tab::Message::Location(Location::Path(path))); + return self.update(message); + } else if !replace && path.exists() { + self.dialog_pages.push_back(DialogPage::Replace { + filename: filename.clone(), + }); + return widget::button::focus(REPLACE_BUTTON_ID.clone()); } + self.result_opt = Some(DialogResult::Open(vec![path])); + return window::close(self.flags.window_id); } } Message::ScrollTab(scroll_speed) => { @@ -1703,16 +1701,14 @@ impl Application for App { let tab_commands = self.tab.update(tab_message, self.modifiers); // Update filename box when anything is selected - if let DialogKind::SaveFile { filename } = &mut self.flags.kind { - if let Some(click_i) = click_i_opt { - if let Some(items) = self.tab.items_opt() { - if let Some(item) = items.get(click_i) { - if item.selected && !item.metadata.is_dir() { - filename.clone_from(&item.name); - } - } - } - } + if let DialogKind::SaveFile { filename } = &mut self.flags.kind + && let Some(click_i) = click_i_opt + && let Some(items) = self.tab.items_opt() + && let Some(item) = items.get(click_i) + && item.selected + && !item.metadata.is_dir() + { + filename.clone_from(&item.name); } let mut commands = Vec::new(); @@ -1840,34 +1836,34 @@ impl Application for App { Message::TabRescan(location, parent_item_opt, mut items, selection_paths) => { if location == self.tab.location { // Filter - if let Some(filter_i) = self.filter_selected { - if let Some(filter) = self.filters.get(filter_i) { - // Parse globs (Mime implements PartialEq with &str, so no need to parse) - let mut parsed_globs = Vec::new(); - let mut mimes = Vec::new(); - for pattern in &filter.patterns { - match pattern { - DialogFilterPattern::Glob(value) => { - match glob::Pattern::new(value) { - Ok(glob) => parsed_globs.push(glob), - Err(err) => { - log::warn!("failed to parse glob {value:?}: {err}"); - } + if let Some(filter_i) = self.filter_selected + && let Some(filter) = self.filters.get(filter_i) + { + // Parse globs (Mime implements PartialEq with &str, so no need to parse) + let mut parsed_globs = Vec::new(); + let mut mimes = Vec::new(); + for pattern in &filter.patterns { + match pattern { + DialogFilterPattern::Glob(value) => { + match glob::Pattern::new(value) { + Ok(glob) => parsed_globs.push(glob), + Err(err) => { + log::warn!("failed to parse glob {value:?}: {err}"); } } - DialogFilterPattern::Mime(value) => mimes.push(value.as_str()), } + DialogFilterPattern::Mime(value) => mimes.push(value.as_str()), } + } - items.retain(|item| { - // Directories are always shown - item.metadata.is_dir() + items.retain(|item| { + // Directories are always shown + item.metadata.is_dir() // Check for mime type match (first because it is faster) || mimes.iter().copied().any(|mime| mime == item.mime) // Check for glob match (last because it is slower) || parsed_globs.iter().any(|glob| glob.matches(&item.name)) - }); - } + }); } // Select based on filename @@ -1944,19 +1940,19 @@ impl Application for App { let mut col = widget::column::with_capacity(2); - if self.core.is_condensed() { - if let Some(term) = self.search_get() { - col = col.push( - widget::container( - widget::text_input::search_input("", term) - .width(Length::Fill) - .id(self.search_id.clone()) - .on_clear(Message::SearchClear) - .on_input(Message::SearchInput), - ) - .padding(space_xxs), - ); - } + if self.core.is_condensed() + && let Some(term) = self.search_get() + { + col = col.push( + widget::container( + widget::text_input::search_input("", term) + .width(Length::Fill) + .id(self.search_id.clone()) + .on_clear(Message::SearchClear) + .on_input(Message::SearchInput), + ) + .padding(space_xxs), + ); } col = col.push( diff --git a/src/large_image.rs b/src/large_image.rs index 6a2cf6b..8686a97 100644 --- a/src/large_image.rs +++ b/src/large_image.rs @@ -392,16 +392,16 @@ impl LargeImageManager { generation: u64, ) -> bool { // Check if this decode is still current (not superseded by a newer one) - if let Some(¤t_gen) = self.decode_generations.get(&path) { - if generation != current_gen { - log::info!( - "Discarding outdated decode for {} (generation {} != current {})", - path.display(), - generation, - current_gen - ); - return false; - } + if let Some(¤t_gen) = self.decode_generations.get(&path) + && generation != current_gen + { + log::info!( + "Discarding outdated decode for {} (generation {} != current {})", + path.display(), + generation, + current_gen + ); + return false; } log::info!( @@ -556,7 +556,7 @@ impl LargeImageManager { /// Check if sufficient memory is available, clearing cache if needed. /// Returns true if memory is available, false otherwise. - fn ensure_memory_available(&mut self, path: &PathBuf, width: u32, height: u32) -> bool { + fn ensure_memory_available(&mut self, path: &Path, width: u32, height: u32) -> bool { let (has_memory, error_opt) = check_memory_available(width, height); if has_memory { @@ -565,7 +565,7 @@ impl LargeImageManager { if self.cache_is_empty() { if let Some(error_msg) = error_opt { - self.store_error(path.clone(), error_msg); + self.store_error(path.to_path_buf(), error_msg); log::warn!( "Cannot load {}: insufficient memory and cache is empty", path.display() @@ -588,7 +588,7 @@ impl LargeImageManager { } if let Some(error_msg) = error_opt_after { - self.store_error(path.clone(), error_msg); + self.store_error(path.to_path_buf(), error_msg); log::warn!( "Cannot load {}: insufficient memory even after cache clear", path.display() diff --git a/src/localize.rs b/src/localize.rs index 1eb11ee..f561a42 100644 --- a/src/localize.rs +++ b/src/localize.rs @@ -62,10 +62,10 @@ pub static LOCALE: LazyLock = LazyLock::new(|| { } // Try language-only fallback (e.g., "en" from "en-US") - if let Some(lang) = cleaned_locale.split('-').next() { - if let Ok(locale) = Locale::try_from_str(lang) { - return locale; - } + if let Some(lang) = cleaned_locale.split('-').next() + && let Ok(locale) = Locale::try_from_str(lang) + { + return locale; } } } diff --git a/src/mime_app.rs b/src/mime_app.rs index cee1456..4a55cdf 100644 --- a/src/mime_app.rs +++ b/src/mime_app.rs @@ -310,7 +310,7 @@ impl MimeAppCache { for (mime, filenames) in list.removed_associations.iter() { for filename in filenames { log::trace!("remove {mime}={filename}"); - if let Some(apps) = self.cache.get_mut(&mime) { + if let Some(apps) = self.cache.get_mut(mime) { apps.retain(|x| !filename_eq(&x.path, filename)); } } @@ -319,7 +319,7 @@ impl MimeAppCache { for (mime, filenames) in list.default_apps.iter() { for filename in filenames { log::trace!("default {mime}={filename}"); - if let Some(apps) = self.cache.get_mut(&mime) { + if let Some(apps) = self.cache.get_mut(mime) { let mut found = false; for app in apps.iter_mut() { if filename_eq(&app.path, filename) { diff --git a/src/mounter/gvfs.rs b/src/mounter/gvfs.rs index 9fdaf12..77fd4eb 100644 --- a/src/mounter/gvfs.rs +++ b/src/mounter/gvfs.rs @@ -23,12 +23,11 @@ fn resolve_uri(uri: &str) -> (String, gio::File) { TARGET_URI_ATTRIBUTE, gio::FileQueryInfoFlags::NONE, gio::Cancellable::NONE, - ) { - if let Some(resolved_uri) = file_info.attribute_as_string(TARGET_URI_ATTRIBUTE) { - let resolved_uri = String::from(resolved_uri); - let file = gio::File::for_uri(&resolved_uri); - return (resolved_uri, file); - } + ) && let Some(resolved_uri) = file_info.attribute_as_string(TARGET_URI_ATTRIBUTE) + { + let resolved_uri = String::from(resolved_uri); + let file = gio::File::for_uri(&resolved_uri); + return (resolved_uri, file); } (uri.to_string(), file) @@ -60,7 +59,7 @@ fn items(monitor: &gio::VolumeMonitor, sizes: IconSizes) -> MounterItems { gio::Cancellable::NONE, ) .ok() - .and_then(|info| Some(info.boolean(gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE))) + .map(|info| info.boolean(gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE)) .unwrap_or(true); // Default to remote if query fails MounterItem::Gvfs(Item { @@ -457,9 +456,9 @@ impl Gvfs { log::info!("mount {name}: result {res:?}"); // Update the mounter_item with mount information after successful mount let mut updated_item = mounter_item.clone(); - if res.is_ok() { - if let MounterItem::Gvfs(ref mut item) = updated_item { - if let Some(mount) = volume_for_callback.get_mount() { + if res.is_ok() + && let MounterItem::Gvfs(ref mut item) = updated_item + && let Some(mount) = volume_for_callback.get_mount() { let root = MountExt::root(&mount); item.path_opt = root.path(); item.is_mounted = true; @@ -469,14 +468,9 @@ impl Gvfs { gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE, gio::Cancellable::NONE, ) - .ok() - .and_then(|info| { - Some(info.boolean(gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE)) - }) + .ok().map(|info| info.boolean(gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE)) .unwrap_or(true); } - } - } event_tx.send(Event::MountResult(updated_item, match res { Ok(()) => { _ = complete_tx.send(Ok(())); diff --git a/src/mouse_area.rs b/src/mouse_area.rs index 978861d..173800c 100644 --- a/src/mouse_area.rs +++ b/src/mouse_area.rs @@ -246,19 +246,18 @@ struct State { impl State { fn drag_rect(&self, cursor: mouse::Cursor) -> Option { - if let Some(drag_source) = self.drag_initiated { - if let Some(position) = cursor.position().or(self.last_virtual_position) { - if position.distance(drag_source) > 1.0 { - let min_x = drag_source.x.min(position.x); - let max_x = drag_source.x.max(position.x); - let min_y = drag_source.y.min(position.y); - let max_y = drag_source.y.max(position.y); - return Some(Rectangle::new( - Point::new(min_x, min_y), - Size::new(max_x - min_x, max_y - min_y), - )); - } - } + if let Some(drag_source) = self.drag_initiated + && let Some(position) = cursor.position().or(self.last_virtual_position) + && position.distance(drag_source) > 1.0 + { + let min_x = drag_source.x.min(position.x); + let max_x = drag_source.x.max(position.x); + let min_y = drag_source.y.min(position.y); + let max_y = drag_source.y.max(position.y); + return Some(Rectangle::new( + Point::new(min_x, min_y), + Size::new(max_x - min_x, max_y - min_y), + )); } None } @@ -527,12 +526,12 @@ fn update( let offset = layout.virtual_offset(); let layout_bounds = layout.bounds(); - let viewport_changed = state.viewport.map_or(true, |v| v != *viewport); + let viewport_changed = state.viewport != Some(*viewport); - if let Some(message) = widget.on_resize.as_ref() { - if viewport_changed { - shell.publish(message(*viewport)); - } + if let Some(message) = widget.on_resize.as_ref() + && viewport_changed + { + shell.publish(message(*viewport)); } state.viewport = Some(*viewport); @@ -664,113 +663,112 @@ fn update( } } - if let Some(message) = widget.on_right_press.as_ref() { - if matches!( + if let Some(message) = widget.on_right_press.as_ref() + && matches!( event, Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Right)) - ) { - let point_opt = if widget.on_right_press_window_position { - cursor.position_over(layout_bounds).map(|mut p| { - p.x -= offset.x; - p.y -= offset.y; - p - }) - } else { - cursor.position_in(layout_bounds) - }; - shell.publish(message(point_opt)); + ) + { + let point_opt = if widget.on_right_press_window_position { + cursor.position_over(layout_bounds).map(|mut p| { + p.x -= offset.x; + p.y -= offset.y; + p + }) + } else { + cursor.position_in(layout_bounds) + }; + shell.publish(message(point_opt)); - if widget.on_right_press_no_capture { - return event::Status::Ignored; - } - return event::Status::Captured; + if widget.on_right_press_no_capture { + return event::Status::Ignored; } + return event::Status::Captured; } - if let Some(message) = widget.on_right_release.as_ref() { - if matches!( + if let Some(message) = widget.on_right_release.as_ref() + && matches!( event, Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Right)) - ) { - shell.publish(message(cursor.position_in(layout_bounds))); + ) + { + shell.publish(message(cursor.position_in(layout_bounds))); - return event::Status::Captured; - } + return event::Status::Captured; } - if let Some(message) = widget.on_middle_press.as_ref() { - if matches!( + if let Some(message) = widget.on_middle_press.as_ref() + && matches!( event, Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Middle)) - ) { - shell.publish(message(cursor.position_in(layout_bounds))); + ) + { + shell.publish(message(cursor.position_in(layout_bounds))); - return event::Status::Captured; - } + return event::Status::Captured; } - if let Some(message) = widget.on_middle_release.as_ref() { - if matches!( + if let Some(message) = widget.on_middle_release.as_ref() + && matches!( event, Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Middle)) - ) { - shell.publish(message(cursor.position_in(layout_bounds))); + ) + { + shell.publish(message(cursor.position_in(layout_bounds))); - return event::Status::Captured; - } + return event::Status::Captured; } - if let Some(message) = widget.on_back_press.as_ref() { - if matches!( + if let Some(message) = widget.on_back_press.as_ref() + && matches!( event, Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Back)) - ) { - shell.publish(message(cursor.position_in(layout_bounds))); + ) + { + shell.publish(message(cursor.position_in(layout_bounds))); - return event::Status::Captured; - } + return event::Status::Captured; } - if let Some(message) = widget.on_back_release.as_ref() { - if matches!( + if let Some(message) = widget.on_back_release.as_ref() + && matches!( event, Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Back)) - ) { - shell.publish(message(cursor.position_in(layout_bounds))); + ) + { + shell.publish(message(cursor.position_in(layout_bounds))); - return event::Status::Captured; - } + return event::Status::Captured; } - if let Some(message) = widget.on_forward_press.as_ref() { - if matches!( + if let Some(message) = widget.on_forward_press.as_ref() + && matches!( event, Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Forward)) - ) { - shell.publish(message(cursor.position_in(layout_bounds))); + ) + { + shell.publish(message(cursor.position_in(layout_bounds))); - return event::Status::Captured; - } + return event::Status::Captured; } - if let Some(message) = widget.on_forward_release.as_ref() { - if matches!( + if let Some(message) = widget.on_forward_release.as_ref() + && matches!( event, Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Forward)) - ) { - shell.publish(message(cursor.position_in(layout_bounds))); + ) + { + shell.publish(message(cursor.position_in(layout_bounds))); - return event::Status::Captured; - } + return event::Status::Captured; } - if let Some(on_scroll) = widget.on_scroll.as_ref() { - if let Event::Mouse(mouse::Event::WheelScrolled { delta }) = event { - if let Some(message) = on_scroll(*delta) { - shell.publish(message); - return event::Status::Captured; - } - } + if let Some(on_scroll) = widget.on_scroll.as_ref() + && let Event::Mouse(mouse::Event::WheelScrolled { delta }) = event + && let Some(message) = on_scroll(*delta) + { + shell.publish(message); + return event::Status::Captured; } if let Some((message, drag_rect)) = widget.on_drag.as_ref().zip(state.drag_rect(cursor)) { diff --git a/src/operation/mod.rs b/src/operation/mod.rs index b05488b..208d09a 100644 --- a/src/operation/mod.rs +++ b/src/operation/mod.rs @@ -957,10 +957,10 @@ impl Operation { let dir_name = get_directory_name(file_name); let mut new_dir = to.join(dir_name); - if new_dir.exists() { - if let Some(new_dir_parent) = new_dir.parent() { - new_dir = copy_unique_path(&new_dir, new_dir_parent); - } + if new_dir.exists() + && let Some(new_dir_parent) = new_dir.parent() + { + new_dir = copy_unique_path(&new_dir, new_dir_parent); } op_sel.ignored.push(path.clone()); diff --git a/src/operation/recursive.rs b/src/operation/recursive.rs index cc74a43..953a874 100644 --- a/src/operation/recursive.rs +++ b/src/operation/recursive.rs @@ -138,10 +138,10 @@ impl Context { }), is_cleanup: false, }; - if matches!(method, Method::Move { .. }) { - if let Some(cleanup_op) = op.move_cleanup_op() { - cleanup_ops.push(cleanup_op); - } + if matches!(method, Method::Move { .. }) + && let Some(cleanup_op) = op.move_cleanup_op() + { + cleanup_ops.push(cleanup_op); } if let Some(parent) = op.to.parent() { target_dirs.insert(parent.to_path_buf()); diff --git a/src/tab.rs b/src/tab.rs index 508b5cc..430176a 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -934,43 +934,43 @@ pub fn scan_path(tab_path: &PathBuf, sizes: IconSizes) -> Vec { #[cfg(feature = "gvfs")] { - if let Ok(path_meta) = fs::metadata(tab_path) { - if fs_kind(&path_meta) == FsKind::Gvfs { - let file = gio::File::for_path(tab_path); + if let Ok(path_meta) = fs::metadata(tab_path) + && fs_kind(&path_meta) == FsKind::Gvfs + { + let file = gio::File::for_path(tab_path); - // gio crate expects a comma delimited string - let attr_string = [ - gio::FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME.as_str(), - gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE.as_str(), - gio::FILE_ATTRIBUTE_TIME_MODIFIED.as_str(), - gio::FILE_ATTRIBUTE_STANDARD_SIZE.as_str(), - gio::FILE_ATTRIBUTE_STANDARD_TYPE.as_str(), - gio::FILE_ATTRIBUTE_STANDARD_NAME.as_str(), - ] - .join(","); + // gio crate expects a comma delimited string + let attr_string = [ + gio::FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME.as_str(), + gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE.as_str(), + gio::FILE_ATTRIBUTE_TIME_MODIFIED.as_str(), + gio::FILE_ATTRIBUTE_STANDARD_SIZE.as_str(), + gio::FILE_ATTRIBUTE_STANDARD_TYPE.as_str(), + gio::FILE_ATTRIBUTE_STANDARD_NAME.as_str(), + ] + .join(","); - match gio::prelude::FileExt::enumerate_children( - &file, - attr_string.as_str(), - gio::FileQueryInfoFlags::NONE, - gio::Cancellable::NONE, - ) { - Ok(res) => { - remote_scannable = true; - items = res - .filter_map(|file| { - let file = file.ok()?; - Some(item_from_gvfs_info(tab_path.join(file.name()), file, sizes)) - }) - .collect(); - } - Err(err) => { - log::warn!( - "could not enumerate {} via gio: {}", - tab_path.display(), - err - ); - } + match gio::prelude::FileExt::enumerate_children( + &file, + attr_string.as_str(), + gio::FileQueryInfoFlags::NONE, + gio::Cancellable::NONE, + ) { + Ok(res) => { + remote_scannable = true; + items = res + .filter_map(|file| { + let file = file.ok()?; + Some(item_from_gvfs_info(tab_path.join(file.name()), file, sizes)) + }) + .collect(); + } + Err(err) => { + log::warn!( + "could not enumerate {} via gio: {}", + tab_path.display(), + err + ); } } } @@ -1410,11 +1410,11 @@ impl EditLocation { self.selected = Some(selected); // Automatically resolve if there is only one completion - if completions.len() == 1 { - if let Some(resolved) = self.resolve() { - self.location = resolved; - self.selected = None; - } + if completions.len() == 1 + && let Some(resolved) = self.resolve() + { + self.location = resolved; + self.selected = None; } } } else { @@ -2033,10 +2033,10 @@ impl ItemThumbnail { if let Some((item_thumbnail, temp_file)) = Self::generate_thumbnail_external(path, &mime, thumbnail_size, thumbnail_dir) { - if let Ok(cache) = thumbnail_cacher { - if let Err(err) = cache.update_with_temp_file(temp_file) { - log::warn!("failed to update cache for {}: {}", path.display(), err); - } + if let Ok(cache) = thumbnail_cacher + && let Err(err) = cache.update_with_temp_file(temp_file) + { + log::warn!("failed to update cache for {}: {}", path.display(), err); } return item_thumbnail; } @@ -2076,16 +2076,15 @@ impl ItemThumbnail { // If we weren't able to create a thumbnail, but we should have // been able to, create a fail marker so that it isn't tried the // next time. - if let Ok(cacher) = thumbnail_cacher { - if tried_supported_file { - if let Err(err) = cacher.create_fail_marker() { - log::warn!( - "failed to create thumbnail fail marker for {}: {}", - path.display(), - err - ); - } - } + if let Ok(cacher) = thumbnail_cacher + && tried_supported_file + && let Err(err) = cacher.create_fail_marker() + { + log::warn!( + "failed to create thumbnail fail marker for {}: {}", + path.display(), + err + ); } Self::NotImage @@ -2273,13 +2272,13 @@ impl Item { widget::button::icon(widget::icon::from_name("go-next-symbolic")) .on_press(Message::ItemRight), ); - if self.can_gallery() { - if let Some(_path) = self.path_opt() { - row = row.push( - widget::button::icon(widget::icon::from_name("view-fullscreen-symbolic")) - .on_press(Message::Gallery(true)), - ); - } + if self.can_gallery() + && let Some(_path) = self.path_opt() + { + row = row.push( + widget::button::icon(widget::icon::from_name("view-fullscreen-symbolic")) + .on_press(Message::Gallery(true)), + ); } row.into() } @@ -2445,11 +2444,11 @@ impl Item { } } - if let Some(path) = self.path_opt() { - if let Ok(img) = image::image_dimensions(path) { - let (width, height) = img; - details = details.push(widget::text::body(format!("{width}x{height}"))); - } + if let Some(path) = self.path_opt() + && let Ok(img) = image::image_dimensions(path) + { + let (width, height) = img; + details = details.push(widget::text::body(format!("{width}x{height}"))); } column = column.push(details); @@ -2637,12 +2636,11 @@ async fn calculate_dir_size(path: &Path, controller: Controller) -> Result { - if let Some(mut edit_location) = self.edit_location.take() { - if !matches!(edit_location.location, Location::Network(..)) { - edit_location.selected = Some(selected); - cd = edit_location.resolve(); - } + if let Some(mut edit_location) = self.edit_location.take() + && !matches!(edit_location.location, Location::Network(..)) + { + edit_location.selected = Some(selected); + cd = edit_location.resolve(); } } Message::EditLocationEnable => { @@ -3532,11 +3528,11 @@ impl Tab { && edit_location .completions .as_ref() - .map_or(false, |completions| !completions.is_empty()) + .is_some_and(|completions| !completions.is_empty()) && edit_location .location .path_opt() - .map_or(false, |path| !path.exists()) + .is_some_and(|path| !path.exists()) { edit_location.selected = Some(0); } @@ -3634,19 +3630,19 @@ impl Tab { } } Message::GoNext => { - if let Some(history_i) = self.history_i.checked_add(1) { - if let Some(location) = self.history.get(history_i) { - cd = Some(location.clone()); - history_i_opt = Some(history_i); - } + if let Some(history_i) = self.history_i.checked_add(1) + && let Some(location) = self.history.get(history_i) + { + cd = Some(location.clone()); + history_i_opt = Some(history_i); } } Message::GoPrevious => { - if let Some(history_i) = self.history_i.checked_sub(1) { - if let Some(location) = self.history.get(history_i) { - cd = Some(location.clone()); - history_i_opt = Some(history_i); - } + if let Some(history_i) = self.history_i.checked_sub(1) + && let Some(location) = self.history.get(history_i) + { + cd = Some(location.clone()); + history_i_opt = Some(history_i); } } Message::ItemDown => { @@ -3825,10 +3821,10 @@ impl Tab { Message::LocationUp => { // Sets location to the path's parent // Does nothing if path is root or location is Trash - if let Location::Path(ref path) = self.location { - if let Some(parent) = path.parent() { - cd = Some(Location::Path(parent.to_owned())); - } + if let Location::Path(ref path) = self.location + && let Some(parent) = path.parent() + { + cd = Some(Location::Path(parent.to_owned())); } } Message::Open(path_opt) => { @@ -3870,27 +3866,25 @@ impl Tab { match mode { Mode::App => { if is_only_one_selected { - return ResolveResult::Cd(location.clone()); + ResolveResult::Cd(location.clone()) } else { - return ResolveResult::OpenInTab(path_opt.cloned()); + ResolveResult::OpenInTab(path_opt.cloned()) } } - Mode::Desktop => { - return match location { - Location::Trash => ResolveResult::OpenTrash, - _ => ResolveResult::Open(path_opt.cloned()), - }; - } + Mode::Desktop => match location { + Location::Trash => ResolveResult::OpenTrash, + _ => ResolveResult::Open(path_opt.cloned()), + }, Mode::Dialog(_) => { if is_only_one_selected { - return ResolveResult::Cd(location.clone()); + ResolveResult::Cd(location.clone()) } else { - return ResolveResult::Skip; + ResolveResult::Skip } } } } else { - return ResolveResult::Open(path_opt.cloned()); + ResolveResult::Open(path_opt.cloned()) } } let mut open_files = Vec::new(); @@ -3935,14 +3929,13 @@ impl Tab { if mod_ctrl || mod_shift { self.update(Message::Click(click_i_opt), modifiers); } - if let Some(ref mut items) = self.items_opt { - if !click_i_opt + if let Some(ref mut items) = self.items_opt + && !click_i_opt .is_some_and(|click_i| items.get(click_i).is_some_and(|x| x.selected)) - { - // If item not selected, clear selection on other items - for (i, item) in items.iter_mut().enumerate() { - item.selected = Some(i) == click_i_opt; - } + { + // If item not selected, clear selection on other items + for (i, item) in items.iter_mut().enumerate() { + item.selected = Some(i) == click_i_opt; } } //TODO: hack for clearing selecting when right clicking empty space @@ -3990,12 +3983,12 @@ impl Tab { } Message::Resize(viewport) => { // Scroll to ensure focused item still in view - if self.viewport_opt.map(|v| v.size()) != Some(viewport.size()) { - if let Some(offset) = self.select_focus_scroll() { - commands.push(Command::Iced( - scrollable::scroll_to(self.scrollable_id.clone(), offset).into(), - )); - } + if self.viewport_opt.map(|v| v.size()) != Some(viewport.size()) + && let Some(offset) = self.select_focus_scroll() + { + commands.push(Command::Iced( + scrollable::scroll_to(self.scrollable_id.clone(), offset).into(), + )); } self.viewport_opt = Some(viewport); @@ -4099,20 +4092,17 @@ impl Tab { } } Message::SelectLast => { - if let Some(ref items) = self.items_opt { - if let Some(last_pos) = items.iter().filter_map(|item| item.pos_opt.get()).max() - { - if self.select_position(last_pos.0, last_pos.1, mod_shift) { - if let Some(offset) = self.select_focus_scroll() { - commands.push(Command::Iced( - scrollable::scroll_to(self.scrollable_id.clone(), offset) - .into(), - )); - } - if let Some(id) = self.select_focus_id() { - commands.push(Command::Iced(widget::button::focus(id).into())); - } - } + if let Some(ref items) = self.items_opt + && let Some(last_pos) = items.iter().filter_map(|item| item.pos_opt.get()).max() + && self.select_position(last_pos.0, last_pos.1, mod_shift) + { + if let Some(offset) = self.select_focus_scroll() { + commands.push(Command::Iced( + scrollable::scroll_to(self.scrollable_id.clone(), offset).into(), + )); + } + if let Some(id) = self.select_focus_id() { + commands.push(Command::Iced(widget::button::focus(id).into())); } } } @@ -4136,13 +4126,13 @@ impl Tab { } } Message::TabComplete(path, completions) => { - if let Some(edit_location) = &mut self.edit_location { - if edit_location.location.path_opt() == Some(&path) { - edit_location.completions = Some(completions); - commands.push(Command::Iced( - widget::text_input::focus(self.edit_location_id.clone()).into(), - )); - } + if let Some(edit_location) = &mut self.edit_location + && edit_location.location.path_opt() == Some(&path) + { + edit_location.completions = Some(completions); + commands.push(Command::Iced( + widget::text_input::focus(self.edit_location_id.clone()).into(), + )); } } Message::Thumbnail(path, thumbnail) => { @@ -4276,10 +4266,10 @@ impl Tab { } Message::DirectorySize(path, dir_size) => { let location = Location::Path(path); - if let Some(ref mut item) = self.parent_item_opt { - if item.location_opt.as_ref() == Some(&location) { - item.dir_size.clone_from(&dir_size); - } + if let Some(ref mut item) = self.parent_item_opt + && item.location_opt.as_ref() == Some(&location) + { + item.dir_size.clone_from(&dir_size); } if let Some(ref mut items) = self.items_opt { for item in items.iter_mut() { @@ -4317,13 +4307,12 @@ impl Tab { } else { // Select parent if location is not directory let mut selected_paths = None; - if let Some(path) = location.path_opt() { - if !path.is_dir() { - if let Some(parent) = path.parent() { - selected_paths = Some(vec![path.clone()]); - location = location.with_path(parent.to_path_buf()); - } - } + if let Some(path) = location.path_opt() + && !path.is_dir() + && let Some(parent) = path.parent() + { + selected_paths = Some(vec![path.clone()]); + location = location.with_path(parent.to_path_buf()); } if location != self.location || selected_paths.is_some() { if location.path_opt().is_none_or(|path| path.is_dir()) { @@ -4531,99 +4520,93 @@ impl Tab { //TODO: display error messages when image not found? let mut name_opt = None; let mut element_opt: Option> = None; - if let Some(index) = self.select_focus { - if let Some(items) = &self.items_opt { - if let Some(item) = items.get(index) { - name_opt = Some(widget::text::heading(&item.display_name)); - match item - .thumbnail_opt - .as_ref() - .unwrap_or(&ItemThumbnail::NotImage) - { - ItemThumbnail::NotImage => {} - ItemThumbnail::Image(handle, original_dims) => { - // Determine which image to show based on async decode state - let mut is_loading = false; - let mut error_msg_opt = None; - let image_handle = if let Some(path) = item.path_opt() { - if let Some(error_msg) = self.large_image_manager.get_error(path) { - error_msg_opt = Some(error_msg.clone()); - handle.clone() - } else if self.large_image_manager.is_decoding(path) { - // Currently decoding (initial or re-decode) --> show cached/thumbnail with loading indicator - is_loading = true; - // Use decoded handle if available (re-decode), otherwise thumbnail (initial decode) - self.large_image_manager - .get_decoded(path) - .cloned() - .unwrap_or_else(|| handle.clone()) - } else if let Some(decoded_handle) = - self.large_image_manager.get_decoded(path) - { - // Decoded and not currently decoding --> use it - decoded_handle.clone() - } else if let Some((w, h)) = original_dims { - // Check if image needs tiling - if should_use_tiling(*w, *h) { - // Large image --> show thumbnail only - handle.clone() - } else { - // Normal-sized image --> load full resolution directly - widget::image::Handle::from_path(path) - } - } else { - // No dimensions available --> show thumbnail - handle.clone() - } - } else { + if let Some(index) = self.select_focus + && let Some(items) = &self.items_opt + && let Some(item) = items.get(index) + { + name_opt = Some(widget::text::heading(&item.display_name)); + match item + .thumbnail_opt + .as_ref() + .unwrap_or(&ItemThumbnail::NotImage) + { + ItemThumbnail::NotImage => {} + ItemThumbnail::Image(handle, original_dims) => { + // Determine which image to show based on async decode state + let mut is_loading = false; + let mut error_msg_opt = None; + let image_handle = if let Some(path) = item.path_opt() { + if let Some(error_msg) = self.large_image_manager.get_error(path) { + error_msg_opt = Some(error_msg.clone()); + handle.clone() + } else if self.large_image_manager.is_decoding(path) { + // Currently decoding (initial or re-decode) --> show cached/thumbnail with loading indicator + is_loading = true; + // Use decoded handle if available (re-decode), otherwise thumbnail (initial decode) + self.large_image_manager + .get_decoded(path) + .cloned() + .unwrap_or_else(|| handle.clone()) + } else if let Some(decoded_handle) = + self.large_image_manager.get_decoded(path) + { + // Decoded and not currently decoding --> use it + decoded_handle.clone() + } else if let Some((w, h)) = original_dims { + // Check if image needs tiling + if should_use_tiling(*w, *h) { + // Large image --> show thumbnail only handle.clone() - }; + } else { + // Normal-sized image --> load full resolution directly + widget::image::Handle::from_path(path) + } + } else { + // No dimensions available --> show thumbnail + handle.clone() + } + } else { + handle.clone() + }; - let content: cosmic::Element<'_, Message> = - if let Some(error_msg) = error_msg_opt { - widget::column() - .push(widget::image(image_handle)) - .push(widget::text(format!("⚠ {}", error_msg)).size(13)) - .padding(space_xs) - .align_x(cosmic::iced::Alignment::Center) - .into() - } else if is_loading { - widget::column() - .push(widget::image(image_handle)) - .push(widget::text("Loading higher resolution...").size(14)) - .padding(space_xs) - .align_x(cosmic::iced::Alignment::Center) - .into() - } else { - //TODO: use widget::image::viewer, when its zoom can be reset - widget::image(image_handle).into() - }; + let content: cosmic::Element<'_, Message> = + if let Some(error_msg) = error_msg_opt { + widget::column() + .push(widget::image(image_handle)) + .push(widget::text(format!("⚠ {}", error_msg)).size(13)) + .padding(space_xs) + .align_x(cosmic::iced::Alignment::Center) + .into() + } else if is_loading { + widget::column() + .push(widget::image(image_handle)) + .push(widget::text("Loading higher resolution...").size(14)) + .padding(space_xs) + .align_x(cosmic::iced::Alignment::Center) + .into() + } else { + //TODO: use widget::image::viewer, when its zoom can be reset + widget::image(image_handle).into() + }; - element_opt = - Some(widget::container(content).center(Length::Fill).into()); - } - ItemThumbnail::Svg(handle) => { - element_opt = Some( - widget::svg(handle.clone()) - .width(Length::Fill) - .height(Length::Fill) - .into(), - ); - } - ItemThumbnail::Text(text) => { - element_opt = Some( - widget::container( - widget::text_editor(text).padding(space_xxs).class( - cosmic::theme::iced::TextEditor::Custom(Box::new( - text_editor_class, - )), - ), - ) - .center(Length::Fill) - .into(), - ); - } - } + element_opt = Some(widget::container(content).center(Length::Fill).into()); + } + ItemThumbnail::Svg(handle) => { + element_opt = Some( + widget::svg(handle.clone()) + .width(Length::Fill) + .height(Length::Fill) + .into(), + ); + } + ItemThumbnail::Text(text) => { + element_opt = Some( + widget::container(widget::text_editor(text).padding(space_xxs).class( + cosmic::theme::iced::TextEditor::Custom(Box::new(text_editor_class)), + )) + .center(Length::Fill) + .into(), + ); } } } @@ -4862,32 +4845,32 @@ impl Tab { ); let mut popover = widget::popover(text_input).position(widget::popover::Position::Bottom); - if let Some(completions) = &edit_location.completions { - if !completions.is_empty() { - let mut column = - widget::column::with_capacity(completions.len()).padding(space_xxs); - for (i, (name, _path)) in completions.iter().enumerate() { - let selected = edit_location.selected == Some(i); - column = column.push( - widget::button::custom(widget::text::body(name)) - //TODO: match to design - .class(if selected { - theme::Button::Standard - } else { - theme::Button::HeaderBar - }) - .on_press(Message::EditLocationComplete(i)) - .padding(space_xxs) - .width(Length::Fill), - ); - } - popover = popover.popup( - widget::container(column) - .class(theme::Container::Dropdown) - //TODO: This is a hack to get the popover to be the right width - .max_width(size.width - 140.0), + if let Some(completions) = &edit_location.completions + && !completions.is_empty() + { + let mut column = + widget::column::with_capacity(completions.len()).padding(space_xxs); + for (i, (name, _path)) in completions.iter().enumerate() { + let selected = edit_location.selected == Some(i); + column = column.push( + widget::button::custom(widget::text::body(name)) + //TODO: match to design + .class(if selected { + theme::Button::Standard + } else { + theme::Button::HeaderBar + }) + .on_press(Message::EditLocationComplete(i)) + .padding(space_xxs) + .width(Length::Fill), ); } + popover = popover.popup( + widget::container(column) + .class(theme::Container::Dropdown) + //TODO: This is a hack to get the popover to be the right width + .max_width(size.width - 140.0), + ); } row = row.push(popover); let mut column = widget::column::with_capacity(4).padding([0, space_s]); @@ -5913,13 +5896,13 @@ impl Tab { .wayland_on_right_press_window_position(); let mut popover = widget::popover(mouse_area); - if let Some(point) = self.context_menu { - if !cfg!(feature = "wayland") || !crate::is_wayland() { - let context_menu = menu::context_menu(self, key_binds, &modifiers); - popover = popover - .popup(context_menu) - .position(widget::popover::Position::Point(point)); - } + if let Some(point) = self.context_menu + && (!cfg!(feature = "wayland") || !crate::is_wayland()) + { + let context_menu = menu::context_menu(self, key_binds, modifiers); + popover = popover + .popup(context_menu) + .position(widget::popover::Position::Point(point)); } let mut tab_column = widget::column::with_capacity(3); @@ -5939,21 +5922,21 @@ impl Tab { } match &self.location { Location::Trash => { - if let Some(items) = self.items_opt() { - if !items.is_empty() { - tab_column = tab_column.push( - widget::layer_container(widget::row::with_children([ - widget::horizontal_space().into(), - widget::button::standard(fl!("empty-trash")) - .on_press(Message::EmptyTrash) - .into(), - ])) - .padding([space_xxs, space_xs]) - .layer(cosmic_theme::Layer::Primary) - .apply(widget::container) - .padding([0, 0, 7, 0]), - ); - } + if let Some(items) = self.items_opt() + && !items.is_empty() + { + tab_column = tab_column.push( + widget::layer_container(widget::row::with_children([ + widget::horizontal_space().into(), + widget::button::standard(fl!("empty-trash")) + .on_press(Message::EmptyTrash) + .into(), + ])) + .padding([space_xxs, space_xs]) + .layer(cosmic_theme::Layer::Primary) + .apply(widget::container) + .padding([0, 0, 7, 0]), + ); } } Location::Network(uri, _display_name, _path) if uri == "network:///" => { @@ -6250,10 +6233,10 @@ impl Tab { let mut selected_items: Vec<&Item> = items.iter().filter(|item| item.selected).collect(); - if selected_items.is_empty() { - if let Some(p) = self.parent_item_opt.as_ref() { - selected_items.push(p) - } + if selected_items.is_empty() + && let Some(p) = self.parent_item_opt.as_ref() + { + selected_items.push(p) } for item in selected_items { // Item must have a path diff --git a/src/thumbnail_cacher.rs b/src/thumbnail_cacher.rs index 82cafb3..719bfc6 100644 --- a/src/thumbnail_cacher.rs +++ b/src/thumbnail_cacher.rs @@ -66,10 +66,10 @@ impl ThumbnailCacher { if let (Some(cache_base_dir), Ok(metadata)) = ( THUMBNAIL_CACHE_BASE_DIR.as_ref(), std::fs::metadata(&self.file_path), - ) { - if metadata.is_file() && self.file_path.starts_with(cache_base_dir) { - return CachedThumbnail::Valid((self.file_path.clone(), None)); - } + ) && metadata.is_file() + && self.file_path.starts_with(cache_base_dir) + { + return CachedThumbnail::Valid((self.file_path.clone(), None)); } // Use cached thumbnail if it is valid. From fcaf6c7e30b48f4d1857f9303a78f9a87b402336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vuka=C5=A1in=20Vojinovi=C4=87?= <150025636+git-f0x@users.noreply.github.com> Date: Sat, 24 Jan 2026 16:49:12 +0100 Subject: [PATCH 2/2] chore: update dependencies --- Cargo.lock | 190 +++++++++++++++---------------------- Cargo.toml | 21 ++-- src/app.rs | 16 ++-- src/archive.rs | 1 + src/operation/mod.rs | 24 ++--- src/operation/reader.rs | 2 +- src/operation/recursive.rs | 2 +- src/tab.rs | 30 +++--- src/thumbnailer.rs | 15 ++- 9 files changed, 136 insertions(+), 165 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index affa134..385b532 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -976,9 +976,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.54" +version = "1.2.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6354c81bbfd62d9cfa9cb3c773c2b7b2a3a482d569de977fd0e961f6e7c00583" +checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29" dependencies = [ "find-msvc-tools", "jobserver", @@ -1457,8 +1457,6 @@ dependencies = [ "fastrand 2.3.0", "flate2", "fork", - "freedesktop_entry_parser", - "futures", "gio", "glib", "glob", @@ -1575,8 +1573,8 @@ dependencies = [ [[package]] name = "cosmic-text" -version = "0.16.0" -source = "git+https://github.com/pop-os/cosmic-text.git#ee702e50901d90cd842dbd88154687bd2512b52c" +version = "0.17.0" +source = "git+https://github.com/pop-os/cosmic-text.git#bdd6657fd7268dc8882214f540a6150eb78cfae0" dependencies = [ "bitflags 2.10.0", "fontdb 0.23.0", @@ -1584,10 +1582,10 @@ dependencies = [ "linebender_resource_handle", "log", "rangemap", - "rustc-hash 1.1.0", + "rustc-hash 2.1.1", "self_cell", - "skrifa 0.39.0", - "smol_str", + "skrifa 0.36.0", + "smol_str 0.3.5", "swash", "sys-locale", "unicode-bidi", @@ -1736,38 +1734,14 @@ dependencies = [ "winapi", ] -[[package]] -name = "darling" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" -dependencies = [ - "darling_core 0.20.11", - "darling_macro 0.20.11", -] - [[package]] name = "darling" version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" dependencies = [ - "darling_core 0.21.3", - "darling_macro 0.21.3", -] - -[[package]] -name = "darling_core" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.114", + "darling_core", + "darling_macro", ] [[package]] @@ -1784,24 +1758,13 @@ dependencies = [ "syn 2.0.114", ] -[[package]] -name = "darling_macro" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" -dependencies = [ - "darling_core 0.20.11", - "quote", - "syn 2.0.114", -] - [[package]] name = "darling_macro" version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ - "darling_core 0.21.3", + "darling_core", "quote", "syn 2.0.114", ] @@ -1841,11 +1804,11 @@ dependencies = [ [[package]] name = "derive_setters" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae5c625eda104c228c06ecaf988d1c60e542176bd7a490e60eeda3493244c0c9" +checksum = "b7e6f6fa1f03c14ae082120b84b3c7fbd7b8588d924cf2d7c3daf9afd49df8b9" dependencies = [ - "darling 0.20.11", + "darling", "proc-macro2", "quote", "syn 2.0.114", @@ -2302,9 +2265,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "fixed_decimal" @@ -2406,6 +2369,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "font-types" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02a596f5713680923a2080d86de50fe472fb290693cf0f701187a1c8b36996b7" +dependencies = [ + "bytemuck", +] + [[package]] name = "font-types" version = "0.10.1" @@ -2527,16 +2499,6 @@ dependencies = [ "xdg", ] -[[package]] -name = "freedesktop_entry_parser" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db9c27b72f19a99a895f8ca89e2d26e4ef31013376e56fdafef697627306c3e4" -dependencies = [ - "nom 7.1.3", - "thiserror 1.0.69", -] - [[package]] name = "fsevent-sys" version = "4.1.0" @@ -2972,14 +2934,14 @@ dependencies = [ [[package]] name = "harfrust" -version = "0.4.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0caaee032384c10dd597af4579c67dee16650d862a9ccbe1233ff1a379abc07" +checksum = "75a4c970f1a00edc1626f1e3cc039492b15b73df28b9fff70f95404a571b4fae" dependencies = [ "bitflags 2.10.0", "bytemuck", "core_maths", - "read-fonts 0.36.0", + "read-fonts 0.34.0", "smallvec", ] @@ -3200,7 +3162,7 @@ dependencies = [ "raw-window-handle", "rustc-hash 2.1.1", "serde", - "smol_str", + "smol_str 0.2.2", "thiserror 1.0.69", "web-time", "window_clipboard", @@ -3835,7 +3797,7 @@ dependencies = [ "rgb", "tiff", "zune-core 0.5.1", - "zune-jpeg 0.5.11", + "zune-jpeg 0.5.12", ] [[package]] @@ -4947,9 +4909,9 @@ dependencies = [ [[package]] name = "notify-debouncer-full" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375bd3a138be7bfeff3480e4a623df4cbfb55b79df617c055cd810ba466fa078" +checksum = "c02b49179cfebc9932238d04d6079912d26de0379328872846118a0fa0dbb302" dependencies = [ "file-id", "log", @@ -5002,9 +4964,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" [[package]] name = "num-derive" @@ -6155,6 +6117,17 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "read-fonts" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8941f8e9d5f8ad3aebea330d01ac68c0167600eb31a86ecd86e97be4d13b51f5" +dependencies = [ + "bytemuck", + "core_maths", + "font-types 0.9.0", +] + [[package]] name = "read-fonts" version = "0.35.0" @@ -6162,18 +6135,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6717cf23b488adf64b9d711329542ba34de147df262370221940dfabc2c91358" dependencies = [ "bytemuck", - "font-types", -] - -[[package]] -name = "read-fonts" -version = "0.36.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eaa2941a4c05443ee3a7b26ab076a553c343ad5995230cc2b1d3e993bdc6345" -dependencies = [ - "bytemuck", - "core_maths", - "font-types", + "font-types 0.10.1", ] [[package]] @@ -6638,7 +6600,7 @@ version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" dependencies = [ - "darling 0.21.3", + "darling", "proc-macro2", "quote", "syn 2.0.114", @@ -6721,6 +6683,16 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" +[[package]] +name = "skrifa" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37004372610e83ee2a4c69c7d896b41f33da6a3dc1a4fe07dd9b2629a549b1dc" +dependencies = [ + "bytemuck", + "read-fonts 0.34.0", +] + [[package]] name = "skrifa" version = "0.37.0" @@ -6731,16 +6703,6 @@ dependencies = [ "read-fonts 0.35.0", ] -[[package]] -name = "skrifa" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9eb0b904a04d09bd68c65d946617b8ff733009999050f3b851c32fb3cfb60e" -dependencies = [ - "bytemuck", - "read-fonts 0.36.0", -] - [[package]] name = "slab" version = "0.4.11" @@ -6837,6 +6799,12 @@ dependencies = [ "serde", ] +[[package]] +name = "smol_str" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f7a918bd2a9951d18ee6e48f076843e8e73a9a5d22cf05bcd4b7a81bdd04e17" + [[package]] name = "socket2" version = "0.4.10" @@ -7211,9 +7179,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.45" +version = "0.3.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" +checksum = "9da98b7d9b7dad93488a84b8248efc35352b0b2657397d4167e7ad67e5d535e5" dependencies = [ "deranged", "itoa", @@ -7227,15 +7195,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.25" +version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" +checksum = "78cc610bac2dcee56805c99642447d4c5dbde4d01f752ffea0199aee1f601dc4" dependencies = [ "num-conv", "time-core", @@ -7791,9 +7759,9 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.1+wasi-0.2.4" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ "wit-bindgen", ] @@ -8811,7 +8779,7 @@ dependencies = [ "rustix 0.38.44", "sctk-adwaita", "smithay-client-toolkit 0.19.2", - "smol_str", + "smol_str 0.2.2", "tracing", "unicode-segmentation", "wasm-bindgen", @@ -8848,9 +8816,9 @@ dependencies = [ [[package]] name = "wit-bindgen" -version = "0.46.0" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" [[package]] name = "write16" @@ -9245,18 +9213,18 @@ checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524" [[package]] name = "zerocopy" -version = "0.8.35" +version = "0.8.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdea86ddd5568519879b8187e1cf04e24fce28f7fe046ceecbce472ff19a2572" +checksum = "7456cf00f0685ad319c5b1693f291a650eaf345e941d082fc4e03df8a03996ac" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.35" +version = "0.8.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c15e1b46eff7c6c91195752e0eeed8ef040e391cdece7c25376957d5f15df22" +checksum = "1328722bbf2115db7e19d69ebcc15e795719e2d66b60827c6a69a117365e37a0" dependencies = [ "proc-macro2", "quote", @@ -9450,9 +9418,9 @@ dependencies = [ [[package]] name = "zune-jpeg" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2959ca473aae96a14ecedf501d20b3608d2825ba280d5adb57d651721885b0c2" +checksum = "410e9ecef634c709e3831c2cfdb8d9c32164fae1c67496d5b68fff728eec37fe" dependencies = [ "zune-core 0.5.1", ] diff --git a/Cargo.toml b/Cargo.toml index 89e2156..6c6e6ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "1.0.4" authors = ["Jeremy Soller "] edition = "2024" license = "GPL-3.0-only" -rust-version = "1.85" +rust-version = "1.90" [dependencies] anyhow = "1" @@ -14,8 +14,6 @@ cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-c cosmic-mime-apps = { git = "https://github.com/pop-os/cosmic-mime-apps.git", optional = true } dirs = "6.0.0" env_logger = "0.11" -freedesktop_entry_parser = "1.3" -futures = "0.3.31" gio = { version = "0.21", optional = true } glib = { version = "0.21", optional = true } glob = "0.3" @@ -24,9 +22,9 @@ image = "0.25" libc = "0.2" log = "0.4" mime_guess = "2" -notify-debouncer-full = "0.6" +notify-debouncer-full = "0.7" notify-rust = { version = "4", optional = true } -open = "5.3.2" +open = "5.3.3" paste = "1.0" regex = "1" rustc-hash = "2.1" @@ -38,15 +36,15 @@ tokio = { version = "1", features = ["process", "sync"] } trash = { git = "https://github.com/jackpot51/trash-rs.git", branch = "cosmic" } url = "2.5" walkdir = "2.5.0" -wayland-client = { version = "0.31.11", optional = true } +wayland-client = { version = "0.31.12", optional = true } xdg = { version = "3.0", optional = true } xdg-mime = { git = "https://github.com/ebassi/xdg-mime-rs" } # Compression bzip2 = { version = "0.6", optional = true } #TODO: replace with pure Rust crate flate2 = "1.1" tar = "0.4.44" -lzma-rust2 = { version = "0.15.4", optional = true } -ordermap = { version = "1.0.0", features = ["serde"] } +lzma-rust2 = { version = "0.15.7", optional = true } +ordermap = { version = "1.1.0", features = ["serde"] } # Internationalization i18n-embed = { version = "0.16", features = [ "fluent-system", @@ -54,10 +52,10 @@ i18n-embed = { version = "0.16", features = [ ] } i18n-embed-fl = "0.10" rust-embed = "8" -slotmap = "1.0.7" +slotmap = "1.1.1" recently-used-xbel = { git = "https://github.com/pop-os/recently-used-xbel.git" } zip = "7" -uzers = "0.12.1" +uzers = "0.12.2" md-5 = "0.10.6" png = "0.18" jxl-oxide = { version = "0.12.5", features = ["image"] } @@ -76,6 +74,7 @@ default-features = false features = [ "about", "autosize", + "desktop", "multi-window", "tokio", "winit", @@ -107,7 +106,7 @@ default = [ "wayland", ] dbus-config = ["libcosmic/dbus-config"] -desktop = ["libcosmic/desktop", "dep:cosmic-mime-apps", "dep:xdg"] +desktop = ["dep:cosmic-mime-apps", "dep:xdg"] desktop-applet = [] gvfs = ["dep:gio", "dep:glib"] io-uring = ["compio/io-uring"] diff --git a/src/app.rs b/src/app.rs index a85b098..52eddca 100644 --- a/src/app.rs +++ b/src/app.rs @@ -18,7 +18,9 @@ use cosmic::{ Application, ApplicationExt, Element, app::{self, Core, Task, context_drawer}, cosmic_config::{self, ConfigSet}, - cosmic_theme, executor, + cosmic_theme, + desktop::fde::DesktopEntry, + executor, iced::{ self, Alignment, Event, Length, Rectangle, Size, Subscription, clipboard::dnd::DndAction, @@ -72,10 +74,10 @@ use crate::{ FxOrderMap, clipboard::{ClipboardCopy, ClipboardKind, ClipboardPaste}, config::{ - AppTheme, Config, DesktopConfig, Favorite, IconSizes, TIME_CONFIG_ID, TabConfig, + AppTheme, Config, DesktopConfig, Favorite, IconSizes, State, TIME_CONFIG_ID, TabConfig, TimeConfig, TypeToSearch, }, - dialog::{Dialog, DialogKind, DialogMessage, DialogResult}, + dialog::{Dialog, DialogKind, DialogMessage, DialogResult, DialogSettings}, fl, home_dir, key_bind::key_binds, localize::LANGUAGE_SORTER, @@ -91,10 +93,6 @@ use crate::{ tab::{ self, HOVER_DURATION, HeadingOptions, ItemMetadata, Location, SORT_OPTION_FALLBACK, Tab, }, -}; -use crate::{ - config::State, - dialog::DialogSettings, zoom::{zoom_in_view, zoom_out_view, zoom_to_default}, }; @@ -846,8 +844,8 @@ impl App { fn launch_desktop_entries(paths: &[impl AsRef]) { for path in paths.iter().map(AsRef::as_ref) { - match freedesktop_entry_parser::parse_entry(path) { - Ok(entry) => match entry.section("Desktop Entry").attr("Exec") { + match DesktopEntry::from_path::<&str>(path, None) { + Ok(entry) => match entry.exec() { Some(exec) => match mime_app::exec_to_command(exec, &[] as &[&str; 0]) { Some(commands) => { for mut command in commands { diff --git a/src/archive.rs b/src/archive.rs index 8684bb8..7374941 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -2,6 +2,7 @@ use crate::{ mime_icon::mime_for_path, operation::{Controller, OpReader, OperationError, OperationErrorType, sync_to_disk}, }; +use cosmic::iced::futures; use std::{ collections::HashSet, fs, diff --git a/src/operation/mod.rs b/src/operation/mod.rs index 208d09a..d17ef5d 100644 --- a/src/operation/mod.rs +++ b/src/operation/mod.rs @@ -5,7 +5,7 @@ use crate::{ spawn_detached::spawn_detached, tab, }; -use cosmic::iced::futures::{SinkExt, channel::mpsc::Sender}; +use cosmic::iced::futures::{self, SinkExt, StreamExt, channel::mpsc::Sender, stream}; use std::{ borrow::Cow, fmt::Formatter, @@ -200,23 +200,25 @@ pub async fn sync_to_disk( written_files: Vec, target_dirs: std::collections::HashSet, ) { - use futures::{StreamExt, stream}; - // Sync files to disk - let file_stream = stream::iter(written_files.into_iter().map(|path| async move { + stream::iter(written_files.into_iter().map(|path| async move { if let Ok(file) = compio::fs::OpenOptions::new().write(true).open(&path).await { let _ = file.sync_all().await; } - })); - file_stream.buffer_unordered(32).collect::>().await; + })) + .buffer_unordered(32) + .collect::>() + .await; // Sync directories to disk - let dir_stream = stream::iter(target_dirs.into_iter().map(|path| async move { + stream::iter(target_dirs.into_iter().map(|path| async move { if let Ok(dir) = compio::fs::OpenOptions::new().read(true).open(&path).await { let _ = dir.sync_all().await; } - })); - dir_stream.buffer_unordered(16).collect::>().await; + })) + .buffer_unordered(16) + .collect::>() + .await; } fn copy_unique_path(from: &Path, to: &Path) -> PathBuf { @@ -1208,7 +1210,7 @@ mod tests { path::PathBuf, }; - use cosmic::iced::futures::{StreamExt, channel::mpsc}; + use cosmic::iced::futures::{StreamExt, channel::mpsc, future}; use log::debug; use test_log::test; use tokio::sync; @@ -1262,7 +1264,7 @@ mod tests { } }; - futures::future::join(handle_messages, handle_copy).await.1 + future::join(handle_messages, handle_copy).await.1 } #[test(compio::test)] diff --git a/src/operation/reader.rs b/src/operation/reader.rs index 6447a1e..75088df 100644 --- a/src/operation/reader.rs +++ b/src/operation/reader.rs @@ -27,7 +27,7 @@ impl OpReader { impl io::Read for OpReader { fn read(&mut self, buf: &mut [u8]) -> io::Result { - futures::executor::block_on(async { + cosmic::iced::futures::executor::block_on(async { self.controller .check() .await diff --git a/src/operation/recursive.rs b/src/operation/recursive.rs index 953a874..076a4b2 100644 --- a/src/operation/recursive.rs +++ b/src/operation/recursive.rs @@ -322,7 +322,7 @@ impl Op { } } - let (from_file, metadata, mut to_file) = futures::try_join!( + let (from_file, metadata, mut to_file) = cosmic::iced::futures::try_join!( async { compio::fs::OpenOptions::new() .read(true) diff --git a/src/tab.rs b/src/tab.rs index 430176a..8b6faa7 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -1,5 +1,8 @@ +use chrono::{Datelike, Timelike, Utc}; use cosmic::{ - Apply, Element, cosmic_theme, font, + Apply, Element, cosmic_theme, + desktop::fde::{DesktopEntry, get_languages_from_env}, + font, iced::{ Alignment, Border, @@ -37,8 +40,6 @@ use cosmic::{ menu::{action::MenuAction, key_bind::KeyBind}, }, }; - -use chrono::{Datelike, Timelike, Utc}; use i18n_embed::LanguageLoader; use icu::{ datetime::{ @@ -615,7 +616,8 @@ pub fn fs_kind(_metadata: &Metadata) -> FsKind { } fn get_desktop_file_display_name(path: &Path) -> Option { - let entry = match freedesktop_entry_parser::parse_entry(path) { + let locales = get_languages_from_env(); + let entry = match DesktopEntry::from_path(path, Some(&locales)) { Ok(ok) => ok, Err(err) => { log::warn!("failed to parse {}: {}", path.display(), err); @@ -623,14 +625,11 @@ fn get_desktop_file_display_name(path: &Path) -> Option { } }; - entry - .section("Desktop Entry") - .attr("Name") - .map(str::to_string) + entry.name(&locales).map(|s| s.into_owned()) } fn get_desktop_file_icon(path: &Path) -> Option { - let entry = match freedesktop_entry_parser::parse_entry(path) { + let entry = match DesktopEntry::from_path::<&str>(path, None) { Ok(ok) => ok, Err(err) => { log::warn!("failed to parse {}: {}", path.display(), err); @@ -638,10 +637,7 @@ fn get_desktop_file_icon(path: &Path) -> Option { } }; - entry - .section("Desktop Entry") - .attr("Icon") - .map(str::to_string) + entry.icon().map(str::to_string) } /// Creates an icon handle from a desktop file's Icon field value. @@ -656,17 +652,17 @@ fn desktop_icon_handle(icon: &str, size: u16) -> widget::icon::Handle { } pub fn parse_desktop_file(path: &Path) -> (Option, Option) { - let entry = match freedesktop_entry_parser::parse_entry(path) { + let locales = get_languages_from_env(); + let entry = match DesktopEntry::from_path(path, Some(&locales)) { Ok(ok) => ok, Err(err) => { log::warn!("failed to parse {}: {}", path.display(), err); return (None, None); } }; - let section = entry.section("Desktop Entry"); ( - section.attr("Name").map(str::to_string), - section.attr("Icon").map(str::to_string), + entry.name(&locales).map(|s| s.into_owned()), + entry.icon().map(str::to_string), ) } diff --git a/src/thumbnailer.rs b/src/thumbnailer.rs index 8a22ba9..f996f03 100644 --- a/src/thumbnailer.rs +++ b/src/thumbnailer.rs @@ -1,6 +1,7 @@ // Copyright 2023 System76 // SPDX-License-Identifier: GPL-3.0-only +use cosmic::desktop::fde::GenericEntry; use mime_guess::Mime; use rustc_hash::FxHashMap; use std::{ @@ -115,7 +116,7 @@ impl ThumbnailerCache { //TODO: handle directory specific behavior for path in thumbnailer_paths { - let entry = match freedesktop_entry_parser::parse_entry(&path) { + let entry = match GenericEntry::from_path(&path) { Ok(ok) => ok, Err(err) => { log::warn!("failed to parse {}: {}", path.display(), err); @@ -124,12 +125,18 @@ impl ThumbnailerCache { }; //TODO: use TryExec? - let section = entry.section("Thumbnailer Entry"); - let Some(exec) = section.attr("Exec") else { + let Some(section) = entry.group("Thumbnailer Entry") else { + log::warn!( + "missing Thumbnailer Entry section for thumbnailer {}", + path.display() + ); + continue; + }; + let Some(exec) = section.entry("Exec") else { log::warn!("missing Exec attribute for thumbnailer {}", path.display()); continue; }; - let Some(mime_types) = section.attr("MimeType") else { + let Some(mime_types) = section.entry("MimeType") else { log::warn!( "missing MimeType attribute for thumbnailer {}", path.display()