@@ -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())
@@ -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(
@@ -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<SharedString>,
forbidden_deletion_path: Option<PathBuf>,
+ current_worktree_path: Option<PathBuf>,
}
impl WorktreeListDelegate {
@@ -282,6 +285,10 @@ impl WorktreeListDelegate {
_window: &mut Window,
cx: &mut Context<WorktreeList>,
) -> 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::<Vec<StringMatchCandidate>>();
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<Picker<Self>>,
) -> Option<Self::ListItem> {
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(),