1 use crate::{
2     components::{
3         visibility_blocking, CommandBlocking, CommandInfo,
4         CommitList, Component, DrawableComponent,
5     },
6     keys::SharedKeyConfig,
7     queue::{Action, InternalEvent, Queue},
8     strings,
9     ui::style::SharedTheme,
10 };
11 use anyhow::Result;
12 use asyncgit::{
13     sync::{self, CommitId},
14     CWD,
15 };
16 use crossterm::event::Event;
17 
18 pub struct StashList {
19     list: CommitList,
20     visible: bool,
21     queue: Queue,
22     key_config: SharedKeyConfig,
23 }
24 
25 impl StashList {
26     ///
new( queue: &Queue, theme: SharedTheme, key_config: SharedKeyConfig, ) -> Self27     pub fn new(
28         queue: &Queue,
29         theme: SharedTheme,
30         key_config: SharedKeyConfig,
31     ) -> Self {
32         Self {
33             visible: false,
34             list: CommitList::new(
35                 &strings::stashlist_title(&key_config),
36                 theme,
37                 key_config.clone(),
38             ),
39             queue: queue.clone(),
40             key_config,
41         }
42     }
43 
44     ///
update(&mut self) -> Result<()>45     pub fn update(&mut self) -> Result<()> {
46         if self.visible {
47             let stashes = sync::get_stashes(CWD)?;
48             let commits =
49                 sync::get_commits_info(CWD, stashes.as_slice(), 100)?;
50 
51             self.list.set_count_total(commits.len());
52             self.list.items().set_items(0, commits);
53         }
54 
55         Ok(())
56     }
57 
apply_stash(&mut self)58     fn apply_stash(&mut self) {
59         if let Some(e) = self.list.selected_entry() {
60             match sync::stash_apply(CWD, e.id) {
61                 Ok(_) => {
62                     self.queue
63                         .borrow_mut()
64                         .push_back(InternalEvent::TabSwitch);
65                 }
66                 Err(e) => {
67                     self.queue.borrow_mut().push_back(
68                         InternalEvent::ShowErrorMsg(format!(
69                             "stash apply error:\n{}",
70                             e,
71                         )),
72                     );
73                 }
74             }
75         }
76     }
77 
drop_stash(&mut self)78     fn drop_stash(&mut self) {
79         if let Some(e) = self.list.selected_entry() {
80             self.queue.borrow_mut().push_back(
81                 InternalEvent::ConfirmAction(Action::StashDrop(e.id)),
82             );
83         }
84     }
85 
inspect(&mut self)86     fn inspect(&mut self) {
87         if let Some(e) = self.list.selected_entry() {
88             self.queue
89                 .borrow_mut()
90                 .push_back(InternalEvent::InspectCommit(e.id, None));
91         }
92     }
93 
94     ///
drop(id: CommitId) -> bool95     pub fn drop(id: CommitId) -> bool {
96         sync::stash_drop(CWD, id).is_ok()
97     }
98 }
99 
100 impl DrawableComponent for StashList {
draw<B: tui::backend::Backend>( &self, f: &mut tui::Frame<B>, rect: tui::layout::Rect, ) -> Result<()>101     fn draw<B: tui::backend::Backend>(
102         &self,
103         f: &mut tui::Frame<B>,
104         rect: tui::layout::Rect,
105     ) -> Result<()> {
106         self.list.draw(f, rect)?;
107 
108         Ok(())
109     }
110 }
111 
112 impl Component for StashList {
commands( &self, out: &mut Vec<CommandInfo>, force_all: bool, ) -> CommandBlocking113     fn commands(
114         &self,
115         out: &mut Vec<CommandInfo>,
116         force_all: bool,
117     ) -> CommandBlocking {
118         if self.visible || force_all {
119             self.list.commands(out, force_all);
120 
121             let selection_valid =
122                 self.list.selected_entry().is_some();
123             out.push(CommandInfo::new(
124                 strings::commands::stashlist_apply(&self.key_config),
125                 selection_valid,
126                 true,
127             ));
128             out.push(CommandInfo::new(
129                 strings::commands::stashlist_drop(&self.key_config),
130                 selection_valid,
131                 true,
132             ));
133             out.push(CommandInfo::new(
134                 strings::commands::stashlist_inspect(
135                     &self.key_config,
136                 ),
137                 selection_valid,
138                 true,
139             ));
140         }
141 
142         visibility_blocking(self)
143     }
144 
event(&mut self, ev: crossterm::event::Event) -> Result<bool>145     fn event(&mut self, ev: crossterm::event::Event) -> Result<bool> {
146         if self.visible {
147             if self.list.event(ev)? {
148                 return Ok(true);
149             }
150 
151             if let Event::Key(k) = ev {
152                 if k == self.key_config.enter {
153                     self.apply_stash()
154                 } else if k == self.key_config.stash_drop {
155                     self.drop_stash()
156                 } else if k == self.key_config.stash_open {
157                     self.inspect()
158                 } else {
159                 }
160             }
161         }
162 
163         Ok(false)
164     }
165 
is_visible(&self) -> bool166     fn is_visible(&self) -> bool {
167         self.visible
168     }
169 
hide(&mut self)170     fn hide(&mut self) {
171         self.visible = false;
172     }
173 
show(&mut self) -> Result<()>174     fn show(&mut self) -> Result<()> {
175         self.visible = true;
176         self.update()?;
177         Ok(())
178     }
179 }
180