Add events for copilot suggestion accepting and discarding

Mikayla Maki created

Change summary

crates/copilot/src/copilot.rs | 36 +++++++++++++++++++++++++++++++++++-
crates/editor/src/editor.rs   | 16 ++++++++++++++--
2 files changed, 49 insertions(+), 3 deletions(-)

Detailed changes

crates/copilot/src/copilot.rs 🔗

@@ -47,6 +47,10 @@ pub fn init(http: Arc<dyn HttpClient>, node_runtime: Arc<NodeRuntime>, cx: &mut
     });
     cx.set_global(copilot.clone());
 
+    //////////////////////////////////////
+    // SUBSCRIBE TO COPILOT EVENTS HERE //
+    //////////////////////////////////////
+
     cx.observe(&copilot, |handle, cx| {
         let status = handle.read(cx).status();
         cx.update_default_global::<collections::CommandPaletteFilter, _, _>(move |filter, _cx| {
@@ -270,8 +274,19 @@ pub struct Copilot {
     buffers: HashMap<u64, WeakModelHandle<Buffer>>,
 }
 
+pub enum Event {
+    CompletionAccepted {
+        uuid: String,
+        file_type: Option<Arc<str>>,
+    },
+    CompletionDiscarded {
+        uuids: Vec<String>,
+        file_type: Option<Arc<str>>,
+    },
+}
+
 impl Entity for Copilot {
-    type Event = ();
+    type Event = Event;
 
     fn app_will_quit(
         &mut self,
@@ -737,18 +752,26 @@ impl Copilot {
     pub fn accept_completion(
         &mut self,
         completion: &Completion,
+        file_type: Option<Arc<str>>,
         cx: &mut ModelContext<Self>,
     ) -> Task<Result<()>> {
         let server = match self.server.as_authenticated() {
             Ok(server) => server,
             Err(error) => return Task::ready(Err(error)),
         };
+
+        cx.emit(Event::CompletionAccepted {
+            uuid: completion.uuid.clone(),
+            file_type,
+        });
+
         let request =
             server
                 .lsp
                 .request::<request::NotifyAccepted>(request::NotifyAcceptedParams {
                     uuid: completion.uuid.clone(),
                 });
+
         cx.background().spawn(async move {
             request.await?;
             Ok(())
@@ -758,12 +781,22 @@ impl Copilot {
     pub fn discard_completions(
         &mut self,
         completions: &[Completion],
+        file_type: Option<Arc<str>>,
         cx: &mut ModelContext<Self>,
     ) -> Task<Result<()>> {
         let server = match self.server.as_authenticated() {
             Ok(server) => server,
             Err(error) => return Task::ready(Err(error)),
         };
+
+        cx.emit(Event::CompletionDiscarded {
+            uuids: completions
+                .iter()
+                .map(|completion| completion.uuid.clone())
+                .collect(),
+            file_type: file_type.clone(),
+        });
+
         let request =
             server
                 .lsp
@@ -773,6 +806,7 @@ impl Copilot {
                         .map(|completion| completion.uuid.clone())
                         .collect(),
                 });
+
         cx.background().spawn(async move {
             request.await?;
             Ok(())

crates/editor/src/editor.rs 🔗

@@ -3094,8 +3094,14 @@ impl Editor {
             if let Some((copilot, completion)) =
                 Copilot::global(cx).zip(self.copilot_state.active_completion())
             {
+                let language = self
+                    .language_at(completion.range.start.offset, cx)
+                    .map(|language| language.name());
+
                 copilot
-                    .update(cx, |copilot, cx| copilot.accept_completion(completion, cx))
+                    .update(cx, |copilot, cx| {
+                        copilot.accept_completion(completion, language, cx)
+                    })
                     .detach_and_log_err(cx);
             }
             self.insert_with_autoindent_mode(&suggestion.text.to_string(), None, cx);
@@ -3109,9 +3115,15 @@ impl Editor {
     fn discard_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) -> bool {
         if self.has_active_copilot_suggestion(cx) {
             if let Some(copilot) = Copilot::global(cx) {
+                let file_type = self.copilot_state
+                    .completions
+                    .get(0)
+                    .and_then(|completion| self.language_at(completion.range.start.offset, cx))
+                    .map(|language| language.name());
+
                 copilot
                     .update(cx, |copilot, cx| {
-                        copilot.discard_completions(&self.copilot_state.completions, cx)
+                        copilot.discard_completions(&self.copilot_state.completions, file_type, cx)
                     })
                     .detach_and_log_err(cx);
             }