use crate::assistant_configuration::{ConfigurationView, ConfigurationViewEvent};use crate::{ terminal_inline_assistant::TerminalInlineAssistant, DeployHistory, InlineAssistant, NewChat,};use anyhow::{anyhow, Result};use assistant_context_editor::{ make_lsp_adapter_delegate, AssistantContext, AssistantPanelDelegate, ContextEditor, ContextEditorToolbarItem, ContextEditorToolbarItemEvent, ContextHistory, ContextId, ContextStore, ContextStoreEvent, InsertDraggedFiles, SlashCommandCompletionProvider, DEFAULT_TAB_TITLE,};use assistant_settings::{AssistantDockPosition, AssistantSettings};use assistant_slash_command::SlashCommandWorkingSet;use client::{proto, Client, Status};use editor::{Editor, EditorEvent};use fs::Fs;use gpui::{ prelude::*, Action, App, AsyncWindowContext, Entity, EventEmitter, ExternalPaths, FocusHandle, Focusable, InteractiveElement, IntoElement, ParentElement, Pixels, Render, Styled, Subscription, Task, UpdateGlobal, WeakEntity,};use language::LanguageRegistry;use language_model::{ AuthenticateError, LanguageModelProviderId, LanguageModelRegistry, ZED_CLOUD_PROVIDER_ID,};use project::Project;use prompt_library::{open_prompt_library, PromptBuilder, PromptLibrary};use search::{buffer_search::DivRegistrar, BufferSearchBar};use settings::{update_settings_file, Settings};use smol::stream::StreamExt;use std::{ops::ControlFlow, path::PathBuf, sync::Arc};use terminal_view::{terminal_panel::TerminalPanel, TerminalView};use ui::{prelude::*, ContextMenu, PopoverMenu, Tooltip};use util::{maybe, ResultExt};use workspace::DraggedTab;use workspace::{ dock::{DockPosition, Panel, PanelEvent}, pane, DraggedSelection, Pane, ShowConfiguration, ToggleZoom, Workspace,};use zed_actions::assistant::{DeployPromptLibrary, InlineAssist, ToggleFocus}; pub fn init(cx: &mut App) { workspace::FollowableViewRegistry::register::<ContextEditor>(cx); cx.observe_new( |workspace: &mut Workspace, _window, _cx: &mut Context<Workspace>| { workspace .register_action(ContextEditor::quote_selection) .register_action(ContextEditor::insert_selection) .register_action(ContextEditor::copy_code) .register_action(ContextEditor::insert_dragged_files) .register_action(AssistantPanel::show_configuration) .register_action(AssistantPanel::create_new_context) .register_action(AssistantPanel::restart_context_servers); }, ) .detach(); cx.observe_new( |terminal_panel: &mut TerminalPanel, _, cx: &mut Context<TerminalPanel>| { let settings = AssistantSettings::get_global(cx); terminal_panel.set_assistant_enabled(settings.enabled, cx); }, ) .detach();} pub enum AssistantPanelEvent { ContextEdited,} pub struct AssistantPanel { pane: Entity<Pane>, workspace: WeakEntity<Workspace>, width: Option<Pixels>, height: Option<Pixels>, project: Entity<Project>, context_store: Entity<ContextStore>, languages: Arc<LanguageRegistry>, fs: Arc<dyn Fs>, subscriptions: Vec<Subscription>, model_summary_editor: Entity<Editor>, authenticate_provider_task: Option<(LanguageModelProviderId, Task<()>)>, configuration_subscription: Option<Subscription>, client_status: Option<client::Status>, watch_client_status: Option<Task<()>>, pub(crate) show_zed_ai_notice: bool,} enum InlineAssistTarget { Editor(Entity<Editor>, bool), Terminal(Entity<TerminalView>),} impl AssistantPanel { pub fn load( workspace: WeakEntity<Workspace>, prompt_builder: Arc<PromptBuilder>, cx: AsyncWindowContext, ) -> Task<Result<Entity<Self>>> { cx.spawn(|mut cx| async move { let slash_commands = Arc::new(SlashCommandWorkingSet::default()); let context_store = workspace .update(&mut cx, |workspace, cx| { let project = workspace.project().clone(); ContextStore::new(project, prompt_builder.clone(), slash_commands, cx) })? .await?; workspace.update_in(&mut cx, |workspace, window, cx| { // TODO: deserialize state. cx.new(|cx| Self::new(workspace, context_store, window, cx)) }) }) } fn new( workspace: &Workspace, context_store: Entity<ContextStore>, window: &mut Window, cx: &mut Context<Self>, ) -> Self { let model_summary_editor = cx.new(|cx| Editor::single_line(window, cx)); let context_editor_toolbar = cx.new(|_| ContextEditorToolbarItem::new(model_summary_editor.clone())); let pane = cx.new(|cx| { let mut pane = Pane::new( workspace.weak_handle(), workspace.project().clone(), Default::default(), None, NewChat.boxed_clone(), window, cx, ); let project = workspace.project().clone(); pane.set_custom_drop_handle(cx, move |_, dropped_item, window, cx| { let action = maybe!({ if project.read(cx).is_local() { if let Some(paths) = dropped_item.downcast_ref::<ExternalPaths>() { return Some(InsertDraggedFiles::ExternalFiles(paths.paths().to_vec())); } } let project_paths = if let Some(tab) = dropped_item.downcast_ref::<DraggedTab>() { if tab.pane == cx.entity() { return None; } let item = tab.pane.read(cx).item_for_index(tab.ix); Some( item.and_then(|item| item.project_path(cx)) .into_iter() .collect::<Vec<_>>(), ) } else if let Some(selection) = dropped_item.downcast_ref::<DraggedSelection>() { Some( selection .items() .filter_map(|item| { project.read(cx).path_for_entry(item.entry_id, cx) }) .collect::<Vec<_>>(), ) } else { None }?; let paths = project_paths .into_iter() .filter_map(|project_path| { let worktree = project .read(cx) .worktree_for_id(project_path.worktree_id, cx)?; let mut full_path = PathBuf::from(worktree.read(cx).root_name()); full_path.push(&project_path.path); Some(full_path) }) .collect::<Vec<_>>(); Some(InsertDraggedFiles::ProjectPaths(paths)) }); if let Some(action) = action { window.dispatch_action(action.boxed_clone(), cx); } ControlFlow::Break(()) }); pane.set_can_navigate(true, cx); pane.display_nav_history_buttons(None); pane.set_should_display_tab_bar(|_, _| true); pane.set_render_tab_bar_buttons(cx, move |pane, _window, cx| { let focus_handle = pane.focus_handle(cx); let left_children = IconButton::new("history", IconName::HistoryRerun) .icon_size(IconSize::Small) .on_click(cx.listener({ let focus_handle = focus_handle.clone(); move |_, _, window, cx| { focus_handle.focus(window); window.dispatch_action(DeployHistory.boxed_clone(), cx) } })) .tooltip({ let focus_handle = focus_handle.clone(); move |window, cx| { Tooltip::for_action_in( "Open History", &DeployHistory, &focus_handle, window, cx, ) } }) .toggle_state( pane.active_item() .map_or(false, |item| item.downcast::<ContextHistory>().is_some()), ); let _pane = cx.entity().clone(); let right_children = h_flex() .gap(DynamicSpacing::Base02.rems(cx)) .child( IconButton::new("new-chat", IconName::Plus) .icon_size(IconSize::Small) .on_click(cx.listener(|_, _, window, cx| { window.dispatch_action(NewChat.boxed_clone(), cx) })) .tooltip(move |window, cx| { Tooltip::for_action_in( "New Chat", &NewChat, &focus_handle, window, cx, ) }), ) .child( PopoverMenu::new("assistant-panel-popover-menu") .trigger_with_tooltip( IconButton::new("menu", IconName::EllipsisVertical) .icon_size(IconSize::Small), Tooltip::text("Toggle Assistant Menu"), ) .menu(move |window, cx| { let zoom_label = if _pane.read(cx).is_zoomed() { "Zoom Out" } else { "Zoom In" }; let focus_handle = _pane.focus_handle(cx); Some(ContextMenu::build(window, cx, move |menu, _, _| { menu.context(focus_handle.clone()) .action("New Chat", Box::new(NewChat)) .action("History", Box::new(DeployHistory)) .action("Prompt Library", Box::new(DeployPromptLibrary)) .action("Configure", Box::new(ShowConfiguration)) .action(zoom_label, Box::new(ToggleZoom)) })) }), ) .into_any_element() .into(); (Some(left_children.into_any_element()), right_children) }); pane.toolbar().update(cx, |toolbar, cx| { toolbar.add_item(context_editor_toolbar.clone(), window, cx); toolbar.add_item( cx.new(|cx| { BufferSearchBar::new( Some(workspace.project().read(cx).languages().clone()), window, cx, ) }), window, cx, ) }); pane }); let subscriptions = vec![ cx.observe(&pane, |_, _, cx| cx.notify()), cx.subscribe_in(&pane, window, Self::handle_pane_event), cx.subscribe(&context_editor_toolbar, Self::handle_toolbar_event), cx.subscribe(&model_summary_editor, Self::handle_summary_editor_event), cx.subscribe_in(&context_store, window, Self::handle_context_store_event), cx.subscribe_in( &LanguageModelRegistry::global(cx), window, |this, _, event: &language_model::Event, window, cx| match event { language_model::Event::ActiveModelChanged => { this.completion_provider_changed(window, cx); } language_model::Event::ProviderStateChanged => { this.ensure_authenticated(window, cx); cx.notify() } language_model::Event::AddedProvider(_) | language_model::Event::RemovedProvider(_) => { this.ensure_authenticated(window, cx); } }, ), ]; let watch_client_status = Self::watch_client_status(workspace.client().clone(), window, cx); let mut this = Self { pane, workspace: workspace.weak_handle(), width: None, height: None, project: workspace.project().clone(), context_store, languages: workspace.app_state().languages.clone(), fs: workspace.app_state().fs.clone(), subscriptions, model_summary_editor, authenticate_provider_task: None, configuration_subscription: None, client_status: None, watch_client_status: Some(watch_client_status), show_zed_ai_notice: false, }; this.new_context(window, cx); this } pub fn toggle_focus( workspace: &mut Workspace, _: &ToggleFocus, window: &mut Window, cx: &mut Context<Workspace>, ) { let settings = AssistantSettings::get_global(cx); if !settings.enabled { return; } workspace.toggle_panel_focus::<Self>(window, cx); } fn watch_client_status( client: Arc<Client>, window: &mut Window, cx: &mut Context<Self>, ) -> Task<()> { let mut status_rx = client.status(); cx.spawn_in(window, |this, mut cx| async move { while let Some(status) = status_rx.next().await { this.update(&mut cx, |this, cx| { if this.client_status.is_none() || this .client_status .map_or(false, |old_status| old_status != status) { this.update_zed_ai_notice_visibility(status, cx); } this.client_status = Some(status); }) .log_err(); } this.update(&mut cx, |this, _cx| this.watch_client_status = None) .log_err(); }) } fn handle_pane_event( &mut self, pane: &Entity<Pane>, event: &pane::Event, window: &mut Window, cx: &mut Context<Self>, ) { let update_model_summary = match event { pane::Event::Remove { .. } => { cx.emit(PanelEvent::Close); false } pane::Event::ZoomIn => { cx.emit(PanelEvent::ZoomIn); false } pane::Event::ZoomOut => { cx.emit(PanelEvent::ZoomOut); false } pane::Event::AddItem { item } => { self.workspace .update(cx, |workspace, cx| { item.added_to_pane(workspace, self.pane.clone(), window, cx) }) .ok(); true } pane::Event::ActivateItem { local, .. } => { if *local { self.workspace .update(cx, |workspace, cx| { workspace.unfollow_in_pane(&pane, window, cx); }) .ok(); } cx.emit(AssistantPanelEvent::ContextEdited); true } pane::Event::RemovedItem { .. } => { let has_configuration_view = self .pane .read(cx) .items_of_type::<ConfigurationView>() .next() .is_some(); if !has_configuration_view { self.configuration_subscription = None; } cx.emit(AssistantPanelEvent::ContextEdited); true } _ => false, }; if update_model_summary { if let Some(editor) = self.active_context_editor(cx) { self.show_updated_summary(&editor, window, cx) } } } fn handle_summary_editor_event( &mut self, model_summary_editor: Entity<Editor>, event: &EditorEvent, cx: &mut Context<Self>, ) { if matches!(event, EditorEvent::Edited { .. }) { if let Some(context_editor) = self.active_context_editor(cx) { let new_summary = model_summary_editor.read(cx).text(cx); context_editor.update(cx, |context_editor, cx| { context_editor.context().update(cx, |context, cx| { if context.summary().is_none() && (new_summary == DEFAULT_TAB_TITLE || new_summary.trim().is_empty()) { return; } context.custom_summary(new_summary, cx) }); }); } } } fn update_zed_ai_notice_visibility(&mut self, client_status: Status, cx: &mut Context<Self>) { let active_provider = LanguageModelRegistry::read_global(cx).active_provider(); // If we're signed out and don't have a provider configured, or we're signed-out AND Zed.dev is // the provider, we want to show a nudge to sign in. let show_zed_ai_notice = client_status.is_signed_out() && active_provider.map_or(true, |provider| provider.id().0 == ZED_CLOUD_PROVIDER_ID); self.show_zed_ai_notice = show_zed_ai_notice; cx.notify(); } fn handle_toolbar_event( &mut self, _: Entity<ContextEditorToolbarItem>, _: &ContextEditorToolbarItemEvent, cx: &mut Context<Self>, ) { if let Some(context_editor) = self.active_context_editor(cx) { context_editor.update(cx, |context_editor, cx| { context_editor.context().update(cx, |context, cx| { context.summarize(true, cx); }) }) } } fn handle_context_store_event( &mut self, _context_store: &Entity<ContextStore>, event: &ContextStoreEvent, window: &mut Window, cx: &mut Context<Self>, ) {Lines 1–500 of 1435. Load more
use crate::assistant_configuration::{ConfigurationView, ConfigurationViewEvent}; use crate::{ terminal_inline_assistant::TerminalInlineAssistant, DeployHistory, InlineAssistant, NewChat, }; use anyhow::{anyhow, Result}; use assistant_context_editor::{ make_lsp_adapter_delegate, AssistantContext, AssistantPanelDelegate, ContextEditor, ContextEditorToolbarItem, ContextEditorToolbarItemEvent, ContextHistory, ContextId, ContextStore, ContextStoreEvent, InsertDraggedFiles, SlashCommandCompletionProvider, DEFAULT_TAB_TITLE, }; use assistant_settings::{AssistantDockPosition, AssistantSettings}; use assistant_slash_command::SlashCommandWorkingSet; use client::{proto, Client, Status}; use editor::{Editor, EditorEvent}; use fs::Fs; use gpui::{ prelude::*, Action, App, AsyncWindowContext, Entity, EventEmitter, ExternalPaths, FocusHandle, Focusable, InteractiveElement, IntoElement, ParentElement, Pixels, Render, Styled, Subscription, Task, UpdateGlobal, WeakEntity, }; use language::LanguageRegistry; use language_model::{ AuthenticateError, LanguageModelProviderId, LanguageModelRegistry, ZED_CLOUD_PROVIDER_ID, }; use project::Project; use prompt_library::{open_prompt_library, PromptBuilder, PromptLibrary}; use search::{buffer_search::DivRegistrar, BufferSearchBar}; use settings::{update_settings_file, Settings}; use smol::stream::StreamExt; use std::{ops::ControlFlow, path::PathBuf, sync::Arc}; use terminal_view::{terminal_panel::TerminalPanel, TerminalView}; use ui::{prelude::*, ContextMenu, PopoverMenu, Tooltip}; use util::{maybe, ResultExt}; use workspace::DraggedTab; use workspace::{ dock::{DockPosition, Panel, PanelEvent}, pane, DraggedSelection, Pane, ShowConfiguration, ToggleZoom, Workspace, }; use zed_actions::assistant::{DeployPromptLibrary, InlineAssist, ToggleFocus}; pub fn init(cx: &mut App) { workspace::FollowableViewRegistry::register::<ContextEditor>(cx); cx.observe_new( |workspace: &mut Workspace, _window, _cx: &mut Context<Workspace>| { workspace .register_action(ContextEditor::quote_selection) .register_action(ContextEditor::insert_selection) .register_action(ContextEditor::copy_code) .register_action(ContextEditor::insert_dragged_files) .register_action(AssistantPanel::show_configuration) .register_action(AssistantPanel::create_new_context) .register_action(AssistantPanel::restart_context_servers); }, ) .detach(); cx.observe_new( |terminal_panel: &mut TerminalPanel, _, cx: &mut Context<TerminalPanel>| { let settings = AssistantSettings::get_global(cx); terminal_panel.set_assistant_enabled(settings.enabled, cx); }, ) .detach(); } pub enum AssistantPanelEvent { ContextEdited, } pub struct AssistantPanel { pane: Entity<Pane>, workspace: WeakEntity<Workspace>, width: Option<Pixels>, height: Option<Pixels>, project: Entity<Project>, context_store: Entity<ContextStore>, languages: Arc<LanguageRegistry>, fs: Arc<dyn Fs>, subscriptions: Vec<Subscription>, model_summary_editor: Entity<Editor>, authenticate_provider_task: Option<(LanguageModelProviderId, Task<()>)>, configuration_subscription: Option<Subscription>, client_status: Option<client::Status>, watch_client_status: Option<Task<()>>, pub(crate) show_zed_ai_notice: bool, } enum InlineAssistTarget { Editor(Entity<Editor>, bool), Terminal(Entity<TerminalView>), } impl AssistantPanel { pub fn load( workspace: WeakEntity<Workspace>, prompt_builder: Arc<PromptBuilder>, cx: AsyncWindowContext, ) -> Task<Result<Entity<Self>>> { cx.spawn(|mut cx| async move { let slash_commands = Arc::new(SlashCommandWorkingSet::default()); let context_store = workspace .update(&mut cx, |workspace, cx| { let project = workspace.project().clone(); ContextStore::new(project, prompt_builder.clone(), slash_commands, cx) })? .await?; workspace.update_in(&mut cx, |workspace, window, cx| { // TODO: deserialize state. cx.new(|cx| Self::new(workspace, context_store, window, cx)) }) }) } fn new( workspace: &Workspace, context_store: Entity<ContextStore>, window: &mut Window, cx: &mut Context<Self>, ) -> Self { let model_summary_editor = cx.new(|cx| Editor::single_line(window, cx)); let context_editor_toolbar = cx.new(|_| ContextEditorToolbarItem::new(model_summary_editor.clone())); let pane = cx.new(|cx| { let mut pane = Pane::new( workspace.weak_handle(), workspace.project().clone(), Default::default(), None, NewChat.boxed_clone(), window, cx, ); let project = workspace.project().clone(); pane.set_custom_drop_handle(cx, move |_, dropped_item, window, cx| { let action = maybe!({ if project.read(cx).is_local() { if let Some(paths) = dropped_item.downcast_ref::<ExternalPaths>() { return Some(InsertDraggedFiles::ExternalFiles(paths.paths().to_vec())); } } let project_paths = if let Some(tab) = dropped_item.downcast_ref::<DraggedTab>() { if tab.pane == cx.entity() { return None; } let item = tab.pane.read(cx).item_for_index(tab.ix); Some( item.and_then(|item| item.project_path(cx)) .into_iter() .collect::<Vec<_>>(), ) } else if let Some(selection) = dropped_item.downcast_ref::<DraggedSelection>() { Some( selection .items() .filter_map(|item| { project.read(cx).path_for_entry(item.entry_id, cx) }) .collect::<Vec<_>>(), ) } else { None }?; let paths = project_paths .into_iter() .filter_map(|project_path| { let worktree = project .read(cx) .worktree_for_id(project_path.worktree_id, cx)?; let mut full_path = PathBuf::from(worktree.read(cx).root_name()); full_path.push(&project_path.path); Some(full_path) }) .collect::<Vec<_>>(); Some(InsertDraggedFiles::ProjectPaths(paths)) }); if let Some(action) = action { window.dispatch_action(action.boxed_clone(), cx); } ControlFlow::Break(()) }); pane.set_can_navigate(true, cx); pane.display_nav_history_buttons(None); pane.set_should_display_tab_bar(|_, _| true); pane.set_render_tab_bar_buttons(cx, move |pane, _window, cx| { let focus_handle = pane.focus_handle(cx); let left_children = IconButton::new("history", IconName::HistoryRerun) .icon_size(IconSize::Small) .on_click(cx.listener({ let focus_handle = focus_handle.clone(); move |_, _, window, cx| { focus_handle.focus(window); window.dispatch_action(DeployHistory.boxed_clone(), cx) } })) .tooltip({ let focus_handle = focus_handle.clone(); move |window, cx| { Tooltip::for_action_in( "Open History", &DeployHistory, &focus_handle, window, cx, ) } }) .toggle_state( pane.active_item() .map_or(false, |item| item.downcast::<ContextHistory>().is_some()), ); let _pane = cx.entity().clone(); let right_children = h_flex() .gap(DynamicSpacing::Base02.rems(cx)) .child( IconButton::new("new-chat", IconName::Plus) .icon_size(IconSize::Small) .on_click(cx.listener(|_, _, window, cx| { window.dispatch_action(NewChat.boxed_clone(), cx) })) .tooltip(move |window, cx| { Tooltip::for_action_in( "New Chat", &NewChat, &focus_handle, window, cx, ) }), ) .child( PopoverMenu::new("assistant-panel-popover-menu") .trigger_with_tooltip( IconButton::new("menu", IconName::EllipsisVertical) .icon_size(IconSize::Small), Tooltip::text("Toggle Assistant Menu"), ) .menu(move |window, cx| { let zoom_label = if _pane.read(cx).is_zoomed() { "Zoom Out" } else { "Zoom In" }; let focus_handle = _pane.focus_handle(cx); Some(ContextMenu::build(window, cx, move |menu, _, _| { menu.context(focus_handle.clone()) .action("New Chat", Box::new(NewChat)) .action("History", Box::new(DeployHistory)) .action("Prompt Library", Box::new(DeployPromptLibrary)) .action("Configure", Box::new(ShowConfiguration)) .action(zoom_label, Box::new(ToggleZoom)) })) }), ) .into_any_element() .into(); (Some(left_children.into_any_element()), right_children) }); pane.toolbar().update(cx, |toolbar, cx| { toolbar.add_item(context_editor_toolbar.clone(), window, cx); toolbar.add_item( cx.new(|cx| { BufferSearchBar::new( Some(workspace.project().read(cx).languages().clone()), window, cx, ) }), window, cx, ) }); pane }); let subscriptions = vec![ cx.observe(&pane, |_, _, cx| cx.notify()), cx.subscribe_in(&pane, window, Self::handle_pane_event), cx.subscribe(&context_editor_toolbar, Self::handle_toolbar_event), cx.subscribe(&model_summary_editor, Self::handle_summary_editor_event), cx.subscribe_in(&context_store, window, Self::handle_context_store_event), cx.subscribe_in( &LanguageModelRegistry::global(cx), window, |this, _, event: &language_model::Event, window, cx| match event { language_model::Event::ActiveModelChanged => { this.completion_provider_changed(window, cx); } language_model::Event::ProviderStateChanged => { this.ensure_authenticated(window, cx); cx.notify() } language_model::Event::AddedProvider(_) | language_model::Event::RemovedProvider(_) => { this.ensure_authenticated(window, cx); } }, ), ]; let watch_client_status = Self::watch_client_status(workspace.client().clone(), window, cx); let mut this = Self { pane, workspace: workspace.weak_handle(), width: None, height: None, project: workspace.project().clone(), context_store, languages: workspace.app_state().languages.clone(), fs: workspace.app_state().fs.clone(), subscriptions, model_summary_editor, authenticate_provider_task: None, configuration_subscription: None, client_status: None, watch_client_status: Some(watch_client_status), show_zed_ai_notice: false, }; this.new_context(window, cx); this } pub fn toggle_focus( workspace: &mut Workspace, _: &ToggleFocus, window: &mut Window, cx: &mut Context<Workspace>, ) { let settings = AssistantSettings::get_global(cx); if !settings.enabled { return; } workspace.toggle_panel_focus::<Self>(window, cx); } fn watch_client_status( client: Arc<Client>, window: &mut Window, cx: &mut Context<Self>, ) -> Task<()> { let mut status_rx = client.status(); cx.spawn_in(window, |this, mut cx| async move { while let Some(status) = status_rx.next().await { this.update(&mut cx, |this, cx| { if this.client_status.is_none() || this .client_status .map_or(false, |old_status| old_status != status) { this.update_zed_ai_notice_visibility(status, cx); } this.client_status = Some(status); }) .log_err(); } this.update(&mut cx, |this, _cx| this.watch_client_status = None) .log_err(); }) } fn handle_pane_event( &mut self, pane: &Entity<Pane>, event: &pane::Event, window: &mut Window, cx: &mut Context<Self>, ) { let update_model_summary = match event { pane::Event::Remove { .. } => { cx.emit(PanelEvent::Close); false } pane::Event::ZoomIn => { cx.emit(PanelEvent::ZoomIn); false } pane::Event::ZoomOut => { cx.emit(PanelEvent::ZoomOut); false } pane::Event::AddItem { item } => { self.workspace .update(cx, |workspace, cx| { item.added_to_pane(workspace, self.pane.clone(), window, cx) }) .ok(); true } pane::Event::ActivateItem { local, .. } => { if *local { self.workspace .update(cx, |workspace, cx| { workspace.unfollow_in_pane(&pane, window, cx); }) .ok(); } cx.emit(AssistantPanelEvent::ContextEdited); true } pane::Event::RemovedItem { .. } => { let has_configuration_view = self .pane .read(cx) .items_of_type::<ConfigurationView>() .next() .is_some(); if !has_configuration_view { self.configuration_subscription = None; } cx.emit(AssistantPanelEvent::ContextEdited); true } _ => false, }; if update_model_summary { if let Some(editor) = self.active_context_editor(cx) { self.show_updated_summary(&editor, window, cx) } } } fn handle_summary_editor_event( &mut self, model_summary_editor: Entity<Editor>, event: &EditorEvent, cx: &mut Context<Self>, ) { if matches!(event, EditorEvent::Edited { .. }) { if let Some(context_editor) = self.active_context_editor(cx) { let new_summary = model_summary_editor.read(cx).text(cx); context_editor.update(cx, |context_editor, cx| { context_editor.context().update(cx, |context, cx| { if context.summary().is_none() && (new_summary == DEFAULT_TAB_TITLE || new_summary.trim().is_empty()) { return; } context.custom_summary(new_summary, cx) }); }); } } } fn update_zed_ai_notice_visibility(&mut self, client_status: Status, cx: &mut Context<Self>) { let active_provider = LanguageModelRegistry::read_global(cx).active_provider(); // If we're signed out and don't have a provider configured, or we're signed-out AND Zed.dev is // the provider, we want to show a nudge to sign in. let show_zed_ai_notice = client_status.is_signed_out() && active_provider.map_or(true, |provider| provider.id().0 == ZED_CLOUD_PROVIDER_ID); self.show_zed_ai_notice = show_zed_ai_notice; cx.notify(); } fn handle_toolbar_event( &mut self, _: Entity<ContextEditorToolbarItem>, _: &ContextEditorToolbarItemEvent, cx: &mut Context<Self>, ) { if let Some(context_editor) = self.active_context_editor(cx) { context_editor.update(cx, |context_editor, cx| { context_editor.context().update(cx, |context, cx| { context.summarize(true, cx); }) }) } } fn handle_context_store_event( &mut self, _context_store: &Entity<ContextStore>, event: &ContextStoreEvent, window: &mut Window, cx: &mut Context<Self>, ) {