diff --git a/assets/settings/default.json b/assets/settings/default.json index 439e82943f..bf423f84b5 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -843,6 +843,8 @@ "button": true, // Whether to hide the gitignore entries in the project panel. "hide_gitignore": false, + // Delay in milliseconds before tooltips appear for project panel titles. + "title_tooltip_delay": "default", // Default width of the project panel. "default_width": 240, // Where to dock the project panel. Can be 'left' or 'right'. diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 9dc8c56acb..ccf7a7dff9 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -52,8 +52,7 @@ use std::{ cell::OnceCell, cmp, collections::HashSet, - ops::Neg, - ops::Range, + ops::{Neg, Range}, path::{Path, PathBuf}, sync::Arc, time::{Duration, Instant}, @@ -68,7 +67,7 @@ use util::{ ResultExt, TakeUntilExt, TryFutureExt, markdown::MarkdownInlineCode, maybe, - paths::{PathStyle, compare_paths}, + paths::{PathExt, PathStyle, compare_paths}, rel_path::{RelPath, RelPathBuf}, }; use workspace::{ @@ -5875,10 +5874,39 @@ impl ProjectPanel { (entry_id.to_proto() as usize).into() }; + let tooltip_path = self + .project + .read(cx) + .worktree_for_id(worktree_id, cx) + .map(|worktree| { + worktree + .read(cx) + .absolutize(&path) + .compact() + .to_string_lossy() + .into_owned() + }); + div() .id(id.clone()) .relative() .group(GROUP_NAME) + .when_some( + tooltip_path.and_then(|path| { + let delay = match settings.title_tooltip_delay { + settings::ProjectPanelTitleTooltipDelay::Default => 1500, + settings::ProjectPanelTitleTooltipDelay::Custom(delay_ms) => delay_ms.0, + settings::ProjectPanelTitleTooltipDelay::Disabled => { + return None; + } + }; + Some((path, delay)) + }), + |this, (path, delay)| { + this.tooltip_show_delay(Duration::from_millis(delay)) + .tooltip(Tooltip::text(path)) + }, + ) .cursor_pointer() .rounded_none() .bg(bg_color) diff --git a/crates/project_panel/src/project_panel_settings.rs b/crates/project_panel/src/project_panel_settings.rs index f4ca810d03..ff0330158f 100644 --- a/crates/project_panel/src/project_panel_settings.rs +++ b/crates/project_panel/src/project_panel_settings.rs @@ -4,7 +4,8 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use settings::{ DockSide, FolderIndicator, IntoGpui, ProjectPanelEntrySpacing, ProjectPanelSortMode, - ProjectPanelSortOrder, RegisterSetting, Settings, ShowDiagnostics, ShowIndentGuides, + ProjectPanelSortOrder, ProjectPanelTitleTooltipDelay, RegisterSetting, Settings, + ShowDiagnostics, ShowIndentGuides, }; use ui::scrollbars::{ScrollbarVisibility, ShowScrollbar}; @@ -13,6 +14,7 @@ pub struct ProjectPanelSettings { pub button: bool, pub hide_gitignore: bool, pub default_width: Pixels, + pub title_tooltip_delay: ProjectPanelTitleTooltipDelay, pub dock: DockSide, pub entry_spacing: ProjectPanelEntrySpacing, pub file_icons: bool, @@ -99,6 +101,7 @@ impl Settings for ProjectPanelSettings { hide_gitignore: project_panel.hide_gitignore.unwrap(), default_width: project_panel.default_width.unwrap().into_gpui(), dock: project_panel.dock.unwrap(), + title_tooltip_delay: project_panel.title_tooltip_delay.unwrap(), entry_spacing: project_panel.entry_spacing.unwrap(), file_icons: project_panel.file_icons.unwrap(), folder_indicator: project_panel.folder_indicator.unwrap(), diff --git a/crates/settings/src/vscode_import.rs b/crates/settings/src/vscode_import.rs index a490b80518..582fcf01d3 100644 --- a/crates/settings/src/vscode_import.rs +++ b/crates/settings/src/vscode_import.rs @@ -827,6 +827,7 @@ impl VsCodeSettings { auto_reveal_entries: self.read_bool("explorer.autoReveal"), bold_folder_labels: None, button: None, + title_tooltip_delay: None, default_width: None, dock: None, drag_and_drop: None, diff --git a/crates/settings_content/src/workspace.rs b/crates/settings_content/src/workspace.rs index b631533a42..bcbcadcc8a 100644 --- a/crates/settings_content/src/workspace.rs +++ b/crates/settings_content/src/workspace.rs @@ -808,6 +808,8 @@ pub struct ProjectPanelSettingsContent { /// /// Default: right (Agentic layout), left (Classic layout) pub dock: Option, + // TODO + pub title_tooltip_delay: Option, /// Spacing between worktree entries in the project panel. /// /// Default: comfortable @@ -893,6 +895,31 @@ pub struct ProjectPanelSettingsContent { pub git_status_indicator: Option, } +/// Controls the width of the git diff hunk indicators in the gutter. +#[derive( + Clone, + Copy, + Debug, + Default, + Serialize, + Deserialize, + JsonSchema, + MergeFrom, + PartialEq, + strum::EnumDiscriminants, +)] +#[strum_discriminants(derive(strum::VariantArray, strum::VariantNames, strum::FromRepr))] +#[serde(rename_all = "snake_case")] +pub enum ProjectPanelTitleTooltipDelay { + /// Default is 1500ms. + #[default] + Default, + /// A custom offset in milliseconds for the tooltip show delay. + Custom(crate::DelayMs), + /// Disables the tooltip + Disabled, +} + #[derive( Copy, Clone, diff --git a/crates/settings_ui/src/page_data.rs b/crates/settings_ui/src/page_data.rs index 890fbaf2a5..d647652289 100644 --- a/crates/settings_ui/src/page_data.rs +++ b/crates/settings_ui/src/page_data.rs @@ -5265,7 +5265,7 @@ fn window_and_layout_page() -> SettingsPage { } fn panels_page() -> SettingsPage { - fn project_panel_section() -> [SettingsPageItem; 29] { + fn project_panel_section() -> [SettingsPageItem; 30] { [ SettingsPageItem::SectionHeader("Project Panel"), SettingsPageItem::SettingItem(SettingItem { @@ -5305,6 +5305,105 @@ fn panels_page() -> SettingsPage { metadata: None, files: USER, }), + SettingsPageItem::DynamicItem(DynamicItem { + discriminant: SettingItem { + title: "Project Panel Title Tooltips Delay", + description: "Delay in milliseconds before tooltips appear for project panel titles.", + field: Box::new(SettingField { + organization_override: None, + json_path: Some("project_panel.title_tooltip_delay$"), + pick: |settings_content| { + Some( + &dynamic_variants::() + [settings_content + .project_panel + .as_ref()? + .title_tooltip_delay + .as_ref()? + .discriminant() + as usize], + ) + }, + write: |settings_content, value, _| { + let project_panel = + settings_content.project_panel.get_or_insert_default(); + project_panel.title_tooltip_delay = value.map(|value| match value { + settings::ProjectPanelTitleTooltipDelayDiscriminants::Default => { + settings::ProjectPanelTitleTooltipDelay::Default + } + settings::ProjectPanelTitleTooltipDelayDiscriminants::Disabled => { + settings::ProjectPanelTitleTooltipDelay::Disabled + } + settings::ProjectPanelTitleTooltipDelayDiscriminants::Custom => { + let delay = match project_panel.title_tooltip_delay { + Some(settings::ProjectPanelTitleTooltipDelay::Custom( + delay, + )) => settings::DelayMs(delay.0), + _ => settings::DelayMs(1500), + }; + settings::ProjectPanelTitleTooltipDelay::Custom(delay) + } + }); + }, + }), + metadata: None, + files: USER, + }, + pick_discriminant: |settings_content| { + Some( + settings_content + .project_panel + .as_ref()? + .title_tooltip_delay + .as_ref()? + .discriminant() as usize, + ) + }, + fields: dynamic_variants::() + .into_iter() + .map(|variant| match variant { + settings::ProjectPanelTitleTooltipDelayDiscriminants::Default => vec![], + settings::ProjectPanelTitleTooltipDelayDiscriminants::Disabled => vec![], + settings::ProjectPanelTitleTooltipDelayDiscriminants::Custom => { + vec![SettingItem { + files: USER, + title: "Custom Delay", + description: "Delay in milliseconds of the project panel title tooltips.", + field: Box::new(SettingField { + organization_override: None, + json_path: Some("project_panel.title_tooltip_delay"), + pick: |settings_content| match settings_content + .project_panel + .as_ref() + .and_then(|project_panel| { + project_panel.title_tooltip_delay.as_ref() + }) { + Some(settings::ProjectPanelTitleTooltipDelay::Custom( + value, + )) => Some(value), + _ => None, + }, + write: |settings_content, value, _| { + let Some(value) = value else { + return; + }; + if let Some( + settings::ProjectPanelTitleTooltipDelay::Custom(width), + ) = settings_content.project_panel.as_mut().and_then( + |project_panel| { + project_panel.title_tooltip_delay.as_mut() + }, + ) { + *width = value; + } + }, + }), + metadata: None, + }] + } + }) + .collect(), + }), SettingsPageItem::SettingItem(SettingItem { title: "Hide .gitignore", description: "Whether to hide the gitignore entries in the project panel.", diff --git a/crates/settings_ui/src/settings_ui.rs b/crates/settings_ui/src/settings_ui.rs index 7f4d4c53b5..12ede658ba 100644 --- a/crates/settings_ui/src/settings_ui.rs +++ b/crates/settings_ui/src/settings_ui.rs @@ -656,6 +656,7 @@ fn init_renderers(cx: &mut App) { .add_basic_renderer::(render_icon_theme_picker) .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)