Git · StashList: words in i18n, rows pick, only handled actions drawn
This commit is contained in:
3 files changed
+91
-22
No files matched your search
+33
-1
@@ -8,7 +8,8 @@ use gpui::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
Blame, BlameView, Branch, BranchList, Commit, CommitList, FileHistory, GitTag, TagList,
|
||||
Blame, BlameView, Branch, BranchList, Commit, CommitList, FileHistory, GitTag, Stash,
|
||||
StashList, TagList,
|
||||
};
|
||||
use crate::{forms, primitives::FocusNext, theme::Theme};
|
||||
|
||||
@@ -89,6 +90,24 @@ impl Render for Lists {
|
||||
tagged.borrow_mut().picked.push(name.to_string())
|
||||
}))
|
||||
}
|
||||
"stashes" => {
|
||||
let stash = |message: &str| Stash {
|
||||
message: message.to_string().into(),
|
||||
branch: "main".into(),
|
||||
when: "today".into(),
|
||||
};
|
||||
let acted = self.heard.clone();
|
||||
frame
|
||||
.child(StashList::new("bare", [stash("unhandled")]))
|
||||
.child(
|
||||
StashList::new("stashes", [stash("one"), stash("two")])
|
||||
.selected(1)
|
||||
.on_pick(move |ix, _, _| pick.borrow_mut().picked.push(format!("{ix}")))
|
||||
.on_action(move |ix, what, _, _| {
|
||||
acted.borrow_mut().picked.push(format!("{what:?} {ix}"))
|
||||
}),
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
let blame = |commit: &str| Blame {
|
||||
commit: commit.into(),
|
||||
@@ -219,3 +238,16 @@ fn branches_and_tags_pick_from_the_keyboard(cx: &mut TestAppContext) {
|
||||
"row actions answer: {picked:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn stashes_pick_and_act_from_the_keyboard(cx: &mut TestAppContext) {
|
||||
let (heard, cx) = shown(cx, 0, "stashes");
|
||||
for _ in 0..4 {
|
||||
press_first(cx);
|
||||
}
|
||||
assert_eq!(
|
||||
heard.borrow().picked,
|
||||
["0", "Apply 0", "Pop 0", "Drop 0"],
|
||||
"a list with no owner draws no stops"
|
||||
);
|
||||
}
|
||||
+50
-21
@@ -7,11 +7,13 @@ use gpui::{
|
||||
|
||||
use super::refs::{OnName, Pick, Run, action, listed};
|
||||
use crate::{
|
||||
i18n,
|
||||
primitives::IconName,
|
||||
theme::{ActiveTheme, TextSize},
|
||||
};
|
||||
|
||||
type OnStash = Rc<dyn Fn(usize, StashAction, &mut Window, &mut App)>;
|
||||
type OnAt = Rc<dyn Fn(usize, &mut Window, &mut App)>;
|
||||
|
||||
/// A tag, its message if annotated, its commit, when.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
@@ -120,6 +122,8 @@ pub struct StashList {
|
||||
id: ElementId,
|
||||
stashes: Vec<Stash>,
|
||||
on_action: Option<OnStash>,
|
||||
selected: Option<usize>,
|
||||
on_pick: Option<OnAt>,
|
||||
}
|
||||
|
||||
impl StashList {
|
||||
@@ -128,9 +132,23 @@ impl StashList {
|
||||
id: id.into(),
|
||||
stashes: stashes.into_iter().collect(),
|
||||
on_action: None,
|
||||
selected: None,
|
||||
on_pick: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// The stash shown as picked.
|
||||
pub fn selected(mut self, ix: usize) -> Self {
|
||||
self.selected = Some(ix);
|
||||
self
|
||||
}
|
||||
|
||||
/// A press on a row picks its stash.
|
||||
pub fn on_pick(mut self, handler: impl Fn(usize, &mut Window, &mut App) + 'static) -> Self {
|
||||
self.on_pick = Some(Rc::new(handler));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_action(
|
||||
mut self,
|
||||
handler: impl Fn(usize, StashAction, &mut Window, &mut App) + 'static,
|
||||
@@ -149,35 +167,46 @@ impl RenderOnce for StashList {
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(ix, stash)| {
|
||||
let act = |key: &str, icon, words: &'static str, what: StashAction| {
|
||||
let run = self.on_action.clone().map(|on_action| {
|
||||
Rc::new(move |window: &mut Window, cx: &mut App| {
|
||||
on_action(ix, what, window, cx)
|
||||
}) as Run
|
||||
});
|
||||
action(
|
||||
(self.id.clone(), format!("{key}-{ix}")).into(),
|
||||
icon,
|
||||
words,
|
||||
run,
|
||||
)
|
||||
};
|
||||
let name = SharedString::from(format!("stash@{{{ix}}}"));
|
||||
// Only actions the owner handles are drawn.
|
||||
let actions: Vec<AnyElement> = [
|
||||
("apply", IconName::Download, StashAction::Apply),
|
||||
("pop", IconName::ArrowUp, StashAction::Pop),
|
||||
("drop", IconName::Trash2, StashAction::Drop),
|
||||
]
|
||||
.into_iter()
|
||||
.filter_map(|(key, icon, what)| {
|
||||
let on_action = self.on_action.clone()?;
|
||||
let run = Rc::new(move |window: &mut Window, cx: &mut App| {
|
||||
on_action(ix, what, window, cx)
|
||||
}) as Run;
|
||||
let words = i18n::text(cx, &format!("git.stash.{key}"), &[]);
|
||||
let id = (self.id.clone(), format!("{key}-{ix}")).into();
|
||||
Some(action(id, icon, words, Some(run)))
|
||||
})
|
||||
.collect();
|
||||
let detail = i18n::text(
|
||||
cx,
|
||||
"git.stash.on",
|
||||
&[("message", &stash.message), ("branch", &stash.branch)],
|
||||
);
|
||||
let pick = self.on_pick.clone().map(|pick| Pick {
|
||||
spoken: format!("{name} {detail}").into(),
|
||||
selected: self.selected == Some(ix),
|
||||
run: Rc::new(move |window: &mut Window, cx: &mut App| pick(ix, window, cx)),
|
||||
});
|
||||
listed(
|
||||
(self.id.clone(), format!("stash-{ix}")).into(),
|
||||
IconName::Archive,
|
||||
div()
|
||||
.font_family(theme.mono_family.clone())
|
||||
.text_color(colors.fg)
|
||||
.child(format!("stash@{{{ix}}}"))
|
||||
.child(name)
|
||||
.into_any_element(),
|
||||
format!("{} · on {}", stash.message, stash.branch).into(),
|
||||
detail,
|
||||
vec![stash.when.clone()],
|
||||
vec![
|
||||
act("apply", IconName::Download, "Apply", StashAction::Apply),
|
||||
act("pop", IconName::ArrowUp, "Pop", StashAction::Pop),
|
||||
act("drop", IconName::Trash2, "Drop", StashAction::Drop),
|
||||
],
|
||||
None,
|
||||
actions,
|
||||
pick,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -96,6 +96,10 @@ const EN: &[(&str, &str)] = &[
|
||||
("git.merge.accept_current", "Accept current"),
|
||||
("git.merge.accept_incoming", "Accept incoming"),
|
||||
("git.merge.accept_both", "Accept both"),
|
||||
("git.stash.apply", "Apply"),
|
||||
("git.stash.pop", "Pop"),
|
||||
("git.stash.drop", "Drop"),
|
||||
("git.stash.on", "{message} · on {branch}"),
|
||||
];
|
||||
|
||||
const ZH_CN: &[(&str, &str)] = &[
|
||||
@@ -190,6 +194,10 @@ const ZH_CN: &[(&str, &str)] = &[
|
||||
("git.merge.accept_current", "接受当前"),
|
||||
("git.merge.accept_incoming", "接受传入"),
|
||||
("git.merge.accept_both", "接受两者"),
|
||||
("git.stash.apply", "应用"),
|
||||
("git.stash.pop", "弹出"),
|
||||
("git.stash.drop", "删除"),
|
||||
("git.stash.on", "{message} · 在 {branch}"),
|
||||
];
|
||||
|
||||
/// Ely's message for `key`; English if unshipped, fails if unknown.
|
||||
|
||||
Reference in new issue
Block a user