From d35637df5c7f4beff720a72d33034de1e55feeb4 Mon Sep 17 00:00:00 2001 From: "zed-zippy[bot]" <234243425+zed-zippy[bot]@users.noreply.github.com> Date: Wed, 4 Feb 2026 21:43:22 +0000 Subject: [PATCH] Add telemetry for toolbar menu open events (#48225) (cherry-pick to preview) (#48404) Cherry-pick of #48225 to preview ---- Closes #ISSUE Release Notes: - N/A *or* Added/Fixed/Improved ... --------- Co-authored-by: Ben Kunkle Co-authored-by: Zed Zippy <234243425+zed-zippy[bot]@users.noreply.github.com> Co-authored-by: Katie Geer Co-authored-by: Ben Kunkle Co-authored-by: Zed Zippy <234243425+zed-zippy[bot]@users.noreply.github.com> --- Cargo.lock | 1 + .../src/edit_prediction_button.rs | 103 ++++++++++++++++++ crates/language_tools/Cargo.toml | 3 +- crates/language_tools/src/lsp_button.rs | 20 +++- 4 files changed, 125 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 71e18afc2848c6597b8ceec795a6df68303a5075..d2c2572a4ed877e13cab6dd9d055afdb174c94ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9207,6 +9207,7 @@ dependencies = [ "serde_json", "settings", "sysinfo 0.37.2", + "telemetry", "theme", "tree-sitter", "ui", diff --git a/crates/edit_prediction_ui/src/edit_prediction_button.rs b/crates/edit_prediction_ui/src/edit_prediction_button.rs index 7344f8e4bf4d874e36d602a7c17682e17b138b94..a6f9d4d84f6e34ca672d81bde88397a420d05f6e 100644 --- a/crates/edit_prediction_ui/src/edit_prediction_button.rs +++ b/crates/edit_prediction_ui/src/edit_prediction_button.rs @@ -26,6 +26,7 @@ use settings::{ EXPERIMENTAL_ZETA2_EDIT_PREDICTION_PROVIDER_NAME, Settings, SettingsStore, update_settings_file, }; use std::{ + rc::Rc, sync::{Arc, LazyLock}, time::Duration, }; @@ -35,6 +36,7 @@ use ui::{ Indicator, PopoverMenu, PopoverMenuHandle, ProgressBar, Tooltip, prelude::*, }; use util::ResultExt as _; + use workspace::{ StatusItemView, Toast, Workspace, create_and_open_local_file, item::ItemHandle, notifications::NotificationId, @@ -147,8 +149,20 @@ impl Render for EditPredictionButton { } let this = cx.weak_entity(); let project = self.project.clone(); + let file = self.file.clone(); + let language = self.language.clone(); div().child( PopoverMenu::new("copilot") + .on_open({ + let file = file.clone(); + let language = language; + let project = project.clone(); + Rc::new(move |_window, cx| { + emit_edit_prediction_menu_opened( + "copilot", &file, &language, &project, cx, + ); + }) + }) .menu(move |window, cx| { let current_status = EditPredictionStore::try_global(cx) .and_then(|store| { @@ -207,9 +221,26 @@ impl Render for EditPredictionButton { let has_menu = status.has_menu(); let this = cx.weak_entity(); let fs = self.fs.clone(); + let file = self.file.clone(); + let language = self.language.clone(); + let project = self.project.clone(); div().child( PopoverMenu::new("supermaven") + .on_open({ + let file = file.clone(); + let language = language; + let project = project; + Rc::new(move |_window, cx| { + emit_edit_prediction_menu_opened( + "supermaven", + &file, + &language, + &project, + cx, + ); + }) + }) .menu(move |window, cx| match &status { SupermavenButtonStatus::NeedsActivation(activate_url) => { Some(ContextMenu::build(window, cx, |menu, _, _| { @@ -258,6 +289,9 @@ impl Render for EditPredictionButton { let enabled = self.editor_enabled.unwrap_or(true); let has_api_key = CodestralEditPredictionDelegate::has_api_key(cx); let this = cx.weak_entity(); + let file = self.file.clone(); + let language = self.language.clone(); + let project = self.project.clone(); let tooltip_meta = if has_api_key { "Powered by Codestral" @@ -267,6 +301,20 @@ impl Render for EditPredictionButton { div().child( PopoverMenu::new("codestral") + .on_open({ + let file = file.clone(); + let language = language; + let project = project; + Rc::new(move |_window, cx| { + emit_edit_prediction_menu_opened( + "codestral", + &file, + &language, + &project, + cx, + ); + }) + }) .menu(move |window, cx| { this.update(cx, |this, cx| { this.build_codestral_context_menu(window, cx) @@ -360,6 +408,14 @@ impl Render for EditPredictionButton { | EditPredictionProvider::Sweep | EditPredictionProvider::Mercury) => { let enabled = self.editor_enabled.unwrap_or(true); + let file = self.file.clone(); + let language = self.language.clone(); + let project = self.project.clone(); + let provider_name: &'static str = match provider { + EditPredictionProvider::Experimental(name) => name, + EditPredictionProvider::Zed => "zed", + _ => "unknown", + }; let icons = self .edit_prediction_provider .as_ref() @@ -486,6 +542,20 @@ impl Render for EditPredictionButton { let this = cx.weak_entity(); let mut popover_menu = PopoverMenu::new("edit-prediction") + .on_open({ + let file = file.clone(); + let language = language; + let project = project; + Rc::new(move |_window, cx| { + emit_edit_prediction_menu_opened( + provider_name, + &file, + &language, + &project, + cx, + ); + }) + }) .map(|popover_menu| { let this = this.clone(); popover_menu.menu(move |window, cx| { @@ -1498,6 +1568,39 @@ fn render_zeta_tab_animation(cx: &App) -> impl IntoElement { .child(tab_sequence(false)) } +fn emit_edit_prediction_menu_opened( + provider: &str, + file: &Option>, + language: &Option>, + project: &WeakEntity, + cx: &App, +) { + let language_name = language.as_ref().map(|l| l.name()); + let edit_predictions_enabled_for_language = + language_settings::language_settings(language_name, file.as_ref(), cx) + .show_edit_predictions; + let file_extension = file + .as_ref() + .and_then(|f| { + std::path::Path::new(f.file_name(cx)) + .extension() + .and_then(|e| e.to_str()) + }) + .map(|s| s.to_string()); + let is_via_ssh = project + .upgrade() + .map(|p| p.read(cx).is_via_remote_server()) + .unwrap_or(false); + telemetry::event!( + "Toolbar Menu Opened", + name = "Edit Predictions", + provider, + file_extension, + edit_predictions_enabled_for_language, + is_via_ssh, + ); +} + fn copilot_settings_url(enterprise_uri: Option<&str>) -> String { match enterprise_uri { Some(uri) => { diff --git a/crates/language_tools/Cargo.toml b/crates/language_tools/Cargo.toml index d5e1ab90b26d6cb8cd18025ec8f5fa9a940b3e59..8e3bb8bf55b8339551b486b332199774b5dd8428 100644 --- a/crates/language_tools/Cargo.toml +++ b/crates/language_tools/Cargo.toml @@ -28,6 +28,7 @@ project.workspace = true proto.workspace = true serde_json.workspace = true settings.workspace = true +telemetry.workspace = true theme.workspace = true tree-sitter.workspace = true sysinfo.workspace = true @@ -42,4 +43,4 @@ release_channel.workspace = true gpui = { workspace = true, features = ["test-support"] } semver.workspace = true util = { workspace = true, features = ["test-support"] } -zlog.workspace = true +zlog.workspace = true \ No newline at end of file diff --git a/crates/language_tools/src/lsp_button.rs b/crates/language_tools/src/lsp_button.rs index 77d58349a2b910aa58efeed7cbc8bdc840da3808..9da38f9d6b44a7daf760419a88d07b39a684533d 100644 --- a/crates/language_tools/src/lsp_button.rs +++ b/crates/language_tools/src/lsp_button.rs @@ -8,6 +8,8 @@ use std::{ use sysinfo::{Pid, ProcessRefreshKind, RefreshKind, System}; +use language::language_settings::{EditPredictionProvider, all_language_settings}; + use client::proto; use collections::HashSet; use editor::{Editor, EditorEvent}; @@ -1296,10 +1298,16 @@ impl Render for LspButton { return div().hidden(); } + let state = self.server_state.read(cx); + let is_via_ssh = state + .workspace + .upgrade() + .map(|workspace| workspace.read(cx).project().read(cx).is_via_remote_server()) + .unwrap_or(false); + let mut has_errors = false; let mut has_warnings = false; let mut has_other_notifications = false; - let state = self.server_state.read(cx); for binary_status in state.language_servers.binary_statuses.values() { has_errors |= matches!(binary_status.status, BinaryStatus::Failed { .. }); has_other_notifications |= binary_status.message.is_some(); @@ -1339,6 +1347,16 @@ impl Render for LspButton { div().child( PopoverMenu::new("lsp-tool") + .on_open(Rc::new(move |_window, cx| { + let copilot_enabled = all_language_settings(None, cx).edit_predictions.provider + == EditPredictionProvider::Copilot; + telemetry::event!( + "Toolbar Menu Opened", + name = "Language Servers", + copilot_enabled, + is_via_ssh, + ); + })) .menu(move |_, cx| { lsp_button .read_with(cx, |lsp_button, _| lsp_button.lsp_menu.clone())