file_finder: Display file icons (#18091)

This PR adds file icons (like in tabs, the project panel and tab
switcher) to the file finder popup.

It's similar to [tab_switcher
icons](https://github.com/zed-industries/zed/pull/17115), but simpler,
because we're only dealing with actual files.

Release Notes:

- Added icons to the file finder.

Screenshot:

![image](https://github.com/user-attachments/assets/bd6a54c1-cdbd-415a-9a82-0cc7a0bb6ca2)

---------

Co-authored-by: Marshall Bowers <elliott.codes@gmail.com>
This commit is contained in:
Daste 2024-09-20 20:44:13 +02:00 committed by GitHub
parent 5d12e3ce3a
commit 7dac5594cd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 57 additions and 2 deletions

3
Cargo.lock generated
View file

@ -4326,6 +4326,7 @@ dependencies = [
"ctor", "ctor",
"editor", "editor",
"env_logger", "env_logger",
"file_icons",
"futures 0.3.30", "futures 0.3.30",
"fuzzy", "fuzzy",
"gpui", "gpui",
@ -4333,7 +4334,9 @@ dependencies = [
"menu", "menu",
"picker", "picker",
"project", "project",
"schemars",
"serde", "serde",
"serde_derive",
"serde_json", "serde_json",
"settings", "settings",
"text", "text",

View file

@ -496,6 +496,11 @@
// Whether a preview tab gets replaced when code navigation is used to navigate away from the tab. // Whether a preview tab gets replaced when code navigation is used to navigate away from the tab.
"enable_preview_from_code_navigation": false "enable_preview_from_code_navigation": false
}, },
// Settings related to the file finder.
"file_finder": {
// Whether to show file icons in the file finder.
"file_icons": true
},
// Whether or not to remove any trailing whitespace from lines of a buffer // Whether or not to remove any trailing whitespace from lines of a buffer
// before saving it. // before saving it.
"remove_trailing_whitespace_on_save": true, "remove_trailing_whitespace_on_save": true,

View file

@ -16,14 +16,17 @@ doctest = false
anyhow.workspace = true anyhow.workspace = true
collections.workspace = true collections.workspace = true
editor.workspace = true editor.workspace = true
file_icons.workspace = true
futures.workspace = true futures.workspace = true
fuzzy.workspace = true fuzzy.workspace = true
gpui.workspace = true gpui.workspace = true
menu.workspace = true menu.workspace = true
picker.workspace = true picker.workspace = true
project.workspace = true project.workspace = true
schemars.workspace = true
settings.workspace = true settings.workspace = true
serde.workspace = true serde.workspace = true
serde_derive.workspace = true
text.workspace = true text.workspace = true
theme.workspace = true theme.workspace = true
ui.workspace = true ui.workspace = true

View file

@ -1,11 +1,14 @@
#[cfg(test)] #[cfg(test)]
mod file_finder_tests; mod file_finder_tests;
mod file_finder_settings;
mod new_path_prompt; mod new_path_prompt;
mod open_path_prompt; mod open_path_prompt;
use collections::HashMap; use collections::HashMap;
use editor::{scroll::Autoscroll, Bias, Editor}; use editor::{scroll::Autoscroll, Bias, Editor};
use file_finder_settings::FileFinderSettings;
use file_icons::FileIcons;
use fuzzy::{CharBag, PathMatch, PathMatchCandidate}; use fuzzy::{CharBag, PathMatch, PathMatchCandidate};
use gpui::{ use gpui::{
actions, rems, Action, AnyElement, AppContext, DismissEvent, EventEmitter, FocusHandle, actions, rems, Action, AnyElement, AppContext, DismissEvent, EventEmitter, FocusHandle,
@ -39,7 +42,12 @@ pub struct FileFinder {
init_modifiers: Option<Modifiers>, init_modifiers: Option<Modifiers>,
} }
pub fn init_settings(cx: &mut AppContext) {
FileFinderSettings::register(cx);
}
pub fn init(cx: &mut AppContext) { pub fn init(cx: &mut AppContext) {
init_settings(cx);
cx.observe_new_views(FileFinder::register).detach(); cx.observe_new_views(FileFinder::register).detach();
cx.observe_new_views(NewPathPrompt::register).detach(); cx.observe_new_views(NewPathPrompt::register).detach();
cx.observe_new_views(OpenPathPrompt::register).detach(); cx.observe_new_views(OpenPathPrompt::register).detach();
@ -1041,12 +1049,14 @@ impl PickerDelegate for FileFinderDelegate {
selected: bool, selected: bool,
cx: &mut ViewContext<Picker<Self>>, cx: &mut ViewContext<Picker<Self>>,
) -> Option<Self::ListItem> { ) -> Option<Self::ListItem> {
let settings = FileFinderSettings::get_global(cx);
let path_match = self let path_match = self
.matches .matches
.get(ix) .get(ix)
.expect("Invalid matches state: no element for index {ix}"); .expect("Invalid matches state: no element for index {ix}");
let icon = match &path_match { let history_icon = match &path_match {
Match::History { .. } => Icon::new(IconName::HistoryRerun) Match::History { .. } => Icon::new(IconName::HistoryRerun)
.color(Color::Muted) .color(Color::Muted)
.size(IconSize::Small) .size(IconSize::Small)
@ -1059,10 +1069,17 @@ impl PickerDelegate for FileFinderDelegate {
let (file_name, file_name_positions, full_path, full_path_positions) = let (file_name, file_name_positions, full_path, full_path_positions) =
self.labels_for_match(path_match, cx, ix); self.labels_for_match(path_match, cx, ix);
let file_icon = if settings.file_icons {
FileIcons::get_icon(Path::new(&file_name), cx).map(Icon::from_path)
} else {
None
};
Some( Some(
ListItem::new(ix) ListItem::new(ix)
.spacing(ListItemSpacing::Sparse) .spacing(ListItemSpacing::Sparse)
.end_slot::<AnyElement>(Some(icon)) .start_slot::<Icon>(file_icon)
.end_slot::<AnyElement>(history_icon)
.inset(true) .inset(true)
.selected(selected) .selected(selected)
.child( .child(

View file

@ -0,0 +1,27 @@
use anyhow::Result;
use schemars::JsonSchema;
use serde_derive::{Deserialize, Serialize};
use settings::{Settings, SettingsSources};
#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
pub struct FileFinderSettings {
pub file_icons: bool,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
pub struct FileFinderSettingsContent {
/// Whether to show file icons in the file finder.
///
/// Default: true
pub file_icons: Option<bool>,
}
impl Settings for FileFinderSettings {
const KEY: Option<&'static str> = Some("file_finder");
type FileContent = FileFinderSettingsContent;
fn load(sources: SettingsSources<Self::FileContent>, _: &mut gpui::AppContext) -> Result<Self> {
sources.json_merge()
}
}