Rework code to contain submitting of copilot events within editor

Joseph Lyons created

Change summary

Cargo.lock                    |  1 
crates/copilot/Cargo.toml     |  1 
crates/copilot/src/copilot.rs | 64 ++----------------------------------
crates/editor/src/editor.rs   | 50 ++++++++++++++++++++--------
crates/zed/src/main.rs        |  3 -
5 files changed, 40 insertions(+), 79 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -1338,7 +1338,6 @@ dependencies = [
  "anyhow",
  "async-compression",
  "async-tar",
- "client",
  "clock",
  "collections",
  "context_menu",

crates/copilot/Cargo.toml 🔗

@@ -22,7 +22,6 @@ test-support = [
 collections = { path = "../collections" }
 context_menu = { path = "../context_menu" }
 gpui = { path = "../gpui" }
-client = { path = "../client" }
 language = { path = "../language" }
 settings = { path = "../settings" }
 theme = { path = "../theme" }

crates/copilot/src/copilot.rs 🔗

@@ -4,7 +4,6 @@ mod sign_in;
 use anyhow::{anyhow, Context, Result};
 use async_compression::futures::bufread::GzipDecoder;
 use async_tar::Archive;
-use client::{ClickhouseEvent, Client};
 use collections::HashMap;
 use futures::{channel::oneshot, future::Shared, Future, FutureExt, TryFutureExt};
 use gpui::{
@@ -41,38 +40,13 @@ actions!(
     [Suggest, NextSuggestion, PreviousSuggestion, Reinstall]
 );
 
-pub fn init(client: &Client, node_runtime: Arc<NodeRuntime>, cx: &mut AppContext) {
+pub fn init(http: Arc<dyn HttpClient>, node_runtime: Arc<NodeRuntime>, cx: &mut AppContext) {
     let copilot = cx.add_model({
         let node_runtime = node_runtime.clone();
-        move |cx| Copilot::start(client.http_client(), node_runtime, cx)
+        move |cx| Copilot::start(http, node_runtime, cx)
     });
     cx.set_global(copilot.clone());
 
-    let telemetry_settings = cx.global::<Settings>().telemetry();
-    let telemetry = client.telemetry().clone();
-
-    cx.subscribe(&copilot, move |_, event, _| match event {
-        Event::CompletionAccepted { uuid, file_type } => {
-            let event = ClickhouseEvent::Copilot {
-                suggestion_id: uuid.clone(),
-                suggestion_accepted: true,
-                file_extension: file_type.clone().map(|a| a.to_string()),
-            };
-            telemetry.report_clickhouse_event(event, telemetry_settings);
-        }
-        Event::CompletionsDiscarded { uuids, file_type } => {
-            for uuid in uuids {
-                let event = ClickhouseEvent::Copilot {
-                    suggestion_id: uuid.clone(),
-                    suggestion_accepted: false,
-                    file_extension: file_type.clone().map(|a| a.to_string()),
-                };
-                telemetry.report_clickhouse_event(event, telemetry_settings);
-            }
-        }
-    })
-    .detach();
-
     cx.observe(&copilot, |handle, cx| {
         let status = handle.read(cx).status();
         cx.update_default_global::<collections::CommandPaletteFilter, _, _>(move |filter, _cx| {
@@ -284,7 +258,7 @@ impl RegisteredBuffer {
 
 #[derive(Debug)]
 pub struct Completion {
-    uuid: String,
+    pub uuid: String,
     pub range: Range<Anchor>,
     pub text: String,
 }
@@ -296,19 +270,8 @@ pub struct Copilot {
     buffers: HashMap<u64, WeakModelHandle<Buffer>>,
 }
 
-pub enum Event {
-    CompletionAccepted {
-        uuid: String,
-        file_type: Option<Arc<str>>,
-    },
-    CompletionsDiscarded {
-        uuids: Vec<String>,
-        file_type: Option<Arc<str>>,
-    },
-}
-
 impl Entity for Copilot {
-    type Event = Event;
+    type Event = ();
 
     fn app_will_quit(
         &mut self,
@@ -774,26 +737,18 @@ 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(())
@@ -803,22 +758,12 @@ 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::CompletionsDiscarded {
-            uuids: completions
-                .iter()
-                .map(|completion| completion.uuid.clone())
-                .collect(),
-            file_type: file_type.clone(),
-        });
-
         let request =
             server
                 .lsp
@@ -828,7 +773,6 @@ impl Copilot {
                         .map(|completion| completion.uuid.clone())
                         .collect(),
                 });
-
         cx.background().spawn(async move {
             request.await?;
             Ok(())

crates/editor/src/editor.rs 🔗

@@ -3094,15 +3094,11 @@ 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, language, cx)
-                    })
+                    .update(cx, |copilot, cx| copilot.accept_completion(completion, cx))
                     .detach_and_log_err(cx);
+
+                self.report_copilot_event(completion.uuid.clone(), true, cx)
             }
             self.insert_with_autoindent_mode(&suggestion.text.to_string(), None, cx);
             cx.notify();
@@ -3115,18 +3111,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, file_type, cx)
+                        copilot.discard_completions(&self.copilot_state.completions, cx)
                     })
                     .detach_and_log_err(cx);
+
+                for completion in &self.copilot_state.completions {
+                    self.report_copilot_event(completion.uuid.clone(), false, cx)
+                }
             }
 
             self.display_map
@@ -6889,6 +6882,33 @@ impl Editor {
             .collect()
     }
 
+    fn report_copilot_event(
+        &self,
+        suggestion_id: String,
+        suggestion_accepted: bool,
+        cx: &AppContext,
+    ) {
+        if let Some((project, file)) = self.project.as_ref().zip(
+            self.buffer
+                .read(cx)
+                .as_singleton()
+                .and_then(|b| b.read(cx).file()),
+        ) {
+            let telemetry_settings = cx.global::<Settings>().telemetry();
+            let extension = Path::new(file.file_name(cx))
+                .extension()
+                .and_then(|e| e.to_str());
+            let telemetry = project.read(cx).client().telemetry().clone();
+
+            let event = ClickhouseEvent::Copilot {
+                suggestion_id,
+                suggestion_accepted,
+                file_extension: extension.map(ToString::to_string),
+            };
+            telemetry.report_clickhouse_event(event, telemetry_settings);
+        }
+    }
+
     fn report_editor_event(&self, name: &'static str, cx: &AppContext) {
         if let Some((project, file)) = self.project.as_ref().zip(
             self.buffer

crates/zed/src/main.rs 🔗

@@ -178,6 +178,7 @@ fn main() {
         vim::init(cx);
         terminal_view::init(cx);
         theme_testbench::init(cx);
+        copilot::init(http.clone(), node_runtime, cx);
 
         cx.spawn(|cx| watch_themes(fs.clone(), themes.clone(), cx))
             .detach();
@@ -196,8 +197,6 @@ fn main() {
             cx.global::<Settings>().telemetry(),
         );
 
-        copilot::init(&client, node_runtime, cx);
-
         let app_state = Arc::new(AppState {
             languages,
             themes,