Detailed changes
@@ -0,0 +1,6 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M8 14.0043V8.59991" stroke="#C6CAD0" stroke-width="1.20097" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M9.9035 2.12072C10.0531 2.0371 10.2216 1.99319 10.3929 1.99319C10.5642 1.99319 10.7327 2.0371 10.8823 2.12072L13.4043 3.53786C13.5829 3.63887 13.7315 3.78548 13.8349 3.96272C13.9383 4.13997 13.9928 4.34148 13.9928 4.54668C13.9928 4.75187 13.9383 4.95339 13.8349 5.13063C13.7315 5.30787 13.5829 5.45449 13.4043 5.55549L6.09043 9.67481C5.94043 9.76037 5.77072 9.80537 5.59804 9.80537C5.42535 9.80537 5.25564 9.76037 5.10564 9.67481L2.59562 8.25767C2.417 8.15666 2.2684 8.01005 2.16501 7.83281C2.06162 7.65556 2.00714 7.45405 2.00714 7.24885C2.00714 7.04366 2.06162 6.84214 2.16501 6.6649C2.2684 6.48766 2.417 6.34104 2.59562 6.24004L9.9035 2.12072Z" stroke="#C6CAD0" stroke-width="1.20097" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M12.8038 8.59991V10.9238C12.8041 11.1504 12.742 11.3728 12.6245 11.5666C12.507 11.7604 12.3384 11.9181 12.1373 12.0227L8.53441 13.8722C8.36933 13.958 8.18602 14.0027 7.99998 14.0027C7.81394 14.0027 7.63063 13.958 7.46555 13.8722L3.86264 12.0227C3.66153 11.9181 3.493 11.7604 3.37546 11.5666C3.25791 11.3728 3.19587 11.1504 3.19611 10.9238V8.59991" stroke="#C6CAD0" stroke-width="1.20097" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M13.4043 8.25766C13.5829 8.15666 13.7315 8.01004 13.8349 7.8328C13.9383 7.65556 13.9928 7.45404 13.9928 7.24885C13.9928 7.04365 13.9383 6.84213 13.8349 6.66489C13.7315 6.48765 13.5829 6.34103 13.4043 6.24003L6.09644 2.11471C5.94745 2.02938 5.77874 1.9845 5.60704 1.9845C5.43535 1.9845 5.26664 2.02938 5.11765 2.11471L2.59562 3.53785C2.417 3.63886 2.2684 3.78547 2.16501 3.96271C2.06162 4.13996 2.00714 4.34147 2.00714 4.54667C2.00714 4.75186 2.06162 4.95338 2.16501 5.13062C2.2684 5.30786 2.417 5.45448 2.59562 5.55548L9.90951 9.6748C10.0584 9.76036 10.2272 9.80538 10.3989 9.80538C10.5706 9.80538 10.7394 9.76036 10.8883 9.6748L13.4043 8.25766Z" stroke="#C6CAD0" stroke-width="1.20097" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
@@ -559,8 +559,7 @@ impl PickerDelegate for BranchListDelegate {
match self.state {
PickerState::List | PickerState::NewRemote | PickerState::NewBranch => {
match self.branch_filter {
- BranchFilter::All => "Select branch or remote…",
- BranchFilter::Remote => "Select remote…",
+ BranchFilter::All | BranchFilter::Remote => "Select branch…",
}
}
PickerState::CreateRemote(_) => "Enter a name for this remote…",
@@ -884,13 +883,13 @@ impl PickerDelegate for BranchListDelegate {
let entry_icon = match entry {
Entry::NewUrl { .. } | Entry::NewBranch { .. } | Entry::NewRemoteName { .. } => {
- Icon::new(IconName::Plus).color(Color::Muted)
+ IconName::Plus
}
Entry::Branch { branch, .. } => {
if branch.is_remote() {
- Icon::new(IconName::Screen).color(Color::Muted)
+ IconName::Screen
} else {
- Icon::new(IconName::GitBranchAlt).color(Color::Muted)
+ IconName::GitBranchAlt
}
}
};
@@ -922,8 +921,11 @@ impl PickerDelegate for BranchListDelegate {
Entry::NewUrl { .. } | Entry::NewBranch { .. } | Entry::NewRemoteName { .. }
);
- let deleted_branch_icon = |entry_ix: usize, is_head_branch: bool| {
+ let is_head_branch = entry.as_branch().is_some_and(|branch| branch.is_head);
+
+ let deleted_branch_icon = |entry_ix: usize| {
IconButton::new(("delete", entry_ix), IconName::Trash)
+ .icon_size(IconSize::Small)
.tooltip(move |_, cx| {
Tooltip::for_action_in(
"Delete Branch",
@@ -932,7 +934,6 @@ impl PickerDelegate for BranchListDelegate {
cx,
)
})
- .disabled(is_head_branch)
.on_click(cx.listener(move |this, _, window, cx| {
this.delegate.delete_at(entry_ix, window, cx);
}))
@@ -943,6 +944,7 @@ impl PickerDelegate for BranchListDelegate {
let focus_handle = self.focus_handle.clone();
IconButton::new("create_from_default", IconName::GitBranchPlus)
+ .icon_size(IconSize::Small)
.tooltip(move |_, cx| {
Tooltip::for_action_in(
tooltip_label.clone(),
@@ -965,105 +967,132 @@ impl PickerDelegate for BranchListDelegate {
.child(
h_flex()
.w_full()
- .gap_3()
+ .gap_2p5()
.flex_grow()
- .child(entry_icon)
+ .child(
+ Icon::new(entry_icon)
+ .color(Color::Muted)
+ .size(IconSize::Small),
+ )
.child(
v_flex()
.id("info_container")
.w_full()
.child(entry_title)
- .child(
- h_flex()
- .w_full()
- .justify_between()
- .gap_1p5()
- .when(self.style == BranchListStyle::Modal, |el| {
- el.child(div().max_w_96().child({
- let message = match entry {
- Entry::NewUrl { url } => {
- format!("Based off {url}")
- }
- Entry::NewRemoteName { url, .. } => {
- format!("Based off {url}")
- }
- Entry::NewBranch { .. } => {
- if let Some(current_branch) =
- self.repo.as_ref().and_then(|repo| {
- repo.read(cx)
- .branch
- .as_ref()
- .map(|b| b.name())
- })
- {
- format!("Based off {}", current_branch)
- } else {
- "Based off the current branch"
- .to_string()
- }
- }
- Entry::Branch { .. } => {
- let show_author_name =
- ProjectSettings::get_global(cx)
- .git
- .branch_picker
- .show_author_name;
-
- subject.map_or(
- "No commits found".into(),
- |subject| {
- if show_author_name
- && let Some(author) =
- author_name
- {
- format!(
- "{} • {}",
- author, subject
- )
- } else {
- subject.to_string()
- }
- },
- )
- }
- };
-
- Label::new(message)
- .size(LabelSize::Small)
- .color(Color::Muted)
- .truncate()
- }))
- })
- .when_some(commit_time, |label, commit_time| {
- label.child(
- Label::new(commit_time)
- .size(LabelSize::Small)
- .color(Color::Muted),
- )
- }),
- )
+ .child({
+ let message = match entry {
+ Entry::NewUrl { url } => format!("Based off {url}"),
+ Entry::NewRemoteName { url, .. } => {
+ format!("Based off {url}")
+ }
+ Entry::NewBranch { .. } => {
+ if let Some(current_branch) =
+ self.repo.as_ref().and_then(|repo| {
+ repo.read(cx).branch.as_ref().map(|b| b.name())
+ })
+ {
+ format!("Based off {}", current_branch)
+ } else {
+ "Based off the current branch".to_string()
+ }
+ }
+ Entry::Branch { .. } => String::new(),
+ };
+
+ if matches!(entry, Entry::Branch { .. }) {
+ let show_author_name = ProjectSettings::get_global(cx)
+ .git
+ .branch_picker
+ .show_author_name;
+ let has_author = show_author_name && author_name.is_some();
+ let has_commit = commit_time.is_some();
+ let author_for_meta =
+ if show_author_name { author_name } else { None };
+
+ let dot = || {
+ Label::new("•")
+ .alpha(0.5)
+ .color(Color::Muted)
+ .size(LabelSize::Small)
+ };
+
+ h_flex()
+ .w_full()
+ .min_w_0()
+ .gap_1p5()
+ .when_some(author_for_meta, |this, author| {
+ this.child(
+ Label::new(author)
+ .color(Color::Muted)
+ .size(LabelSize::Small),
+ )
+ })
+ .when_some(commit_time, |this, time| {
+ this.when(has_author, |this| this.child(dot()))
+ .child(
+ Label::new(time)
+ .color(Color::Muted)
+ .size(LabelSize::Small),
+ )
+ })
+ .when_some(subject, |this, subj| {
+ this.when(has_commit, |this| this.child(dot()))
+ .child(
+ Label::new(subj.to_string())
+ .color(Color::Muted)
+ .size(LabelSize::Small)
+ .truncate()
+ .flex_1(),
+ )
+ })
+ .when(!has_commit, |this| {
+ this.child(
+ Label::new("No commits found")
+ .color(Color::Muted)
+ .size(LabelSize::Small),
+ )
+ })
+ .into_any_element()
+ } else {
+ Label::new(message)
+ .size(LabelSize::Small)
+ .color(Color::Muted)
+ .truncate()
+ .into_any_element()
+ }
+ })
.when_some(
entry.as_branch().map(|b| b.name().to_string()),
- |this, branch_name| this.tooltip(Tooltip::text(branch_name)),
+ |this, branch_name| {
+ this.map(|this| {
+ if is_head_branch {
+ this.tooltip(move |_, cx| {
+ Tooltip::with_meta(
+ branch_name.clone(),
+ None,
+ "Current Branch",
+ cx,
+ )
+ })
+ } else {
+ this.tooltip(Tooltip::text(branch_name))
+ }
+ })
+ },
),
),
)
- .when(
- self.editor_position() == PickerEditorPosition::End && !is_new_items,
- |this| {
- this.map(|this| {
- let is_head_branch =
- entry.as_branch().is_some_and(|branch| branch.is_head);
- if self.selected_index() == ix {
- this.end_slot(deleted_branch_icon(ix, is_head_branch))
- } else {
- this.end_hover_slot(deleted_branch_icon(ix, is_head_branch))
- }
- })
- },
- )
+ .when(!is_new_items && !is_head_branch, |this| {
+ this.map(|this| {
+ if self.selected_index() == ix {
+ this.end_slot(deleted_branch_icon(ix))
+ } else {
+ this.end_hover_slot(deleted_branch_icon(ix))
+ }
+ })
+ })
.when_some(
- if self.editor_position() == PickerEditorPosition::End && is_new_items {
+ if is_new_items {
create_from_default_button
} else {
None
@@ -468,7 +468,7 @@ impl PickerDelegate for StashListDelegate {
ix: usize,
selected: bool,
_window: &mut Window,
- _cx: &mut Context<Picker<Self>>,
+ cx: &mut Context<Picker<Self>>,
) -> Option<Self::ListItem> {
let entry_match = &self.matches[ix];
@@ -501,16 +501,46 @@ impl PickerDelegate for StashListDelegate {
.size(LabelSize::Small),
);
+ let focus_handle = self.focus_handle.clone();
+
+ let drop_button = |entry_ix: usize| {
+ IconButton::new(("drop-stash", entry_ix), IconName::Trash)
+ .icon_size(IconSize::Small)
+ .tooltip(move |_, cx| {
+ Tooltip::for_action_in("Drop Stash", &DropStashItem, &focus_handle, cx)
+ })
+ .on_click(cx.listener(move |this, _, window, cx| {
+ this.delegate.drop_stash_at(entry_ix, window, cx);
+ }))
+ };
+
Some(
ListItem::new(format!("stash-{ix}"))
.inset(true)
.spacing(ListItemSpacing::Sparse)
.toggle_state(selected)
- .child(v_flex().w_full().child(stash_label).child(branch_info))
+ .child(
+ h_flex()
+ .w_full()
+ .gap_2p5()
+ .child(
+ Icon::new(IconName::BoxOpen)
+ .size(IconSize::Small)
+ .color(Color::Muted),
+ )
+ .child(div().w_full().child(stash_label).child(branch_info)),
+ )
.tooltip(Tooltip::text(format!(
"stash@{{{}}}",
entry_match.entry.index
- ))),
+ )))
+ .map(|this| {
+ if selected {
+ this.end_slot(drop_button(ix))
+ } else {
+ this.end_hover_slot(drop_button(ix))
+ }
+ }),
)
}
@@ -18,7 +18,7 @@ use remote::{RemoteConnectionOptions, remote_client::ConnectionIdentifier};
use remote_connection::{RemoteConnectionModal, connect};
use settings::Settings;
use std::{path::PathBuf, sync::Arc};
-use ui::{HighlightedLabel, KeyBinding, ListItem, ListItemSpacing, prelude::*};
+use ui::{HighlightedLabel, KeyBinding, ListItem, ListItemSpacing, Tooltip, prelude::*};
use util::ResultExt;
use workspace::{ModalView, MultiWorkspace, Workspace, notifications::DetachAndPromptErr};
@@ -769,38 +769,83 @@ impl PickerDelegate for WorktreeListDelegate {
)
};
+ let focus_handle = self.focus_handle.clone();
+
+ let delete_button = |entry_ix: usize| {
+ IconButton::new(("delete-worktree", entry_ix), IconName::Trash)
+ .icon_size(IconSize::Small)
+ .tooltip(move |_, cx| {
+ Tooltip::for_action_in("Delete Worktree", &DeleteWorktree, &focus_handle, cx)
+ })
+ .on_click(cx.listener(move |this, _, window, cx| {
+ this.delegate.delete_at(entry_ix, window, cx);
+ }))
+ };
+
+ let entry_icon = if entry.is_new {
+ IconName::Plus
+ } else {
+ IconName::GitWorktree
+ };
+
Some(
ListItem::new(format!("worktree-menu-{ix}"))
.inset(true)
.spacing(ListItemSpacing::Sparse)
.toggle_state(selected)
.child(
- v_flex()
+ h_flex()
.w_full()
+ .gap_2p5()
.child(
- h_flex()
- .gap_2()
- .justify_between()
- .overflow_x_hidden()
- .child(branch_name)
- .when(!entry.is_new, |this| {
- this.child(
- Label::new(sha)
- .size(LabelSize::Small)
- .color(Color::Muted)
- .buffer_font(cx)
- .into_element(),
- )
- }),
- )
- .child(
- Label::new(sublabel)
- .size(LabelSize::Small)
+ Icon::new(entry_icon)
.color(Color::Muted)
- .truncate()
- .into_any_element(),
- ),
- ),
+ .size(IconSize::Small),
+ )
+ .child(v_flex().w_full().child(branch_name).map(|this| {
+ if entry.is_new {
+ this.child(
+ Label::new(sublabel)
+ .size(LabelSize::Small)
+ .color(Color::Muted)
+ .truncate(),
+ )
+ } else {
+ this.child(
+ h_flex()
+ .w_full()
+ .min_w_0()
+ .gap_1p5()
+ .child(
+ Label::new(sha)
+ .size(LabelSize::Small)
+ .color(Color::Muted),
+ )
+ .child(
+ Label::new("•")
+ .alpha(0.5)
+ .color(Color::Muted)
+ .size(LabelSize::Small),
+ )
+ .child(
+ Label::new(sublabel)
+ .truncate()
+ .color(Color::Muted)
+ .size(LabelSize::Small)
+ .flex_1(),
+ )
+ .into_any_element(),
+ )
+ }
+ })),
+ )
+ .when(!entry.is_new, |this| {
+ if selected {
+ this.end_slot(delete_button(ix))
+ } else {
+ this.end_hover_slot(delete_button(ix))
+ }
+ }),
)
}
@@ -53,6 +53,7 @@ pub enum IconName {
Book,
BookCopy,
Box,
+ BoxOpen,
CaseSensitive,
Chat,
Check,