Skip to content

Commit 2b85b81

Browse files
author
Stephan Dilly
authored
drop multiple stashes (#855)
1 parent 5c694bd commit 2b85b81

File tree

11 files changed

+137
-49
lines changed

11 files changed

+137
-49
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10+
**drop multiple stashes**
11+
12+
![drop-multiple-stashes](assets/drop-multiple-stashes.gif)
1013

1114
**branch name validation**
1215

1316
![name-validation](assets/branch-validation.gif)
1417

1518
## Added
19+
- mark and drop multiple stashes ([#854](https://github.com/extrawurst/gitui/issues/854))
1620
- check branch name validity while typing ([#559](https://github.com/extrawurst/gitui/issues/559))
1721
- support deleting remote branch [[@zcorniere](https://github.com/zcorniere)] ([#622](https://github.com/extrawurst/gitui/issues/622))
1822

assets/drop-multiple-stashes.gif

121 KB
Loading

src/app.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ use crate::{
44
components::{
55
event_pump, BlameFileComponent, BranchListComponent,
66
CommandBlocking, CommandInfo, CommitComponent, Component,
7-
CreateBranchComponent, DrawableComponent,
7+
ConfirmComponent, CreateBranchComponent, DrawableComponent,
88
ExternalEditorComponent, HelpComponent,
99
InspectCommitComponent, MsgComponent, PullComponent,
1010
PushComponent, PushTagsComponent, RenameBranchComponent,
11-
ResetComponent, RevisionFilesPopup, StashMsgComponent,
12-
TagCommitComponent, TagListComponent,
11+
RevisionFilesPopup, StashMsgComponent, TagCommitComponent,
12+
TagListComponent,
1313
},
1414
input::{Input, InputEvent, InputState},
1515
keys::{KeyConfig, SharedKeyConfig},
@@ -42,7 +42,7 @@ pub struct App {
4242
do_quit: bool,
4343
help: HelpComponent,
4444
msg: MsgComponent,
45-
reset: ResetComponent,
45+
reset: ConfirmComponent,
4646
commit: CommitComponent,
4747
blame_file_popup: BlameFileComponent,
4848
stashmsg_popup: StashMsgComponent,
@@ -91,7 +91,7 @@ impl App {
9191

9292
Self {
9393
input,
94-
reset: ResetComponent::new(
94+
reset: ConfirmComponent::new(
9595
queue.clone(),
9696
theme.clone(),
9797
key_config.clone(),
@@ -682,9 +682,13 @@ impl App {
682682
}
683683
}
684684
Action::StashDrop(_) | Action::StashPop(_) => {
685-
if self.stashlist_tab.action_confirmed(&action) {
686-
flags.insert(NeedsUpdate::ALL);
685+
if let Err(e) = StashList::action_confirmed(&action) {
686+
self.queue.push(InternalEvent::ShowErrorMsg(
687+
e.to_string(),
688+
));
687689
}
690+
691+
flags.insert(NeedsUpdate::ALL);
688692
}
689693
Action::ResetHunk(path, hash) => {
690694
sync::reset_hunk(CWD, &path, hash)?;

src/components/commitlist.rs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::{
55
Component, DrawableComponent, EventState, ScrollType,
66
},
77
keys::SharedKeyConfig,
8-
strings,
8+
strings::{self, symbol},
99
ui::calc_scroll_top,
1010
ui::style::{SharedTheme, Theme},
1111
};
@@ -120,6 +120,23 @@ impl CommitList {
120120
)
121121
}
122122

123+
///
124+
pub fn selected_entry_marked(&self) -> bool {
125+
self.selected_entry()
126+
.and_then(|e| self.is_marked(&e.id))
127+
.unwrap_or_default()
128+
}
129+
130+
///
131+
pub fn marked_count(&self) -> usize {
132+
self.marked.len()
133+
}
134+
135+
///
136+
pub fn marked(&self) -> &[CommitId] {
137+
&self.marked
138+
}
139+
123140
pub fn copy_entry_hash(&self) -> Result<()> {
124141
if let Some(e) = self.items.iter().nth(
125142
self.selection.saturating_sub(self.items.index_offset()),
@@ -223,14 +240,18 @@ impl CommitList {
223240
ELEMENTS_PER_LINE + if marked.is_some() { 2 } else { 0 },
224241
);
225242

226-
let splitter_txt = Cow::from(" ");
243+
let splitter_txt = Cow::from(symbol::EMPTY_SPACE);
227244
let splitter =
228245
Span::styled(splitter_txt, theme.text(true, selected));
229246

230247
// marker
231248
if let Some(marked) = marked {
232249
txt.push(Span::styled(
233-
Cow::from(if marked { "\u{2713}" } else { " " }),
250+
Cow::from(if marked {
251+
symbol::CHECKMARK
252+
} else {
253+
symbol::EMPTY_SPACE
254+
}),
234255
theme.log_marker(selected),
235256
));
236257
txt.push(splitter.clone());
@@ -433,6 +454,14 @@ impl Component for CommitList {
433454
self.selected_entry().is_some(),
434455
true,
435456
));
457+
out.push(CommandInfo::new(
458+
strings::commands::commit_list_mark(
459+
&self.key_config,
460+
self.selected_entry_marked(),
461+
),
462+
true,
463+
true,
464+
));
436465
CommandBlocking::PassingOn
437466
}
438467
}

src/components/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub use pull::PullComponent;
4545
pub use push::PushComponent;
4646
pub use push_tags::PushTagsComponent;
4747
pub use rename_branch::RenameBranchComponent;
48-
pub use reset::ResetComponent;
48+
pub use reset::ConfirmComponent;
4949
pub use revision_files::RevisionFilesComponent;
5050
pub use revision_files_popup::RevisionFilesPopup;
5151
pub use stashmsg::StashMsgComponent;

src/components/reset.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ use tui::{
1616
use ui::style::SharedTheme;
1717

1818
///
19-
pub struct ResetComponent {
19+
pub struct ConfirmComponent {
2020
target: Option<Action>,
2121
visible: bool,
2222
queue: Queue,
2323
theme: SharedTheme,
2424
key_config: SharedKeyConfig,
2525
}
2626

27-
impl DrawableComponent for ResetComponent {
27+
impl DrawableComponent for ConfirmComponent {
2828
fn draw<B: Backend>(
2929
&self,
3030
f: &mut Frame<B>,
@@ -50,7 +50,7 @@ impl DrawableComponent for ResetComponent {
5050
}
5151
}
5252

53-
impl Component for ResetComponent {
53+
impl Component for ConfirmComponent {
5454
fn commands(
5555
&self,
5656
out: &mut Vec<CommandInfo>,
@@ -101,7 +101,7 @@ impl Component for ResetComponent {
101101
}
102102
}
103103

104-
impl ResetComponent {
104+
impl ConfirmComponent {
105105
///
106106
pub fn new(
107107
queue: Queue,
@@ -139,11 +139,11 @@ impl ResetComponent {
139139
strings::confirm_title_reset(),
140140
strings::confirm_msg_reset(),
141141
),
142-
Action::StashDrop(_) => (
142+
Action::StashDrop(ids) => (
143143
strings::confirm_title_stashdrop(
144-
&self.key_config,
144+
&self.key_config,ids.len()>1
145145
),
146-
strings::confirm_msg_stashdrop(&self.key_config),
146+
strings::confirm_msg_stashdrop(&self.key_config,ids),
147147
),
148148
Action::StashPop(_) => (
149149
strings::confirm_title_stashpop(&self.key_config),

src/components/textinput.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::strings::symbol;
12
use crate::ui::Size;
23
use crate::{
34
components::{
@@ -169,7 +170,7 @@ impl TextInputComponent {
169170
let cursor_highlighting = {
170171
let mut h = HashMap::with_capacity(2);
171172
h.insert("\n", "\u{21b5}\n\r");
172-
h.insert(" ", "\u{00B7}");
173+
h.insert(" ", symbol::WHITESPACE);
173174
h
174175
};
175176

@@ -470,7 +471,10 @@ mod tests {
470471
get_style(&txt.lines[0].0[0]),
471472
Some(&not_underlined)
472473
);
473-
assert_eq!(get_text(&txt.lines[0].0[1]), Some("\u{00B7}"));
474+
assert_eq!(
475+
get_text(&txt.lines[0].0[1]),
476+
Some(symbol::WHITESPACE)
477+
);
474478
assert_eq!(
475479
get_style(&txt.lines[0].0[1]),
476480
Some(&underlined_whitespace)

src/keys.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use std::{
1515
rc::Rc,
1616
};
1717

18-
use crate::args::get_app_config_path;
18+
use crate::{args::get_app_config_path, strings::symbol};
1919

2020
pub type SharedKeyConfig = Rc<KeyConfig>;
2121

@@ -248,6 +248,7 @@ impl KeyConfig {
248248
self.get_key_symbol(ev.code)
249249
)
250250
}
251+
KeyCode::Char(' ') => String::from(symbol::SPACE),
251252
KeyCode::Char(c) => {
252253
format!(
253254
"{}{}",

src/queue.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub enum Action {
3030
Reset(ResetItem),
3131
ResetHunk(String, u64),
3232
ResetLines(String, Vec<DiffLinePosition>),
33-
StashDrop(CommitId),
33+
StashDrop(Vec<CommitId>),
3434
StashPop(CommitId),
3535
DeleteBranch(String, bool),
3636
DeleteTag(String),

src/strings.rs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use asyncgit::sync::CommitId;
2+
13
use crate::keys::SharedKeyConfig;
24

35
pub mod order {
@@ -20,6 +22,13 @@ pub static PUSH_TAGS_STATES_FETCHING: &str = "fetching";
2022
pub static PUSH_TAGS_STATES_PUSHING: &str = "pushing";
2123
pub static PUSH_TAGS_STATES_DONE: &str = "done";
2224

25+
pub mod symbol {
26+
pub const WHITESPACE: &str = "\u{00B7}"; //·
27+
pub const CHECKMARK: &str = "\u{2713}"; //✓
28+
pub const SPACE: &str = "\u{02FD}"; //˽
29+
pub const EMPTY_SPACE: &str = " ";
30+
}
31+
2332
pub fn title_branches() -> String {
2433
"Branches".to_string()
2534
}
@@ -103,8 +112,9 @@ pub fn confirm_title_reset() -> String {
103112
}
104113
pub fn confirm_title_stashdrop(
105114
_key_config: &SharedKeyConfig,
115+
multiple: bool,
106116
) -> String {
107-
"Drop".to_string()
117+
format!("Drop Stash{}", if multiple { "es" } else { "" })
108118
}
109119
pub fn confirm_title_stashpop(
110120
_key_config: &SharedKeyConfig,
@@ -151,8 +161,21 @@ pub fn confirm_msg_reset_lines(lines: usize) -> String {
151161
}
152162
pub fn confirm_msg_stashdrop(
153163
_key_config: &SharedKeyConfig,
164+
ids: &[CommitId],
154165
) -> String {
155-
"confirm stash drop?".to_string()
166+
format!(
167+
"Sure you want to drop following {}stash{}?\n\n{}",
168+
if ids.len() > 1 {
169+
format!("{} ", ids.len())
170+
} else {
171+
String::default()
172+
},
173+
if ids.len() > 1 { "es" } else { "" },
174+
ids.iter()
175+
.map(CommitId::get_short_string)
176+
.collect::<Vec<_>>()
177+
.join(", ")
178+
)
156179
}
157180
pub fn confirm_msg_stashpop(_key_config: &SharedKeyConfig) -> String {
158181
"The stash will be applied and removed from the stash list. Confirm stash pop?"
@@ -399,6 +422,20 @@ pub mod commands {
399422
CMD_GROUP_GENERAL,
400423
)
401424
}
425+
pub fn commit_list_mark(
426+
key_config: &SharedKeyConfig,
427+
marked: bool,
428+
) -> CommandText {
429+
CommandText::new(
430+
format!(
431+
"{} [{}]",
432+
if marked { "Unmark" } else { "Mark" },
433+
key_config.get_hint(key_config.log_mark_commit),
434+
),
435+
"mark multiple commits",
436+
CMD_GROUP_GENERAL,
437+
)
438+
}
402439
pub fn copy(key_config: &SharedKeyConfig) -> CommandText {
403440
CommandText::new(
404441
format!(
@@ -828,10 +865,16 @@ pub mod commands {
828865
}
829866
pub fn stashlist_drop(
830867
key_config: &SharedKeyConfig,
868+
marked: usize,
831869
) -> CommandText {
832870
CommandText::new(
833871
format!(
834-
"Drop [{}]",
872+
"Drop{} [{}]",
873+
if marked == 0 {
874+
String::default()
875+
} else {
876+
format!(" {}", marked)
877+
},
835878
key_config.get_hint(key_config.stash_drop),
836879
),
837880
"drop selected stash",

0 commit comments

Comments
 (0)