From e84463648aaa09b64d3e35e2721565d34706b82d Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Tue, 27 May 2025 02:14:16 +0300 Subject: [PATCH] Highlight file finder entries according to their git status (#31469) Configure this with the ```json5 "file_finder": { "git_status": true } ``` settings value. Before: before After: image After with search matches: image Release Notes: - Start highlighting file finder entries according to their git status --- assets/settings/default.json | 4 +- crates/file_finder/src/file_finder.rs | 51 ++++++++++++++++--- .../file_finder/src/file_finder_settings.rs | 9 +++- 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/assets/settings/default.json b/assets/settings/default.json index 0ff88926b2..fd280f4535 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -954,7 +954,9 @@ // "skip_focus_for_active_in_search": false // // Default: true - "skip_focus_for_active_in_search": true + "skip_focus_for_active_in_search": true, + // Whether to show the git status in the file finder. + "git_status": true }, // Whether or not to remove any trailing whitespace from lines of a buffer // before saving it. diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index 1a51e766d3..5fb1724eb7 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -11,7 +11,7 @@ use futures::future::join_all; pub use open_path_prompt::OpenPathDelegate; use collections::HashMap; -use editor::Editor; +use editor::{Editor, items::entry_git_aware_label_color}; use file_finder_settings::{FileFinderSettings, FileFinderWidth}; use file_icons::FileIcons; use fuzzy::{CharBag, PathMatch, PathMatchCandidate}; @@ -1418,23 +1418,58 @@ impl PickerDelegate for FileFinderDelegate { cx: &mut Context>, ) -> Option { let settings = FileFinderSettings::get_global(cx); + let path_match = self.matches.get(ix)?; - let path_match = self - .matches - .get(ix) - .expect("Invalid matches state: no element for index {ix}"); + let git_status_color = if settings.git_status { + let (entry, project_path) = match path_match { + Match::History { path, .. } => { + let project = self.project.read(cx); + let project_path = path.project.clone(); + let entry = project.entry_for_path(&project_path, cx)?; + Some((entry, project_path)) + } + Match::Search(mat) => { + let project = self.project.read(cx); + let project_path = ProjectPath { + worktree_id: WorktreeId::from_usize(mat.0.worktree_id), + path: mat.0.path.clone(), + }; + let entry = project.entry_for_path(&project_path, cx)?; + Some((entry, project_path)) + } + }?; - let history_icon = match &path_match { + let git_status = self + .project + .read(cx) + .project_path_git_status(&project_path, cx) + .map(|status| status.summary()) + .unwrap_or_default(); + Some(entry_git_aware_label_color( + git_status, + entry.is_ignored, + selected, + )) + } else { + None + }; + + let history_icon = match path_match { Match::History { .. } => Icon::new(IconName::HistoryRerun) - .color(Color::Muted) .size(IconSize::Small) + .color(Color::Muted) .into_any_element(), Match::Search(_) => v_flex() .flex_none() .size(IconSize::Small.rems()) .into_any_element(), }; + let (file_name_label, full_path_label) = self.labels_for_match(path_match, window, cx, ix); + let file_name_label = match git_status_color { + Some(git_status_color) => file_name_label.color(git_status_color), + None => file_name_label, + }; let file_icon = maybe!({ if !settings.file_icons { @@ -1442,7 +1477,7 @@ impl PickerDelegate for FileFinderDelegate { } let file_name = path_match.path().file_name()?; let icon = FileIcons::get_icon(file_name.as_ref(), cx)?; - Some(Icon::from_path(icon).color(Color::Muted)) + Some(Icon::from_path(icon).color(git_status_color.unwrap_or(Color::Muted))) }); Some( diff --git a/crates/file_finder/src/file_finder_settings.rs b/crates/file_finder/src/file_finder_settings.rs index 4a2f2bd2a3..73f4793e02 100644 --- a/crates/file_finder/src/file_finder_settings.rs +++ b/crates/file_finder/src/file_finder_settings.rs @@ -8,6 +8,7 @@ pub struct FileFinderSettings { pub file_icons: bool, pub modal_max_width: Option, pub skip_focus_for_active_in_search: bool, + pub git_status: bool, } #[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)] @@ -24,6 +25,10 @@ pub struct FileFinderSettingsContent { /// /// Default: true pub skip_focus_for_active_in_search: Option, + /// Determines whether to show the git status in the file finder + /// + /// Default: true + pub git_status: Option, } impl Settings for FileFinderSettings { @@ -35,7 +40,9 @@ impl Settings for FileFinderSettings { sources.json_merge() } - fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {} + fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut Self::FileContent) { + vscode.bool_setting("git.decorations.enabled", &mut current.git_status); + } } #[derive(Debug, PartialEq, Eq, Clone, Copy, Default, Serialize, Deserialize, JsonSchema)]