diff --git a/Cargo.lock b/Cargo.lock index 80d3092d51799cc42b007e7a447888192e9688cf..90edb241138ff3b378f79a2647c6769da9b46c7f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3260,6 +3260,7 @@ dependencies = [ "futures 0.3.31", "gpui", "http_client", + "icons", "language", "language_models", "log", @@ -3693,6 +3694,7 @@ dependencies = [ "futures 0.3.31", "gpui", "http_client", + "icons", "indoc", "language", "log", @@ -5402,6 +5404,7 @@ version = "0.1.0" dependencies = [ "client", "gpui", + "icons", "language", "text", ] diff --git a/assets/icons/sweep_ai.svg b/assets/icons/sweep_ai.svg index bf3459c7ea9896bc6c1d2297d1f7671cfc8a4d46..9c63c810dd9e164c14c1ad1a1bca9c6ec68fc95e 100644 --- a/assets/icons/sweep_ai.svg +++ b/assets/icons/sweep_ai.svg @@ -1,32 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/assets/icons/sweep_ai_disabled.svg b/assets/icons/sweep_ai_disabled.svg new file mode 100644 index 0000000000000000000000000000000000000000..b15a8d8526f36f312482effefd3d7538ce5f7a04 --- /dev/null +++ b/assets/icons/sweep_ai_disabled.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/sweep_ai_down.svg b/assets/icons/sweep_ai_down.svg new file mode 100644 index 0000000000000000000000000000000000000000..f08dcb171811c761cd13c4efd0ef0acdc78f9951 --- /dev/null +++ b/assets/icons/sweep_ai_down.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/sweep_ai_error.svg b/assets/icons/sweep_ai_error.svg new file mode 100644 index 0000000000000000000000000000000000000000..95285a1273e72ec4f02cb23e3c2fb39460f42761 --- /dev/null +++ b/assets/icons/sweep_ai_error.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/sweep_ai_up.svg b/assets/icons/sweep_ai_up.svg new file mode 100644 index 0000000000000000000000000000000000000000..7c28282a6a14c47561a50ab456c0bec2e05b07cc --- /dev/null +++ b/assets/icons/sweep_ai_up.svg @@ -0,0 +1 @@ + diff --git a/crates/codestral/Cargo.toml b/crates/codestral/Cargo.toml index 7da3bed75a9f175b49b3b11f00fd1d1583743f5e..0036e9df0f89bef0e4fec6ca48951549a5d55bb4 100644 --- a/crates/codestral/Cargo.toml +++ b/crates/codestral/Cargo.toml @@ -15,6 +15,7 @@ edit_prediction.workspace = true futures.workspace = true gpui.workspace = true http_client.workspace = true +icons.workspace = true language.workspace = true language_models.workspace = true log.workspace = true diff --git a/crates/codestral/src/codestral.rs b/crates/codestral/src/codestral.rs index afec79bef7f6d5f523b1ad2d110982e0a1dd467a..270526f0e323d0792167a8538baebe193a852e08 100644 --- a/crates/codestral/src/codestral.rs +++ b/crates/codestral/src/codestral.rs @@ -1,9 +1,10 @@ use anyhow::Result; use edit_prediction::cursor_excerpt; -use edit_prediction_types::{EditPrediction, EditPredictionDelegate}; +use edit_prediction_types::{EditPrediction, EditPredictionDelegate, EditPredictionIconSet}; use futures::AsyncReadExt; use gpui::{App, Context, Entity, Task}; use http_client::HttpClient; +use icons::IconName; use language::{ language_settings::all_language_settings, Anchor, Buffer, BufferSnapshot, EditPreview, ToPoint, }; @@ -172,6 +173,10 @@ impl EditPredictionDelegate for CodestralEditPredictionDelegate { true } + fn icons(&self, _cx: &App) -> EditPredictionIconSet { + EditPredictionIconSet::new(IconName::AiMistral) + } + fn is_enabled(&self, _buffer: &Entity, _cursor_position: Anchor, cx: &App) -> bool { Self::api_key(cx).is_some() } diff --git a/crates/copilot/Cargo.toml b/crates/copilot/Cargo.toml index a07811cd2e3a6b17a1bf23c24ae7af376ef9b37a..6e5144ff6346375e90ea368074b5da7c4e7a5d87 100644 --- a/crates/copilot/Cargo.toml +++ b/crates/copilot/Cargo.toml @@ -32,6 +32,7 @@ fs.workspace = true futures.workspace = true gpui.workspace = true edit_prediction_types.workspace = true +icons.workspace = true language.workspace = true log.workspace = true lsp.workspace = true diff --git a/crates/copilot/src/copilot_edit_prediction_delegate.rs b/crates/copilot/src/copilot_edit_prediction_delegate.rs index ffd4414a49066175cc58ad1c59dacb8d31a94bff..c7a7963de26564df81e91c4602c19f8ccc437179 100644 --- a/crates/copilot/src/copilot_edit_prediction_delegate.rs +++ b/crates/copilot/src/copilot_edit_prediction_delegate.rs @@ -6,8 +6,11 @@ use crate::{ }, }; use anyhow::Result; -use edit_prediction_types::{EditPrediction, EditPredictionDelegate, interpolate_edits}; +use edit_prediction_types::{ + EditPrediction, EditPredictionDelegate, EditPredictionIconSet, interpolate_edits, +}; use gpui::{App, Context, Entity, Task}; +use icons::IconName; use language::{Anchor, Buffer, BufferSnapshot, EditPreview, OffsetRangeExt, ToPointUtf16}; use std::{ops::Range, sync::Arc, time::Duration}; @@ -50,6 +53,12 @@ impl EditPredictionDelegate for CopilotEditPredictionDelegate { true } + fn icons(&self, _cx: &App) -> EditPredictionIconSet { + EditPredictionIconSet::new(IconName::Copilot) + .with_disabled(IconName::CopilotDisabled) + .with_error(IconName::CopilotError) + } + fn is_refreshing(&self, _cx: &App) -> bool { self.pending_refresh.is_some() && self.completion.is_none() } diff --git a/crates/edit_prediction/src/edit_prediction.rs b/crates/edit_prediction/src/edit_prediction.rs index 0d34f7b0fe5ee0f90cb137c0837f03c08b635fe1..5d49dd18524ddc95ace929982ad90fc5d2f70fdf 100644 --- a/crates/edit_prediction/src/edit_prediction.rs +++ b/crates/edit_prediction/src/edit_prediction.rs @@ -659,6 +659,32 @@ impl EditPredictionStore { self.edit_prediction_model = model; } + pub fn icons(&self) -> edit_prediction_types::EditPredictionIconSet { + use ui::IconName; + match self.edit_prediction_model { + EditPredictionModel::Ollama => { + edit_prediction_types::EditPredictionIconSet::new(IconName::AiOllama) + } + EditPredictionModel::Sweep => { + edit_prediction_types::EditPredictionIconSet::new(IconName::SweepAi) + .with_disabled(IconName::SweepAiDisabled) + .with_up(IconName::SweepAiUp) + .with_down(IconName::SweepAiDown) + .with_error(IconName::SweepAiError) + } + EditPredictionModel::Mercury => { + edit_prediction_types::EditPredictionIconSet::new(IconName::Inception) + } + EditPredictionModel::Zeta1 | EditPredictionModel::Zeta2 { .. } => { + edit_prediction_types::EditPredictionIconSet::new(IconName::ZedPredict) + .with_disabled(IconName::ZedPredictDisabled) + .with_up(IconName::ZedPredictUp) + .with_down(IconName::ZedPredictDown) + .with_error(IconName::ZedPredictError) + } + } + } + pub fn has_sweep_api_token(&self, cx: &App) -> bool { self.sweep_ai.api_token.read(cx).has_key() } diff --git a/crates/edit_prediction/src/zed_edit_prediction_delegate.rs b/crates/edit_prediction/src/zed_edit_prediction_delegate.rs index cdfe230d4bf84e9e5c891efa0a1f38a07839e37f..02c91ad159dd824c6ac7ed00df483cfbb0bd836e 100644 --- a/crates/edit_prediction/src/zed_edit_prediction_delegate.rs +++ b/crates/edit_prediction/src/zed_edit_prediction_delegate.rs @@ -2,10 +2,13 @@ use std::{cmp, sync::Arc}; use client::{Client, UserStore}; use cloud_llm_client::EditPredictionRejectReason; -use edit_prediction_types::{DataCollectionState, EditPredictionDelegate, SuggestionDisplayType}; +use edit_prediction_types::{ + DataCollectionState, EditPredictionDelegate, EditPredictionIconSet, SuggestionDisplayType, +}; use gpui::{App, Entity, prelude::*}; use language::{Buffer, ToPoint as _}; use project::Project; +use ui::prelude::*; use crate::{BufferEditPrediction, EditPredictionModel, EditPredictionStore}; @@ -58,6 +61,25 @@ impl EditPredictionDelegate for ZedEditPredictionDelegate { true } + fn icons(&self, cx: &App) -> EditPredictionIconSet { + match self.store.read(cx).edit_prediction_model { + EditPredictionModel::Ollama => EditPredictionIconSet::new(IconName::AiOllama), + EditPredictionModel::Sweep => EditPredictionIconSet::new(IconName::SweepAi) + .with_disabled(IconName::SweepAiDisabled) + .with_up(IconName::SweepAiUp) + .with_down(IconName::SweepAiDown) + .with_error(IconName::SweepAiError), + EditPredictionModel::Mercury => EditPredictionIconSet::new(IconName::Inception), + EditPredictionModel::Zeta1 | EditPredictionModel::Zeta2 { .. } => { + EditPredictionIconSet::new(IconName::ZedPredict) + .with_disabled(IconName::ZedPredictDisabled) + .with_up(IconName::ZedPredictUp) + .with_down(IconName::ZedPredictDown) + .with_error(IconName::ZedPredictError) + } + } + } + fn data_collection_state(&self, cx: &App) -> DataCollectionState { if let Some(buffer) = &self.singleton_buffer && let Some(file) = buffer.read(cx).file() diff --git a/crates/edit_prediction_types/Cargo.toml b/crates/edit_prediction_types/Cargo.toml index 00a8577911af0afd012535fd324a68af8fd70391..4de0c9f62c5e556d20fe55ef69513cb807ff8164 100644 --- a/crates/edit_prediction_types/Cargo.toml +++ b/crates/edit_prediction_types/Cargo.toml @@ -14,5 +14,6 @@ path = "src/edit_prediction_types.rs" [dependencies] client.workspace = true gpui.workspace = true +icons.workspace = true language.workspace = true text.workspace = true diff --git a/crates/edit_prediction_types/src/edit_prediction_types.rs b/crates/edit_prediction_types/src/edit_prediction_types.rs index 9cb191f7b99da7229bd686abeb46fdef3f2274be..80e62a2b0d579f3accaec6db22f0a435d9a73ca1 100644 --- a/crates/edit_prediction_types/src/edit_prediction_types.rs +++ b/crates/edit_prediction_types/src/edit_prediction_types.rs @@ -2,8 +2,78 @@ use std::{ops::Range, sync::Arc}; use client::EditPredictionUsage; use gpui::{App, Context, Entity, SharedString}; +use icons::IconName; use language::{Anchor, Buffer, OffsetRangeExt}; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct EditPredictionIconSet { + pub base: IconName, + pub disabled: IconName, + pub up: IconName, + pub down: IconName, + pub error: IconName, +} + +impl EditPredictionIconSet { + pub fn new(base: IconName) -> Self { + Self { + base, + disabled: IconName::ZedPredictDisabled, + up: IconName::ZedPredictUp, + down: IconName::ZedPredictDown, + error: IconName::ZedPredictError, + } + } + + pub fn with_disabled(mut self, disabled: IconName) -> Self { + self.disabled = disabled; + self + } + + pub fn with_up(mut self, up: IconName) -> Self { + self.up = up; + self + } + + pub fn with_down(mut self, down: IconName) -> Self { + self.down = down; + self + } + + pub fn with_error(mut self, error: IconName) -> Self { + self.error = error; + self + } +} + +/// Represents a predicted cursor position after an edit is applied. +/// +/// Since the cursor may be positioned inside newly inserted text that doesn't +/// exist in the original buffer, we store an anchor (which points to a position +/// in the original buffer, typically the start of an edit) plus an offset into +/// the inserted text. +#[derive(Clone, Debug)] +pub struct PredictedCursorPosition { + /// An anchor in the original buffer. If the cursor is inside an edit, + /// this points to the start of that edit's range. + pub anchor: language::Anchor, + /// Offset from the anchor into the new text. If the cursor is inside + /// inserted text, this is the offset within that insertion. If the cursor + /// is outside any edit, this is 0. + pub offset: usize, +} + +impl PredictedCursorPosition { + pub fn new(anchor: language::Anchor, offset: usize) -> Self { + Self { anchor, offset } + } + + /// Creates a predicted cursor position at an exact anchor location (offset = 0). + pub fn at_anchor(anchor: language::Anchor) -> Self { + Self { anchor, offset: 0 } + } +} + /// The display mode used when showing an edit prediction to the user. /// Used for metrics tracking. #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -81,6 +151,8 @@ pub trait EditPredictionDelegate: 'static + Sized { true } + fn icons(&self, cx: &App) -> EditPredictionIconSet; + fn data_collection_state(&self, _cx: &App) -> DataCollectionState { DataCollectionState::Unsupported } @@ -127,6 +199,7 @@ pub trait EditPredictionDelegateHandle { fn show_predictions_in_menu(&self) -> bool; fn show_tab_accept_marker(&self) -> bool; fn supports_jump_to_edit(&self) -> bool; + fn icons(&self, cx: &App) -> EditPredictionIconSet; fn data_collection_state(&self, cx: &App) -> DataCollectionState; fn usage(&self, cx: &App) -> Option; fn toggle_data_collection(&self, cx: &mut App); @@ -173,6 +246,10 @@ where T::supports_jump_to_edit() } + fn icons(&self, cx: &App) -> EditPredictionIconSet { + self.read(cx).icons(cx) + } + fn data_collection_state(&self, cx: &App) -> DataCollectionState { self.read(cx).data_collection_state(cx) } diff --git a/crates/edit_prediction_ui/src/edit_prediction_button.rs b/crates/edit_prediction_ui/src/edit_prediction_button.rs index 395afaf31f40c9ce3f8c77b5210432f1cef1f129..7344f8e4bf4d874e36d602a7c17682e17b138b94 100644 --- a/crates/edit_prediction_ui/src/edit_prediction_button.rs +++ b/crates/edit_prediction_ui/src/edit_prediction_button.rs @@ -360,6 +360,13 @@ impl Render for EditPredictionButton { | EditPredictionProvider::Sweep | EditPredictionProvider::Mercury) => { let enabled = self.editor_enabled.unwrap_or(true); + let icons = self + .edit_prediction_provider + .as_ref() + .map(|p| p.icons(cx)) + .unwrap_or_else(|| { + edit_prediction_types::EditPredictionIconSet::new(IconName::ZedPredict) + }); let ep_icon; let tooltip_meta; @@ -369,17 +376,15 @@ impl Render for EditPredictionButton { EditPredictionProvider::Sweep => { missing_token = edit_prediction::EditPredictionStore::try_global(cx) .is_some_and(|ep_store| !ep_store.read(cx).has_sweep_api_token(cx)); - ep_icon = IconName::SweepAi; + ep_icon = if enabled { icons.base } else { icons.disabled }; tooltip_meta = if missing_token { "Missing API key for Sweep" } else { "Powered by Sweep" }; - missing_token = edit_prediction::EditPredictionStore::try_global(cx) - .is_some_and(|ep_store| !ep_store.read(cx).has_sweep_api_token(cx)); } EditPredictionProvider::Mercury => { - ep_icon = IconName::Inception; + ep_icon = if enabled { icons.base } else { icons.disabled }; missing_token = edit_prediction::EditPredictionStore::try_global(cx) .is_some_and(|ep_store| !ep_store.read(cx).has_mercury_api_token(cx)); tooltip_meta = if missing_token { @@ -389,11 +394,7 @@ impl Render for EditPredictionButton { }; } _ => { - ep_icon = if enabled { - IconName::ZedPredict - } else { - IconName::ZedPredictDisabled - }; + ep_icon = if enabled { icons.base } else { icons.disabled }; tooltip_meta = "Powered by Zeta" } }; @@ -889,10 +890,17 @@ impl EditPredictionButton { ); if !self.editor_enabled.unwrap_or(true) { + let icons = self + .edit_prediction_provider + .as_ref() + .map(|p| p.icons(cx)) + .unwrap_or_else(|| { + edit_prediction_types::EditPredictionIconSet::new(IconName::ZedPredict) + }); menu = menu.item( ContextMenuEntry::new("This file is excluded.") .disabled(true) - .icon(IconName::ZedPredictDisabled) + .icon(icons.disabled) .icon_size(IconSize::Small), ); } diff --git a/crates/edit_prediction_ui/src/rate_prediction_modal.rs b/crates/edit_prediction_ui/src/rate_prediction_modal.rs index 936c51a2ae9bc5f8b72578f2adf022ecb8a9d6b9..65ce7ec8761541d886f272baa3934af58884524d 100644 --- a/crates/edit_prediction_ui/src/rate_prediction_modal.rs +++ b/crates/edit_prediction_ui/src/rate_prediction_modal.rs @@ -839,20 +839,21 @@ impl Render for RatePredictionsModal { .border_color(border_color) .flex_shrink_0() .overflow_hidden() - .child( + .child({ + let icons = self.ep_store.read(cx).icons(); h_flex() .h_8() .px_2() .justify_between() .border_b_1() .border_color(border_color) - .child(Icon::new(IconName::ZedPredict).size(IconSize::Small)) + .child(Icon::new(icons.base).size(IconSize::Small)) .child( Label::new("From most recent to oldest") .color(Color::Muted) .size(LabelSize::Small), - ), - ) + ) + }) .child( div() .id("completion_list") diff --git a/crates/editor/src/edit_prediction_tests.rs b/crates/editor/src/edit_prediction_tests.rs index b5931cde42a4e2c0e21b2d1f68558879de9750b4..798860d0aa201733f7852808405f261cf38b9112 100644 --- a/crates/editor/src/edit_prediction_tests.rs +++ b/crates/editor/src/edit_prediction_tests.rs @@ -1,9 +1,10 @@ -use edit_prediction_types::EditPredictionDelegate; +use edit_prediction_types::{EditPredictionDelegate, EditPredictionIconSet}; use gpui::{Entity, KeyBinding, Modifiers, prelude::*}; use indoc::indoc; use multi_buffer::{Anchor, MultiBufferSnapshot, ToPoint}; use std::{ops::Range, sync::Arc}; use text::{Point, ToOffset}; +use ui::prelude::*; use crate::{ AcceptEditPrediction, EditPrediction, MenuEditPredictionsPolicy, editor_tests::init_test, @@ -463,6 +464,10 @@ impl EditPredictionDelegate for FakeEditPredictionDelegate { true } + fn icons(&self, _cx: &gpui::App) -> EditPredictionIconSet { + EditPredictionIconSet::new(IconName::ZedPredict) + } + fn is_enabled( &self, _buffer: &gpui::Entity, @@ -530,6 +535,10 @@ impl EditPredictionDelegate for FakeNonZedEditPredictionDelegate { false } + fn icons(&self, _cx: &gpui::App) -> EditPredictionIconSet { + EditPredictionIconSet::new(IconName::ZedPredict) + } + fn is_enabled( &self, _buffer: &gpui::Entity, diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index e4b3d1a6bb37f0080ba470c575fca2f82e8a6e31..b9c9cc3e80a9631fb1f88513650eaeed75d92e2b 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -9722,6 +9722,7 @@ impl Editor { let keybind = self.render_edit_prediction_accept_keybind(window, cx); let has_keybind = keybind.is_some(); + let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx); h_flex() .id("ep-line-popover") @@ -9740,7 +9741,7 @@ impl Editor { el.bg(status_colors.error_background) .border_color(status_colors.error.opacity(0.6)) .pl_2() - .child(Icon::new(IconName::ZedPredictError).color(Color::Error)) + .child(Icon::new(icons.error).color(Color::Error)) .cursor_default() .hoverable_tooltip(move |_window, cx| { cx.new(|_| MissingEditPredictionKeybindingTooltip).into() @@ -9780,6 +9781,7 @@ impl Editor { ) -> Stateful
{ let keybind = self.render_edit_prediction_accept_keybind(window, cx); let has_keybind = keybind.is_some(); + let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx); let file_name = snapshot .file() @@ -9802,7 +9804,7 @@ impl Editor { el.bg(status_colors.error_background) .border_color(status_colors.error.opacity(0.6)) .pl_2() - .child(Icon::new(IconName::ZedPredictError).color(Color::Error)) + .child(Icon::new(icons.error).color(Color::Error)) .cursor_default() .hoverable_tooltip(move |_window, cx| { cx.new(|_| MissingEditPredictionKeybindingTooltip).into() @@ -9844,16 +9846,13 @@ impl Editor { let editor_bg_color = cx.theme().colors().editor_background; editor_bg_color.blend(accent_color.opacity(0.6)) } - fn get_prediction_provider_icon_name( + fn get_prediction_provider_icons( provider: &Option, - ) -> IconName { + cx: &App, + ) -> edit_prediction_types::EditPredictionIconSet { match provider { - Some(provider) => match provider.provider.name() { - "copilot" => IconName::Copilot, - "supermaven" => IconName::Supermaven, - _ => IconName::ZedPredict, - }, - None => IconName::ZedPredict, + Some(provider) => provider.provider.icons(cx), + None => edit_prediction_types::EditPredictionIconSet::new(IconName::ZedPredict), } } @@ -9868,7 +9867,7 @@ impl Editor { cx: &mut Context, ) -> Option { let provider = self.edit_prediction_provider.as_ref()?; - let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider); + let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx); let is_refreshing = provider.provider.is_refreshing(cx); @@ -9898,16 +9897,16 @@ impl Editor { use text::ToPoint as _; if target.text_anchor.to_point(snapshot).row > cursor_point.row { - Icon::new(IconName::ZedPredictDown) + Icon::new(icons.down) } else { - Icon::new(IconName::ZedPredictUp) + Icon::new(icons.up) } } EditPrediction::MoveOutside { .. } => { // TODO [zeta2] custom icon for external jump? - Icon::new(provider_icon) + Icon::new(icons.base) } - EditPrediction::Edit { .. } => Icon::new(provider_icon), + EditPrediction::Edit { .. } => Icon::new(icons.base), })) .child( h_flex() @@ -9974,11 +9973,11 @@ impl Editor { cx, )?, - None => pending_completion_container(provider_icon) + None => pending_completion_container(icons.base) .child(Label::new("...").size(LabelSize::Small)), }, - None => pending_completion_container(provider_icon) + None => pending_completion_container(icons.base) .child(Label::new("...").size(LabelSize::Small)), }; @@ -10088,6 +10087,8 @@ impl Editor { .map(|provider| provider.provider.supports_jump_to_edit()) .unwrap_or(true); + let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx); + match &completion.completion { EditPrediction::MoveWithin { target, snapshot, .. @@ -10103,9 +10104,9 @@ impl Editor { .flex_1() .child( if target.text_anchor.to_point(snapshot).row > cursor_point.row { - Icon::new(IconName::ZedPredictDown) + Icon::new(icons.down) } else { - Icon::new(IconName::ZedPredictUp) + Icon::new(icons.up) }, ) .child(Label::new("Jump to Edit")), @@ -10121,7 +10122,7 @@ impl Editor { .px_2() .gap_2() .flex_1() - .child(Icon::new(IconName::ZedPredict)) + .child(Icon::new(icons.base)) .child(Label::new(format!("Jump to {file_name}"))), ) } @@ -10154,9 +10155,7 @@ impl Editor { render_relative_row_jump("", cursor_point.row, first_edit_row) .into_any_element() } else { - let icon_name = - Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider); - Icon::new(icon_name).into_any_element() + Icon::new(icons.base).into_any_element() }; Some( diff --git a/crates/icons/src/icons.rs b/crates/icons/src/icons.rs index 386414e7d7ddc223394a91381babf2f446a48be3..d55442448b0d62a5dc98895e87fcd04242bb9f9f 100644 --- a/crates/icons/src/icons.rs +++ b/crates/icons/src/icons.rs @@ -222,6 +222,10 @@ pub enum IconName { SupermavenInit, SwatchBook, SweepAi, + SweepAiDisabled, + SweepAiDown, + SweepAiError, + SweepAiUp, Tab, Terminal, TerminalAlt, diff --git a/crates/supermaven/src/supermaven_edit_prediction_delegate.rs b/crates/supermaven/src/supermaven_edit_prediction_delegate.rs index 9563a0aa99f1760b5af214be28f25dbf1734c371..248177d577284f43ee9959887651b496c8492770 100644 --- a/crates/supermaven/src/supermaven_edit_prediction_delegate.rs +++ b/crates/supermaven/src/supermaven_edit_prediction_delegate.rs @@ -1,6 +1,6 @@ use crate::{Supermaven, SupermavenCompletionStateId}; use anyhow::Result; -use edit_prediction_types::{EditPrediction, EditPredictionDelegate}; +use edit_prediction_types::{EditPrediction, EditPredictionDelegate, EditPredictionIconSet}; use futures::StreamExt as _; use gpui::{App, Context, Entity, EntityId, Task}; use language::{Anchor, Buffer, BufferSnapshot}; @@ -11,6 +11,7 @@ use std::{ time::Duration, }; use text::{ToOffset, ToPoint}; +use ui::prelude::*; use unicode_segmentation::UnicodeSegmentation; pub const DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(75); @@ -125,6 +126,12 @@ impl EditPredictionDelegate for SupermavenEditPredictionDelegate { false } + fn icons(&self, _cx: &App) -> EditPredictionIconSet { + EditPredictionIconSet::new(IconName::Supermaven) + .with_disabled(IconName::SupermavenDisabled) + .with_error(IconName::SupermavenError) + } + fn is_enabled(&self, _buffer: &Entity, _cursor_position: Anchor, cx: &App) -> bool { self.supermaven.read(cx).is_enabled() }