picker: Reintroduce headers and footers (#3786)
Update VCS menu to match Zed1. <img width="444" alt="image" src="https://github.com/zed-industries/zed/assets/24362066/6cb27510-f501-46bc-862f-1fb78006b77c"> Release Notes: - N/A
This commit is contained in:
parent
87ff5f04cb
commit
25a5eda76f
2 changed files with 86 additions and 92 deletions
|
@ -1,8 +1,8 @@
|
||||||
use editor::Editor;
|
use editor::Editor;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, prelude::*, uniform_list, AppContext, DismissEvent, Div, EventEmitter, FocusHandle,
|
div, prelude::*, uniform_list, AnyElement, AppContext, DismissEvent, Div, EventEmitter,
|
||||||
FocusableView, Length, MouseButton, MouseDownEvent, Render, Task, UniformListScrollHandle,
|
FocusHandle, FocusableView, Length, MouseButton, MouseDownEvent, Render, Task,
|
||||||
View, ViewContext, WindowContext,
|
UniformListScrollHandle, View, ViewContext, WindowContext,
|
||||||
};
|
};
|
||||||
use std::{cmp, sync::Arc};
|
use std::{cmp, sync::Arc};
|
||||||
use ui::{prelude::*, v_stack, Color, Divider, Label, ListItem, ListItemSpacing};
|
use ui::{prelude::*, v_stack, Color, Divider, Label, ListItem, ListItemSpacing};
|
||||||
|
@ -40,6 +40,12 @@ pub trait PickerDelegate: Sized + 'static {
|
||||||
selected: bool,
|
selected: bool,
|
||||||
cx: &mut ViewContext<Picker<Self>>,
|
cx: &mut ViewContext<Picker<Self>>,
|
||||||
) -> Option<Self::ListItem>;
|
) -> Option<Self::ListItem>;
|
||||||
|
fn render_header(&self, _: &mut ViewContext<Picker<Self>>) -> Option<AnyElement> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn render_footer(&self, _: &mut ViewContext<Picker<Self>>) -> Option<AnyElement> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: PickerDelegate> FocusableView for Picker<D> {
|
impl<D: PickerDelegate> FocusableView for Picker<D> {
|
||||||
|
@ -253,6 +259,7 @@ impl<D: PickerDelegate> Render for Picker<D> {
|
||||||
v_stack()
|
v_stack()
|
||||||
.flex_grow()
|
.flex_grow()
|
||||||
.py_2()
|
.py_2()
|
||||||
|
.children(self.delegate.render_header(cx))
|
||||||
.child(
|
.child(
|
||||||
uniform_list(
|
uniform_list(
|
||||||
cx.view().clone(),
|
cx.view().clone(),
|
||||||
|
@ -286,6 +293,7 @@ impl<D: PickerDelegate> Render for Picker<D> {
|
||||||
)
|
)
|
||||||
.track_scroll(self.scroll_handle.clone())
|
.track_scroll(self.scroll_handle.clone())
|
||||||
)
|
)
|
||||||
|
|
||||||
.max_h_72()
|
.max_h_72()
|
||||||
.overflow_hidden(),
|
.overflow_hidden(),
|
||||||
)
|
)
|
||||||
|
@ -301,5 +309,6 @@ impl<D: PickerDelegate> Render for Picker<D> {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
.children(self.delegate.render_footer(cx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,16 @@ use anyhow::{anyhow, bail, Result};
|
||||||
use fs::repository::Branch;
|
use fs::repository::Branch;
|
||||||
use fuzzy::{StringMatch, StringMatchCandidate};
|
use fuzzy::{StringMatch, StringMatchCandidate};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, rems, AppContext, DismissEvent, Div, EventEmitter, FocusHandle, FocusableView,
|
actions, rems, AnyElement, AppContext, DismissEvent, Div, Element, EventEmitter, FocusHandle,
|
||||||
InteractiveElement, ParentElement, Render, SharedString, Styled, Subscription, Task, View,
|
FocusableView, InteractiveElement, IntoElement, ParentElement, Render, SharedString, Styled,
|
||||||
ViewContext, VisualContext, WindowContext,
|
Subscription, Task, View, ViewContext, VisualContext, WindowContext,
|
||||||
};
|
};
|
||||||
use picker::{Picker, PickerDelegate};
|
use picker::{Picker, PickerDelegate};
|
||||||
use std::sync::Arc;
|
use std::{ops::Not, sync::Arc};
|
||||||
use ui::{v_stack, HighlightedLabel, ListItem, ListItemSpacing, Selectable};
|
use ui::{
|
||||||
|
h_stack, v_stack, Button, ButtonCommon, Clickable, HighlightedLabel, Label, LabelCommon,
|
||||||
|
LabelSize, ListItem, ListItemSpacing, Selectable,
|
||||||
|
};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
use workspace::{ModalView, Toast, Workspace};
|
use workspace::{ModalView, Toast, Workspace};
|
||||||
|
|
||||||
|
@ -288,88 +291,70 @@ impl PickerDelegate for BranchListDelegate {
|
||||||
.start_slot(HighlightedLabel::new(shortened_branch_name, highlights)),
|
.start_slot(HighlightedLabel::new(shortened_branch_name, highlights)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// fn render_header(
|
fn render_header(&self, _: &mut ViewContext<Picker<Self>>) -> Option<AnyElement> {
|
||||||
// &self,
|
let label = if self.last_query.is_empty() {
|
||||||
// cx: &mut ViewContext<Picker<Self>>,
|
h_stack()
|
||||||
// ) -> Option<AnyElement<Picker<Self>>> {
|
.ml_3()
|
||||||
// let theme = &theme::current(cx);
|
.child(Label::new("Recent branches").size(LabelSize::Small))
|
||||||
// let style = theme.picker.header.clone();
|
} else {
|
||||||
// let label = if self.last_query.is_empty() {
|
let match_label = self.matches.is_empty().not().then(|| {
|
||||||
// Flex::row()
|
let suffix = if self.matches.len() == 1 { "" } else { "es" };
|
||||||
// .with_child(Label::new("Recent branches", style.label.clone()))
|
Label::new(format!("{} match{}", self.matches.len(), suffix)).size(LabelSize::Small)
|
||||||
// .contained()
|
});
|
||||||
// .with_style(style.container)
|
h_stack()
|
||||||
// } else {
|
.px_3()
|
||||||
// Flex::row()
|
.h_full()
|
||||||
// .with_child(Label::new("Branches", style.label.clone()))
|
.justify_between()
|
||||||
// .with_children(self.matches.is_empty().not().then(|| {
|
.child(Label::new("Branches").size(LabelSize::Small))
|
||||||
// let suffix = if self.matches.len() == 1 { "" } else { "es" };
|
.children(match_label)
|
||||||
// Label::new(
|
};
|
||||||
// format!("{} match{}", self.matches.len(), suffix),
|
Some(label.into_any())
|
||||||
// style.label,
|
}
|
||||||
// )
|
fn render_footer(&self, cx: &mut ViewContext<Picker<Self>>) -> Option<AnyElement> {
|
||||||
// .flex_float()
|
if self.last_query.is_empty() {
|
||||||
// }))
|
return None;
|
||||||
// .contained()
|
}
|
||||||
// .with_style(style.container)
|
|
||||||
// };
|
Some(
|
||||||
// Some(label.into_any())
|
h_stack().mr_3().pb_2().child(h_stack().w_full()).child(
|
||||||
// }
|
Button::new("branch-picker-create-branch-button", "Create branch").on_click(
|
||||||
// fn render_footer(
|
cx.listener(|_, _, cx| {
|
||||||
// &self,
|
cx.spawn(|picker, mut cx| async move {
|
||||||
// cx: &mut ViewContext<Picker<Self>>,
|
picker.update(&mut cx, |this, cx| {
|
||||||
// ) -> Option<AnyElement<Picker<Self>>> {
|
let project = this.delegate.workspace.read(cx).project().read(cx);
|
||||||
// if !self.last_query.is_empty() {
|
let current_pick = &this.delegate.last_query;
|
||||||
// let theme = &theme::current(cx);
|
let mut cwd = project
|
||||||
// let style = theme.picker.footer.clone();
|
.visible_worktrees(cx)
|
||||||
// enum BranchCreateButton {}
|
.next()
|
||||||
// Some(
|
.ok_or_else(|| anyhow!("There are no visisible worktrees."))?
|
||||||
// Flex::row().with_child(MouseEventHandler::new::<BranchCreateButton, _>(0, cx, |state, _| {
|
.read(cx)
|
||||||
// let style = style.style_for(state);
|
.abs_path()
|
||||||
// Label::new("Create branch", style.label.clone())
|
.to_path_buf();
|
||||||
// .contained()
|
cwd.push(".git");
|
||||||
// .with_style(style.container)
|
let repo = project
|
||||||
// })
|
.fs()
|
||||||
// .with_cursor_style(CursorStyle::PointingHand)
|
.open_repo(&cwd)
|
||||||
// .on_down(MouseButton::Left, |_, _, cx| {
|
.ok_or_else(|| anyhow!("Could not open repository at path `{}`", cwd.as_os_str().to_string_lossy()))?;
|
||||||
// cx.spawn(|picker, mut cx| async move {
|
let repo = repo
|
||||||
// picker.update(&mut cx, |this, cx| {
|
.lock();
|
||||||
// let project = this.delegate().workspace.read(cx).project().read(cx);
|
let status = repo
|
||||||
// let current_pick = &this.delegate().last_query;
|
.create_branch(¤t_pick);
|
||||||
// let mut cwd = project
|
if status.is_err() {
|
||||||
// .visible_worktrees(cx)
|
this.delegate.display_error_toast(format!("Failed to create branch '{current_pick}', check for conflicts or unstashed files"), cx);
|
||||||
// .next()
|
status?;
|
||||||
// .ok_or_else(|| anyhow!("There are no visisible worktrees."))?
|
}
|
||||||
// .read(cx)
|
let status = repo.change_branch(¤t_pick);
|
||||||
// .abs_path()
|
if status.is_err() {
|
||||||
// .to_path_buf();
|
this.delegate.display_error_toast(format!("Failed to chec branch '{current_pick}', check for conflicts or unstashed files"), cx);
|
||||||
// cwd.push(".git");
|
status?;
|
||||||
// let repo = project
|
}
|
||||||
// .fs()
|
this.cancel(&Default::default(), cx);
|
||||||
// .open_repo(&cwd)
|
Ok::<(), anyhow::Error>(())
|
||||||
// .ok_or_else(|| anyhow!("Could not open repository at path `{}`", cwd.as_os_str().to_string_lossy()))?;
|
})
|
||||||
// let repo = repo
|
|
||||||
// .lock();
|
}).detach_and_log_err(cx);
|
||||||
// let status = repo
|
}),
|
||||||
// .create_branch(¤t_pick);
|
).style(ui::ButtonStyle::Filled)).into_any_element(),
|
||||||
// if status.is_err() {
|
)
|
||||||
// this.delegate().display_error_toast(format!("Failed to create branch '{current_pick}', check for conflicts or unstashed files"), cx);
|
}
|
||||||
// status?;
|
|
||||||
// }
|
|
||||||
// let status = repo.change_branch(¤t_pick);
|
|
||||||
// if status.is_err() {
|
|
||||||
// this.delegate().display_error_toast(format!("Failed to chec branch '{current_pick}', check for conflicts or unstashed files"), cx);
|
|
||||||
// status?;
|
|
||||||
// }
|
|
||||||
// cx.emit(PickerEvent::Dismiss);
|
|
||||||
// Ok::<(), anyhow::Error>(())
|
|
||||||
// })
|
|
||||||
// }).detach();
|
|
||||||
// })).aligned().right()
|
|
||||||
// .into_any(),
|
|
||||||
// )
|
|
||||||
// } else {
|
|
||||||
// None
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue