From 7c444439946a4617d080a87adbba528437c3b5c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= <blaz@mxxn.io>
Date: Tue, 6 Apr 2021 15:34:33 +0900
Subject: [PATCH] Handle c-n, c-p, etc. autocompletion events.

---
 helix-term/src/ui/completion.rs |  2 +-
 helix-term/src/ui/editor.rs     | 48 +++++++++++++++++++++++++--------
 2 files changed, 38 insertions(+), 12 deletions(-)

diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs
index 637fc5f4..a804b5f2 100644
--- a/helix-term/src/ui/completion.rs
+++ b/helix-term/src/ui/completion.rs
@@ -131,7 +131,7 @@ impl Completion {
 
         let cursor = doc.selection(view.id).cursor();
         if self.trigger_offset <= cursor {
-            let fragment = doc.text().slice(self.trigger_offset..=cursor);
+            let fragment = doc.text().slice(self.trigger_offset..cursor);
             let text = Cow::from(fragment);
             // TODO: logic is same as ui/picker
             menu.score(&text);
diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs
index 16a77b6c..1317a5e7 100644
--- a/helix-term/src/ui/editor.rs
+++ b/helix-term/src/ui/editor.rs
@@ -500,7 +500,7 @@ impl Component for EditorView {
                 cx.editor.resize(Rect::new(0, 0, width, height - 1));
                 EventResult::Consumed(None)
             }
-            Event::Key(event) => {
+            Event::Key(key) => {
                 let (view, doc) = cx.editor.current();
                 let mode = doc.mode();
 
@@ -519,24 +519,50 @@ impl Component for EditorView {
 
                 if let Some(on_next_key) = self.on_next_key.take() {
                     // if there's a command waiting input, do that first
-                    on_next_key(&mut cxt, event);
+                    on_next_key(&mut cxt, key);
                 } else {
                     match mode {
                         Mode::Insert => {
                             // record last_insert key
-                            self.last_insert.1.push(event);
-
-                            self.insert_mode(&mut cxt, event);
+                            self.last_insert.1.push(key);
 
+                            // let completion swallow the event if necessary
+                            let mut consumed = false;
                             if let Some(completion) = &mut self.completion {
-                                completion.update(&mut cxt);
-                                if completion.is_empty() {
-                                    self.completion = None;
+                                // use a fake context here
+                                let mut cx = Context {
+                                    editor: cxt.editor,
+                                    callbacks: cxt.callbacks,
+                                    executor: cx.executor,
+                                    scroll: None,
+                                };
+                                let res = completion.handle_event(event, &mut cx);
+
+                                if let EventResult::Consumed(callback) = res {
+                                    consumed = true;
+
+                                    if callback.is_some() {
+                                        // assume close_fn
+                                        self.completion = None;
+                                    }
+                                }
+                            }
+
+                            // if completion didn't take the event, we pass it onto commands
+                            if !consumed {
+                                self.insert_mode(&mut cxt, key);
+
+                                // lastly we recalculate completion
+                                if let Some(completion) = &mut self.completion {
+                                    completion.update(&mut cxt);
+                                    if completion.is_empty() {
+                                        self.completion = None;
+                                    }
+                                    // TODO: if exiting InsertMode, remove completion
                                 }
-                                // TODO: if exiting InsertMode, remove completion
                             }
                         }
-                        mode => self.command_mode(mode, &mut cxt, event),
+                        mode => self.command_mode(mode, &mut cxt, key),
                     }
                 }
                 self.on_next_key = cxt.on_next_key_callback.take();
@@ -554,7 +580,7 @@ impl Component for EditorView {
                     // how we entered insert mode is important, and we should track that so
                     // we can repeat the side effect.
 
-                    self.last_insert.0 = self.keymap[&mode][&event];
+                    self.last_insert.0 = self.keymap[&mode][&key];
                     self.last_insert.1.clear();
                 };