diff --git a/crates/agent_ui/src/agent_panel.rs b/crates/agent_ui/src/agent_panel.rs index f522f05fdeb93ea0a2063f03f6da8827133e8648..abba2ae69b466f176116eb933a87082a2f1c5280 100644 --- a/crates/agent_ui/src/agent_panel.rs +++ b/crates/agent_ui/src/agent_panel.rs @@ -62,7 +62,7 @@ use gpui::{ use language::LanguageRegistry; use language_model::LanguageModelRegistry; use project::project_settings::ProjectSettings; -use project::{Project, ProjectPath, Worktree}; +use project::{Project, ProjectPath, Worktree, linked_worktree_short_name}; use prompt_store::{PromptStore, UserPromptId}; use rules_library::{RulesLibrary, open_rules_library}; use settings::TerminalDockPosition; @@ -641,6 +641,18 @@ impl StartThreadIn { } } + if let Some(name) = linked_worktree_short_name( + repo.original_repo_abs_path.as_ref(), + repo.work_directory_abs_path.as_ref(), + ) { + if visible_paths + .iter() + .any(|p| p.as_path() == repo.work_directory_abs_path.as_ref()) + { + return Some(SharedString::from(format!("({})", name))); + } + } + if visible_paths .iter() .any(|p| p.as_path() == work_dir.as_ref()) diff --git a/crates/git_ui/src/branch_picker.rs b/crates/git_ui/src/branch_picker.rs index 2bf4a1991f7a302ed73fe098e8914fedd0f9eb2a..f46eb08ef9caf35b3e8fab1ce65c449f76ea2ed4 100644 --- a/crates/git_ui/src/branch_picker.rs +++ b/crates/git_ui/src/branch_picker.rs @@ -885,12 +885,16 @@ impl PickerDelegate for BranchListDelegate { }) .unwrap_or_else(|| (None, None, None)); + let is_head_branch = entry.as_branch().is_some_and(|branch| branch.is_head); + let entry_icon = match entry { Entry::NewUrl { .. } | Entry::NewBranch { .. } | Entry::NewRemoteName { .. } => { IconName::Plus } Entry::Branch { branch, .. } => { - if branch.is_remote() { + if is_head_branch { + IconName::Check + } else if branch.is_remote() { IconName::Screen } else { IconName::GitBranchAlt @@ -975,7 +979,11 @@ impl PickerDelegate for BranchListDelegate { .flex_grow() .child( Icon::new(entry_icon) - .color(Color::Muted) + .color(if is_head_branch { + Color::Accent + } else { + Color::Muted + }) .size(IconSize::Small), ) .child( diff --git a/crates/git_ui/src/worktree_picker.rs b/crates/git_ui/src/worktree_picker.rs index bd1d694fa30bb914569fbb5e6e3c67de3e3d86a0..6c95f42e99169370a08119bc22e2b71e33cb270d 100644 --- a/crates/git_ui/src/worktree_picker.rs +++ b/crates/git_ui/src/worktree_picker.rs @@ -19,13 +19,15 @@ use remote_connection::{RemoteConnectionModal, connect}; use settings::Settings; use std::{path::PathBuf, sync::Arc}; use ui::{HighlightedLabel, KeyBinding, ListItem, ListItemSpacing, Tooltip, prelude::*}; -use util::{ResultExt, debug_panic}; +use util::{ResultExt, debug_panic, paths::PathExt}; use workspace::{ ModalView, MultiWorkspace, OpenMode, Workspace, notifications::DetachAndPromptErr, }; use crate::git_panel::show_error_toast; +const MAIN_WORKTREE_DISPLAY_NAME: &str = "main"; + actions!( git, [ @@ -273,6 +275,7 @@ pub struct WorktreeListDelegate { focus_handle: FocusHandle, default_branch: Option, forbidden_deletion_path: Option, + current_worktree_path: Option, } impl WorktreeListDelegate { @@ -282,6 +285,10 @@ impl WorktreeListDelegate { _window: &mut Window, cx: &mut Context, ) -> Self { + let current_worktree_path = repo + .as_ref() + .map(|r| r.read(cx).work_directory_abs_path.to_path_buf()); + Self { matches: vec![], all_worktrees: None, @@ -293,6 +300,7 @@ impl WorktreeListDelegate { focus_handle: cx.focus_handle(), default_branch: None, forbidden_deletion_path: None, + current_worktree_path, } } @@ -699,7 +707,14 @@ impl PickerDelegate for WorktreeListDelegate { let candidates = all_worktrees .iter() .enumerate() - .map(|(ix, worktree)| StringMatchCandidate::new(ix, worktree.display_name())) + .map(|(ix, worktree)| { + let name = if worktree.is_main { + MAIN_WORKTREE_DISPLAY_NAME + } else { + worktree.display_name() + }; + StringMatchCandidate::new(ix, name) + }) .collect::>(); fuzzy::match_strings( &candidates, @@ -722,9 +737,14 @@ impl PickerDelegate for WorktreeListDelegate { picker .update(cx, |picker, _| { if !query.is_empty() - && !matches - .first() - .is_some_and(|entry| entry.worktree.display_name() == query) + && !matches.first().is_some_and(|entry| { + let name = if entry.worktree.is_main { + MAIN_WORKTREE_DISPLAY_NAME + } else { + entry.worktree.display_name() + }; + name == query + }) { let query = query.replace(' ', "-"); matches.push(WorktreeEntry { @@ -777,7 +797,7 @@ impl PickerDelegate for WorktreeListDelegate { cx: &mut Context>, ) -> Option { let entry = &self.matches.get(ix)?; - let path = entry.worktree.path.to_string_lossy().to_string(); + let path = entry.worktree.path.compact().to_string_lossy().to_string(); let sha = entry .worktree .sha @@ -800,17 +820,21 @@ impl PickerDelegate for WorktreeListDelegate { ), ) } else { - let branch = entry.worktree.display_name(); - let branch_first_line = branch.lines().next().unwrap_or(branch); + let display_name = if entry.worktree.is_main { + MAIN_WORKTREE_DISPLAY_NAME + } else { + entry.worktree.display_name() + }; + let first_line = display_name.lines().next().unwrap_or(display_name); let positions: Vec<_> = entry .positions .iter() .copied() - .filter(|&pos| pos < branch_first_line.len()) + .filter(|&pos| pos < first_line.len()) .collect(); ( - HighlightedLabel::new(branch_first_line.to_owned(), positions) + HighlightedLabel::new(first_line.to_owned(), positions) .truncate() .into_any_element(), path, @@ -832,8 +856,16 @@ impl PickerDelegate for WorktreeListDelegate { })) }; + let is_current = !entry.is_new + && self + .current_worktree_path + .as_ref() + .is_some_and(|current| *current == entry.worktree.path); + let entry_icon = if entry.is_new { IconName::Plus + } else if is_current { + IconName::Check } else { IconName::GitWorktree }; @@ -849,7 +881,11 @@ impl PickerDelegate for WorktreeListDelegate { .gap_2p5() .child( Icon::new(entry_icon) - .color(Color::Muted) + .color(if is_current { + Color::Accent + } else { + Color::Muted + }) .size(IconSize::Small), ) .child(v_flex().w_full().child(branch_name).map(|this| { @@ -879,7 +915,7 @@ impl PickerDelegate for WorktreeListDelegate { ) .child( Label::new(sublabel) - .truncate() + .truncate_start() .color(Color::Muted) .size(LabelSize::Small) .flex_1(),