diff --git a/assets/settings/default.json b/assets/settings/default.json index 7ef69bc1675947ba3d07dc7b523658902459996b..fd6362eba1e9216d123898761ea2f5d95f676de9 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -782,6 +782,8 @@ "sort_mode": "directories_first", // Whether to show error and warning count badges next to file names in the project panel. "diagnostic_badges": false, + // Whether to show the git status indicator next to file names in the project panel. + "git_status_indicator": false, // Whether to enable drag-and-drop operations in the project panel. "drag_and_drop": true, // Whether to hide the root entry when only one folder is open in the window; diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 30d1c9b88155f2d9bc98c5ae9784bb46b8d4bb1f..68199376e8bd39cf4014bb219a305f52a46347cb 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -61,9 +61,9 @@ use std::{ use theme::ThemeSettings; use ui::{ Color, ContextMenu, ContextMenuEntry, DecoratedIcon, Divider, Icon, IconDecoration, - IconDecorationKind, IndentGuideColors, IndentGuideLayout, KeyBinding, Label, LabelSize, - ListItem, ListItemSpacing, ScrollAxes, ScrollableHandle, Scrollbars, StickyCandidate, Tooltip, - WithScrollbar, prelude::*, v_flex, + IconDecorationKind, IndentGuideColors, IndentGuideLayout, Indicator, KeyBinding, Label, + LabelSize, ListItem, ListItemSpacing, ScrollAxes, ScrollableHandle, Scrollbars, + StickyCandidate, Tooltip, WithScrollbar, prelude::*, v_flex, }; use util::{ ResultExt, TakeUntilExt, TryFutureExt, maybe, @@ -5352,6 +5352,10 @@ impl ProjectPanel { false } }; + let git_indicator = settings + .git_status_indicator + .then(|| git_status_indicator(details.git_status)) + .flatten(); let id: ElementId = if is_sticky { SharedString::from(format!("project_panel_sticky_item_{}", entry_id.to_usize())).into() @@ -5696,7 +5700,9 @@ impl ProjectPanel { }) .selectable(false) .when( - canonical_path.is_some() || diagnostic_count.is_some(), + canonical_path.is_some() + || diagnostic_count.is_some() + || git_indicator.is_some(), |this| { let symlink_element = canonical_path.map(|path| { div() @@ -5739,6 +5745,20 @@ impl ProjectPanel { }, ) }) + .when_some(git_indicator, |this, (label, color)| { + let git_indicator = if kind.is_dir() { + Indicator::dot() + .color(Color::Custom(color.color(cx).opacity(0.5))) + .into_any_element() + } else { + Label::new(label) + .size(LabelSize::Small) + .color(color) + .into_any_element() + }; + + this.child(git_indicator) + }) .when_some(symlink_element, |this, el| this.child(el)) .into_any_element(), ) @@ -7286,5 +7306,30 @@ pub fn par_sort_worktree_entries_with_mode( entries.par_sort_by(|lhs, rhs| cmp_with_mode(lhs, rhs, &mode)); } +fn git_status_indicator(git_status: GitSummary) -> Option<(&'static str, Color)> { + if git_status.conflict > 0 { + return Some(("!", Color::Conflict)); + } + if git_status.untracked > 0 { + return Some(("U", Color::Created)); + } + if git_status.worktree.deleted > 0 { + return Some(("D", Color::Deleted)); + } + if git_status.worktree.modified > 0 { + return Some(("M", Color::Warning)); + } + if git_status.index.deleted > 0 { + return Some(("D", Color::Deleted)); + } + if git_status.index.modified > 0 { + return Some(("M", Color::Modified)); + } + if git_status.index.added > 0 { + return Some(("A", Color::Created)); + } + None +} + #[cfg(test)] mod project_panel_tests; diff --git a/crates/project_panel/src/project_panel_settings.rs b/crates/project_panel/src/project_panel_settings.rs index de2ff8e0087b8e7dbe4fcc533e3eea0470553b50..d3786f371fdf1878dec39cd7b32f2f2dcfd90877 100644 --- a/crates/project_panel/src/project_panel_settings.rs +++ b/crates/project_panel/src/project_panel_settings.rs @@ -36,6 +36,7 @@ pub struct ProjectPanelSettings { pub auto_open: AutoOpenSettings, pub sort_mode: ProjectPanelSortMode, pub diagnostic_badges: bool, + pub git_status_indicator: bool, } #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] @@ -137,6 +138,7 @@ impl Settings for ProjectPanelSettings { }, sort_mode: project_panel.sort_mode.unwrap(), diagnostic_badges: project_panel.diagnostic_badges.unwrap(), + git_status_indicator: project_panel.git_status_indicator.unwrap(), } } } diff --git a/crates/settings/src/vscode_import.rs b/crates/settings/src/vscode_import.rs index fda63ced4c740291554034e461b3469c8809008d..414fef665a8e6841bc43242bd2f0a05147eaea1d 100644 --- a/crates/settings/src/vscode_import.rs +++ b/crates/settings/src/vscode_import.rs @@ -808,6 +808,7 @@ impl VsCodeSettings { sticky_scroll: None, auto_open: None, diagnostic_badges: None, + git_status_indicator: None, }; if let (Some(false), Some(false)) = ( diff --git a/crates/settings_content/src/workspace.rs b/crates/settings_content/src/workspace.rs index 92dc6679e60fc5d54b24afafa4daa00600c066f2..7134f7db6e058bbbdd53e72196ae6727c628d339 100644 --- a/crates/settings_content/src/workspace.rs +++ b/crates/settings_content/src/workspace.rs @@ -741,8 +741,12 @@ pub struct ProjectPanelSettingsContent { pub sort_mode: Option, /// Whether to show error and warning count badges next to file names in the project panel. /// - /// Default: true + /// Default: false pub diagnostic_badges: Option, + /// Whether to show a git status indicator next to file names in the project panel. + /// + /// Default: false + pub git_status_indicator: Option, } #[derive( diff --git a/crates/settings_ui/src/page_data.rs b/crates/settings_ui/src/page_data.rs index 6eb2f1dbf454ccd03492e5790a1f207f0fa47a56..5fa1679532aa9ad82801e78a929a8bfd59509818 100644 --- a/crates/settings_ui/src/page_data.rs +++ b/crates/settings_ui/src/page_data.rs @@ -4349,7 +4349,7 @@ fn window_and_layout_page() -> SettingsPage { } fn panels_page() -> SettingsPage { - fn project_panel_section() -> [SettingsPageItem; 23] { + fn project_panel_section() -> [SettingsPageItem; 24] { [ SettingsPageItem::SectionHeader("Project Panel"), SettingsPageItem::SettingItem(SettingItem { @@ -4697,6 +4697,28 @@ fn panels_page() -> SettingsPage { metadata: None, files: USER, }), + SettingsPageItem::SettingItem(SettingItem { + title: "Git Status Indicator", + description: "Show a git status indicator next to file names in the project panel.", + field: Box::new(SettingField { + json_path: Some("project_panel.git_status_indicator"), + pick: |settings_content| { + settings_content + .project_panel + .as_ref()? + .git_status_indicator + .as_ref() + }, + write: |settings_content, value| { + settings_content + .project_panel + .get_or_insert_default() + .git_status_indicator = value; + }, + }), + metadata: None, + files: USER, + }), SettingsPageItem::SettingItem(SettingItem { title: "Sticky Scroll", description: "Whether to stick parent directories at top of the project panel.", @@ -4771,7 +4793,7 @@ fn panels_page() -> SettingsPage { title: "Hide Root", description: "Whether to hide the root entry when only one folder is open in the window.", field: Box::new(SettingField { - json_path: Some("project_panel.drag_and_drop"), + json_path: Some("project_panel.hide_root"), pick: |settings_content| { settings_content.project_panel.as_ref()?.hide_root.as_ref() },