on master help sign in
Close some popups automatically (#1285)

* Add Event::Used to use event callback without consuming * Close popup if contents ignored event * collect event results before executing callbacks * don't add new result variant, use Ignored(..) instead * break in match cases * Make auto_close configurable * fix merge * auto close hover popups * fix formatting

commit40eb1268c72b60f1249389c58892e7c45d268cff authorBram <bram.hoendervangers@gmail.com> dateWed 23 Feb 2022, 04:46 (5 years ago) parente1a92fd
9 files changed+64−34
helix-term/src/commands.rs+1−1 helix-term/src/commands/lsp.rs+1−1 helix-term/src/compositor.rs+22−7 helix-term/src/ui/completion.rs+1−1 helix-term/src/ui/editor.rs+11−13 helix-term/src/ui/menu.rs+2−2 helix-term/src/ui/picker.rs+1−1 helix-term/src/ui/popup.rs+24−7 helix-term/src/ui/prompt.rs+1−1
helix-term/src/commands.rs+1−1
@@ -2921,7 +2921,7 @@ pub mod cmd {
29212921 let call: job::Callback =
29222922 Box::new(move |editor: &mut Editor, compositor: &mut Compositor| {
29232923 let contents = ui::Markdown::new(contents, editor.syn_loader.clone());
2924− let popup = Popup::new("hover", contents);
2924+ let popup = Popup::new("hover", contents).auto_close(true);
29252925 compositor.replace_or_push("hover", Box::new(popup));
29262926 });
29272927 Ok(call)
helix-term/src/commands/lsp.rs+1−1
@@ -633,7 +633,7 @@ pub fn hover(cx: &mut Context) {
633633 // skip if contents empty
634634
635635 let contents = ui::Markdown::new(contents, editor.syn_loader.clone());
636− let popup = Popup::new("hover", contents);
636+ let popup = Popup::new("hover", contents).auto_close(true);
637637 compositor.replace_or_push("hover", Box::new(popup));
638638 }
639639 },
helix-term/src/compositor.rs+22−7
@@ -19,7 +19,7 @@ pub type Callback = Box<dyn FnOnce(&mut Compositor, &mut Context)>;
1919
2020// Cursive-inspired
2121pub enum EventResult {
22− Ignored,
22+ Ignored(Option<Callback>),
2323 Consumed(Option<Callback>),
2424}
2525
@@ -36,7 +36,7 @@ pub struct Context<'a> {
3636pub trait Component: Any + AnyComponent {
3737 /// Process input events, return true if handled.
3838 fn handle_event(&mut self, _event: Event, _ctx: &mut Context) -> EventResult {
39− EventResult::Ignored
39+ EventResult::Ignored(None)
4040 }
4141 // , args: ()
4242
@@ -146,19 +146,34 @@ impl Compositor {
146146 keys.push(key.into());
147147 }
148148
149+ let mut callbacks = Vec::new();
150+ let mut consumed = false;
151+
149152 // propagate events through the layers until we either find a layer that consumes it or we
150153 // run out of layers (event bubbling)
151154 for layer in self.layers.iter_mut().rev() {
152155 match layer.handle_event(event, cx) {
153156 EventResult::Consumed(Some(callback)) => {
154− callback(self, cx);
155− return true;
157+ callbacks.push(callback);
158+ consumed = true;
159+ break;
160+ }
161+ EventResult::Consumed(None) => {
162+ consumed = true;
163+ break;
164+ }
165+ EventResult::Ignored(Some(callback)) => {
166+ callbacks.push(callback);
156167 }
157− EventResult::Consumed(None) => return true,
158− EventResult::Ignored => false,
168+ EventResult::Ignored(None) => {}
159169 };
160170 }
161− false
171+
172+ for callback in callbacks {
173+ callback(self, cx)
174+ }
175+
176+ consumed
162177 }
163178
164179 pub fn render(&mut self, cx: &mut Context) {
helix-term/src/ui/completion.rs+1−1
@@ -276,7 +276,7 @@ impl Component for Completion {
276276 code: KeyCode::Esc, ..
277277 }) = event
278278 {
279− return EventResult::Ignored;
279+ return EventResult::Ignored(None);
280280 }
281281 self.popup.handle_event(event, cx)
282282 }
helix-term/src/ui/editor.rs+11−13
@@ -872,9 +872,7 @@ impl EditorView {
872872
873873 let path = match doc.path() {
874874 Some(path) => path.clone(),
875− None => {
876− return EventResult::Ignored;
877− }
875+ None => return EventResult::Ignored(None),
878876 };
879877
880878 let line = coords.row + view.offset.row;
@@ -884,7 +882,7 @@ impl EditorView {
884882 }
885883 }
886884
887− EventResult::Ignored
885+ EventResult::Ignored(None)
888886 }
889887
890888 MouseEvent {
@@ -897,7 +895,7 @@ impl EditorView {
897895
898896 let pos = match view.pos_at_screen_coords(doc, row, column) {
899897 Some(pos) => pos,
900− None => return EventResult::Ignored,
898+ None => return EventResult::Ignored(None),
901899 };
902900
903901 let mut selection = doc.selection(view.id).clone();
@@ -928,7 +926,7 @@ impl EditorView {
928926
929927 match result {
930928 Some(view_id) => cxt.editor.tree.focus = view_id,
931− None => return EventResult::Ignored,
929+ None => return EventResult::Ignored(None),
932930 }
933931
934932 let offset = cxt.editor.config.scroll_lines.abs() as usize;
@@ -944,14 +942,14 @@ impl EditorView {
944942 ..
945943 } => {
946944 if !cxt.editor.config.middle_click_paste {
947− return EventResult::Ignored;
945+ return EventResult::Ignored(None);
948946 }
949947
950948 let (view, doc) = current!(cxt.editor);
951949 let range = doc.selection(view.id).primary();
952950
953951 if range.to() - range.from() <= 1 {
954− return EventResult::Ignored;
952+ return EventResult::Ignored(None);
955953 }
956954
957955 commands::MappableCommand::yank_main_selection_to_primary_clipboard.execute(cxt);
@@ -988,7 +986,7 @@ impl EditorView {
988986 return EventResult::Consumed(None);
989987 }
990988 }
991− EventResult::Ignored
989+ EventResult::Ignored(None)
992990 }
993991
994992 MouseEvent {
@@ -1000,7 +998,7 @@ impl EditorView {
1000998 } => {
1001999 let editor = &mut cxt.editor;
10021000 if !editor.config.middle_click_paste {
1003− return EventResult::Ignored;
1001+ return EventResult::Ignored(None);
10041002 }
10051003
10061004 if modifiers == crossterm::event::KeyModifiers::ALT {
@@ -1023,10 +1021,10 @@ impl EditorView {
10231021 return EventResult::Consumed(None);
10241022 }
10251023
1026− EventResult::Ignored
1024+ EventResult::Ignored(None)
10271025 }
10281026
1029− _ => EventResult::Ignored,
1027+ _ => EventResult::Ignored(None),
10301028 }
10311029 }
10321030}
@@ -1117,7 +1115,7 @@ impl Component for EditorView {
11171115 // if the command consumed the last view, skip the render.
11181116 // on the next loop cycle the Application will then terminate.
11191117 if cx.editor.should_close() {
1120− return EventResult::Ignored;
1118+ return EventResult::Ignored(None);
11211119 }
11221120
11231121 let (view, doc) = current!(cx.editor);
helix-term/src/ui/menu.rs+2−2
@@ -202,7 +202,7 @@ impl<T: Item + 'static> Component for Menu<T> {
202202 fn handle_event(&mut self, event: Event, cx: &mut Context) -> EventResult {
203203 let event = match event {
204204 Event::Key(event) => event,
205− _ => return EventResult::Ignored,
205+ _ => return EventResult::Ignored(None),
206206 };
207207
208208 let close_fn = EventResult::Consumed(Some(Box::new(|compositor: &mut Compositor, _| {
@@ -252,7 +252,7 @@ impl<T: Item + 'static> Component for Menu<T> {
252252 // for some events, we want to process them but send ignore, specifically all input except
253253 // tab/enter/ctrl-k or whatever will confirm the selection/ ctrl-n/ctrl-p for scroll.
254254 // EventResult::Consumed(None)
255− EventResult::Ignored
255+ EventResult::Ignored(None)
256256 }
257257
258258 fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> {
helix-term/src/ui/picker.rs+1−1
@@ -419,7 +419,7 @@ impl<T: 'static> Component for Picker<T> {
419419 let key_event = match event {
420420 Event::Key(event) => event,
421421 Event::Resize(..) => return EventResult::Consumed(None),
422− _ => return EventResult::Ignored,
422+ _ => return EventResult::Ignored(None),
423423 };
424424
425425 let close_fn = EventResult::Consumed(Some(Box::new(|compositor: &mut Compositor, _| {
helix-term/src/ui/popup.rs+24−7
@@ -1,5 +1,5 @@
11use crate::{
2− compositor::{Component, Compositor, Context, EventResult},
2+ compositor::{Callback, Component, Context, EventResult},
33 ctrl, key,
44};
55use crossterm::event::Event;
@@ -18,6 +18,7 @@ pub struct Popup<T: Component> {
1818 size: (u16, u16),
1919 child_size: (u16, u16),
2020 scroll: usize,
21+ auto_close: bool,
2122 id: &'static str,
2223}
2324
@@ -33,6 +34,7 @@ impl<T: Component> Popup<T> {
3334 size: (0, 0),
3435 child_size: (0, 0),
3536 scroll: 0,
37+ auto_close: false,
3638 id,
3739 }
3840 }
@@ -46,6 +48,11 @@ impl<T: Component> Popup<T> {
4648 self
4749 }
4850
51+ pub fn auto_close(mut self, auto_close: bool) -> Self {
52+ self.auto_close = auto_close;
53+ self
54+ }
55+
4956 pub fn get_rel_position(&mut self, viewport: Rect, cx: &Context) -> (u16, u16) {
5057 let position = self
5158 .position
@@ -105,19 +112,19 @@ impl<T: Component> Component for Popup<T> {
105112 Event::Key(event) => event,
106113 Event::Resize(_, _) => {
107114 // TODO: calculate inner area, call component's handle_event with that area
108− return EventResult::Ignored;
115+ return EventResult::Ignored(None);
109116 }
110− _ => return EventResult::Ignored,
117+ _ => return EventResult::Ignored(None),
111118 };
112119
113− let close_fn = EventResult::Consumed(Some(Box::new(|compositor: &mut Compositor, _| {
120+ let close_fn: Callback = Box::new(|compositor, _| {
114121 // remove the layer
115122 compositor.pop();
116− })));
123+ });
117124
118125 match key.into() {
119126 // esc or ctrl-c aborts the completion and closes the menu
120− key!(Esc) | ctrl!('c') => close_fn,
127+ key!(Esc) | ctrl!('c') => EventResult::Consumed(Some(close_fn)),
121128 ctrl!('d') => {
122129 self.scroll(self.size.1 as usize / 2, true);
123130 EventResult::Consumed(None)
@@ -126,7 +133,17 @@ impl<T: Component> Component for Popup<T> {
126133 self.scroll(self.size.1 as usize / 2, false);
127134 EventResult::Consumed(None)
128135 }
129− _ => self.contents.handle_event(event, cx),
136+ _ => {
137+ let contents_event_result = self.contents.handle_event(event, cx);
138+
139+ if self.auto_close {
140+ if let EventResult::Ignored(None) = contents_event_result {
141+ return EventResult::Ignored(Some(close_fn));
142+ }
143+ }
144+
145+ contents_event_result
146+ }
130147 }
131148 // for some events, we want to process them but send ignore, specifically all input except
132149 // tab/enter/ctrl-k or whatever will confirm the selection/ ctrl-n/ctrl-p for scroll.
helix-term/src/ui/prompt.rs+1−1
@@ -438,7 +438,7 @@ impl Component for Prompt {
438438 let event = match event {
439439 Event::Key(event) => event,
440440 Event::Resize(..) => return EventResult::Consumed(None),
441− _ => return EventResult::Ignored,
441+ _ => return EventResult::Ignored(None),
442442 };
443443
444444 let close_fn = EventResult::Consumed(Some(Box::new(|compositor: &mut Compositor, _| {