diff --git a/assets/settings/default.json b/assets/settings/default.json index 36c140dce7f8949ea73c163b9786b63ebeed0869..63ef8b51bb84c8f8dc5475dc172b82a78cee8eac 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -1316,7 +1316,10 @@ // "hunk_style": "staged_hollow" // 2. Show unstaged hunks hollow and staged hunks filled: // "hunk_style": "unstaged_hollow" - "hunk_style": "staged_hollow" + "hunk_style": "staged_hollow", + // Should the name or path be displayed first in the git view. + // "path_style": "file_name_first" or "file_path_first" + "path_style": "file_name_first" }, // The list of custom Git hosting providers. "git_hosting_providers": [ diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs index ad77820078d43bc72be12ff358f96b5f4edaea0e..5c86d79eee41e61d7cc904bfe148be6e8c9abdd2 100644 --- a/crates/git_ui/src/git_panel.rs +++ b/crates/git_ui/src/git_panel.rs @@ -51,6 +51,7 @@ use panel::{ use project::{ Fs, Project, ProjectPath, git_store::{GitStoreEvent, Repository, RepositoryEvent, RepositoryId, pending_op}, + project_settings::{GitPathStyle, ProjectSettings}, }; use serde::{Deserialize, Serialize}; use settings::{Settings, SettingsStore, StatusStyle}; @@ -3954,6 +3955,7 @@ impl GitPanel { cx: &Context, ) -> AnyElement { let path_style = self.project.read(cx).path_style(cx); + let git_path_style = ProjectSettings::get_global(cx).git.path_style; let display_name = entry.display_name(path_style); let selected = self.selected_entry == Some(ix); @@ -4053,7 +4055,6 @@ impl GitPanel { } else { cx.theme().colors().ghost_element_active }; - h_flex() .id(id) .h(self.list_item_height()) @@ -4151,28 +4152,70 @@ impl GitPanel { h_flex() .items_center() .flex_1() - // .overflow_hidden() - .when_some(entry.parent_dir(path_style), |this, parent| { - if !parent.is_empty() { - this.child( - self.entry_label( - format!("{parent}{}", path_style.separator()), - path_color, - ) - .when(status.is_deleted(), |this| this.strikethrough()), - ) - } else { - this - } - }) - .child( - self.entry_label(display_name, label_color) - .when(status.is_deleted(), |this| this.strikethrough()), - ), + .child(h_flex().items_center().flex_1().map(|this| { + self.path_formatted( + this, + entry.parent_dir(path_style), + path_color, + display_name, + label_color, + path_style, + git_path_style, + status.is_deleted(), + ) + })), ) .into_any_element() } + fn path_formatted( + &self, + parent: Div, + directory: Option, + path_color: Color, + file_name: String, + label_color: Color, + path_style: PathStyle, + git_path_style: GitPathStyle, + strikethrough: bool, + ) -> Div { + parent + .when(git_path_style == GitPathStyle::FileNameFirst, |this| { + this.child( + self.entry_label( + match directory.as_ref().is_none_or(|d| d.is_empty()) { + true => file_name.clone(), + false => format!("{file_name} "), + }, + label_color, + ) + .when(strikethrough, Label::strikethrough), + ) + }) + .when_some(directory, |this, dir| { + match ( + !dir.is_empty(), + git_path_style == GitPathStyle::FileNameFirst, + ) { + (true, true) => this.child( + self.entry_label(dir, path_color) + .when(strikethrough, Label::strikethrough), + ), + (true, false) => this.child( + self.entry_label(format!("{dir}{}", path_style.separator()), path_color) + .when(strikethrough, Label::strikethrough), + ), + _ => this, + } + }) + .when(git_path_style == GitPathStyle::FilePathFirst, |this| { + this.child( + self.entry_label(file_name, label_color) + .when(strikethrough, Label::strikethrough), + ) + }) + } + fn has_write_access(&self, cx: &App) -> bool { !self.project.read(cx).is_read_only(cx) } diff --git a/crates/project/src/project_settings.rs b/crates/project/src/project_settings.rs index 1bfd44957b2b0d75f8fda2b42a875c92e37d63f4..05d5612f7db5b35e3c2fe6513cc45a05ddaac68c 100644 --- a/crates/project/src/project_settings.rs +++ b/crates/project/src/project_settings.rs @@ -348,6 +348,26 @@ pub struct GitSettings { /// /// Default: staged_hollow pub hunk_style: settings::GitHunkStyleSetting, + /// How file paths are displayed in the git gutter. + /// + /// Default: file_name_first + pub path_style: GitPathStyle, +} + +#[derive(Clone, Copy, Debug, PartialEq, Default)] +pub enum GitPathStyle { + #[default] + FileNameFirst, + FilePathFirst, +} + +impl From for GitPathStyle { + fn from(style: settings::GitPathStyle) -> Self { + match style { + settings::GitPathStyle::FileNameFirst => GitPathStyle::FileNameFirst, + settings::GitPathStyle::FilePathFirst => GitPathStyle::FilePathFirst, + } + } } #[derive(Clone, Copy, Debug)] @@ -501,6 +521,7 @@ impl Settings for ProjectSettings { } }, hunk_style: git.hunk_style.unwrap(), + path_style: git.path_style.unwrap().into(), }; Self { context_servers: project diff --git a/crates/settings/src/settings_content/project.rs b/crates/settings/src/settings_content/project.rs index 83e0537940870bd944cb75f20e35cc522059570c..c9021ee22e4c419af544bea8e76387615e2a949d 100644 --- a/crates/settings/src/settings_content/project.rs +++ b/crates/settings/src/settings_content/project.rs @@ -311,6 +311,10 @@ pub struct GitSettings { /// /// Default: staged_hollow pub hunk_style: Option, + /// How file paths are displayed in the git gutter. + /// + /// Default: file_name_first + pub path_style: Option, } #[derive( @@ -406,6 +410,28 @@ pub enum GitHunkStyleSetting { UnstagedHollow, } +#[derive( + Copy, + Clone, + Debug, + PartialEq, + Default, + Serialize, + Deserialize, + JsonSchema, + MergeFrom, + strum::VariantArray, + strum::VariantNames, +)] +#[serde(rename_all = "snake_case")] +pub enum GitPathStyle { + /// Show file name first, then path + #[default] + FileNameFirst, + /// Show full path first + FilePathFirst, +} + #[skip_serializing_none] #[derive(Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)] pub struct DiagnosticsSettingsContent { diff --git a/crates/settings_ui/src/page_data.rs b/crates/settings_ui/src/page_data.rs index a6baaf94842955a323f348dcbae8130dcfd060c6..d5368e278914044196f55aaf852e2efefed07117 100644 --- a/crates/settings_ui/src/page_data.rs +++ b/crates/settings_ui/src/page_data.rs @@ -5494,6 +5494,19 @@ pub(crate) fn settings_data(cx: &App) -> Vec { metadata: None, files: USER, }), + SettingsPageItem::SettingItem(SettingItem { + title: "Path Style", + description: "Should the name or path be displayed first in the git view.", + field: Box::new(SettingField { + json_path: Some("git.path_style"), + pick: |settings_content| settings_content.git.as_ref()?.path_style.as_ref(), + write: |settings_content, value| { + settings_content.git.get_or_insert_default().path_style = value; + }, + }), + metadata: None, + files: USER, + }), ], }, SettingsPage { diff --git a/crates/settings_ui/src/settings_ui.rs b/crates/settings_ui/src/settings_ui.rs index 7b90464633c47caf7a2b11421fdbc6ac5aefe129..ef8cf4928665113a72d97b804931295d6181dde4 100644 --- a/crates/settings_ui/src/settings_ui.rs +++ b/crates/settings_ui/src/settings_ui.rs @@ -452,6 +452,7 @@ fn init_renderers(cx: &mut App) { .add_basic_renderer::(render_dropdown) .add_basic_renderer::(render_dropdown) .add_basic_renderer::(render_dropdown) + .add_basic_renderer::(render_dropdown) .add_basic_renderer::(render_dropdown) .add_basic_renderer::(render_dropdown) .add_basic_renderer::(render_dropdown)