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::{
|
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};
|
use crate::{forms, primitives::FocusNext, theme::Theme};
|
||||||
|
|
||||||
@@ -89,6 +90,24 @@ impl Render for Lists {
|
|||||||
tagged.borrow_mut().picked.push(name.to_string())
|
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 {
|
let blame = |commit: &str| Blame {
|
||||||
commit: commit.into(),
|
commit: commit.into(),
|
||||||
@@ -219,3 +238,16 @@ fn branches_and_tags_pick_from_the_keyboard(cx: &mut TestAppContext) {
|
|||||||
"row actions answer: {picked:?}"
|
"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 super::refs::{OnName, Pick, Run, action, listed};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
i18n,
|
||||||
primitives::IconName,
|
primitives::IconName,
|
||||||
theme::{ActiveTheme, TextSize},
|
theme::{ActiveTheme, TextSize},
|
||||||
};
|
};
|
||||||
|
|
||||||
type OnStash = Rc<dyn Fn(usize, StashAction, &mut Window, &mut App)>;
|
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.
|
/// A tag, its message if annotated, its commit, when.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
@@ -120,6 +122,8 @@ pub struct StashList {
|
|||||||
id: ElementId,
|
id: ElementId,
|
||||||
stashes: Vec<Stash>,
|
stashes: Vec<Stash>,
|
||||||
on_action: Option<OnStash>,
|
on_action: Option<OnStash>,
|
||||||
|
selected: Option<usize>,
|
||||||
|
on_pick: Option<OnAt>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StashList {
|
impl StashList {
|
||||||
@@ -128,9 +132,23 @@ impl StashList {
|
|||||||
id: id.into(),
|
id: id.into(),
|
||||||
stashes: stashes.into_iter().collect(),
|
stashes: stashes.into_iter().collect(),
|
||||||
on_action: None,
|
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(
|
pub fn on_action(
|
||||||
mut self,
|
mut self,
|
||||||
handler: impl Fn(usize, StashAction, &mut Window, &mut App) + 'static,
|
handler: impl Fn(usize, StashAction, &mut Window, &mut App) + 'static,
|
||||||
@@ -149,35 +167,46 @@ impl RenderOnce for StashList {
|
|||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(ix, stash)| {
|
.map(|(ix, stash)| {
|
||||||
let act = |key: &str, icon, words: &'static str, what: StashAction| {
|
let name = SharedString::from(format!("stash@{{{ix}}}"));
|
||||||
let run = self.on_action.clone().map(|on_action| {
|
// Only actions the owner handles are drawn.
|
||||||
Rc::new(move |window: &mut Window, cx: &mut App| {
|
let actions: Vec<AnyElement> = [
|
||||||
on_action(ix, what, window, cx)
|
("apply", IconName::Download, StashAction::Apply),
|
||||||
}) as Run
|
("pop", IconName::ArrowUp, StashAction::Pop),
|
||||||
});
|
("drop", IconName::Trash2, StashAction::Drop),
|
||||||
action(
|
]
|
||||||
(self.id.clone(), format!("{key}-{ix}")).into(),
|
.into_iter()
|
||||||
icon,
|
.filter_map(|(key, icon, what)| {
|
||||||
words,
|
let on_action = self.on_action.clone()?;
|
||||||
run,
|
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(
|
listed(
|
||||||
(self.id.clone(), format!("stash-{ix}")).into(),
|
(self.id.clone(), format!("stash-{ix}")).into(),
|
||||||
IconName::Archive,
|
IconName::Archive,
|
||||||
div()
|
div()
|
||||||
.font_family(theme.mono_family.clone())
|
.font_family(theme.mono_family.clone())
|
||||||
.text_color(colors.fg)
|
.text_color(colors.fg)
|
||||||
.child(format!("stash@{{{ix}}}"))
|
.child(name)
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
format!("{} · on {}", stash.message, stash.branch).into(),
|
detail,
|
||||||
vec![stash.when.clone()],
|
vec![stash.when.clone()],
|
||||||
vec![
|
actions,
|
||||||
act("apply", IconName::Download, "Apply", StashAction::Apply),
|
pick,
|
||||||
act("pop", IconName::ArrowUp, "Pop", StashAction::Pop),
|
|
||||||
act("drop", IconName::Trash2, "Drop", StashAction::Drop),
|
|
||||||
],
|
|
||||||
None,
|
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -96,6 +96,10 @@ const EN: &[(&str, &str)] = &[
|
|||||||
("git.merge.accept_current", "Accept current"),
|
("git.merge.accept_current", "Accept current"),
|
||||||
("git.merge.accept_incoming", "Accept incoming"),
|
("git.merge.accept_incoming", "Accept incoming"),
|
||||||
("git.merge.accept_both", "Accept both"),
|
("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)] = &[
|
const ZH_CN: &[(&str, &str)] = &[
|
||||||
@@ -190,6 +194,10 @@ const ZH_CN: &[(&str, &str)] = &[
|
|||||||
("git.merge.accept_current", "接受当前"),
|
("git.merge.accept_current", "接受当前"),
|
||||||
("git.merge.accept_incoming", "接受传入"),
|
("git.merge.accept_incoming", "接受传入"),
|
||||||
("git.merge.accept_both", "接受两者"),
|
("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.
|
/// Ely's message for `key`; English if unshipped, fails if unknown.
|
||||||
|
|||||||
Reference in new issue
Block a user