context_server_configuration.rs

  1use std::sync::Arc;
  2
  3use context_server::ContextServerId;
  4use extension::ExtensionManifest;
  5use fs::Fs;
  6use gpui::WeakEntity;
  7use language::LanguageRegistry;
  8use project::project_settings::ProjectSettings;
  9use settings::update_settings_file;
 10use ui::prelude::*;
 11use util::ResultExt;
 12use workspace::Workspace;
 13
 14use crate::agent_configuration::ConfigureContextServerModal;
 15
 16pub(crate) fn init(language_registry: Arc<LanguageRegistry>, fs: Arc<dyn Fs>, cx: &mut App) {
 17    cx.observe_new(move |_: &mut Workspace, window, cx| {
 18        let Some(window) = window else {
 19            return;
 20        };
 21
 22        if let Some(extension_events) = extension::ExtensionEvents::try_global(cx).as_ref() {
 23            cx.subscribe_in(extension_events, window, {
 24                let language_registry = language_registry.clone();
 25                let fs = fs.clone();
 26                move |_, _, event, window, cx| match event {
 27                    extension::Event::ExtensionInstalled(manifest) => {
 28                        show_configure_mcp_modal(
 29                            language_registry.clone(),
 30                            manifest,
 31                            cx.weak_entity(),
 32                            window,
 33                            cx,
 34                        );
 35                    }
 36                    extension::Event::ExtensionUninstalled(manifest) => {
 37                        remove_context_server_settings(
 38                            manifest.context_servers.keys().cloned().collect(),
 39                            fs.clone(),
 40                            cx,
 41                        );
 42                    }
 43                    extension::Event::ConfigureExtensionRequested(manifest) => {
 44                        if !manifest.context_servers.is_empty() {
 45                            show_configure_mcp_modal(
 46                                language_registry.clone(),
 47                                manifest,
 48                                cx.weak_entity(),
 49                                window,
 50                                cx,
 51                            );
 52                        }
 53                    }
 54                    _ => {}
 55                }
 56            })
 57            .detach();
 58        } else {
 59            log::info!(
 60                "No extension events global found. Skipping context server configuration wizard"
 61            );
 62        }
 63    })
 64    .detach();
 65}
 66
 67fn remove_context_server_settings(
 68    context_server_ids: Vec<Arc<str>>,
 69    fs: Arc<dyn Fs>,
 70    cx: &mut App,
 71) {
 72    update_settings_file::<ProjectSettings>(fs, cx, move |settings, _| {
 73        settings
 74            .context_servers
 75            .retain(|server_id, _| !context_server_ids.contains(server_id));
 76    });
 77}
 78
 79fn show_configure_mcp_modal(
 80    language_registry: Arc<LanguageRegistry>,
 81    manifest: &Arc<ExtensionManifest>,
 82    workspace: WeakEntity<Workspace>,
 83    window: &mut Window,
 84    cx: &mut Context<'_, Workspace>,
 85) {
 86    if !window.is_window_active() {
 87        return;
 88    }
 89
 90    let ids = manifest.context_servers.keys().cloned().collect::<Vec<_>>();
 91    if ids.is_empty() {
 92        return;
 93    }
 94
 95    window
 96        .spawn(cx, async move |cx| {
 97            for id in ids {
 98                let Some(task) = cx
 99                    .update(|window, cx| {
100                        ConfigureContextServerModal::show_modal_for_existing_server(
101                            ContextServerId(id.clone()),
102                            language_registry.clone(),
103                            workspace.clone(),
104                            window,
105                            cx,
106                        )
107                    })
108                    .ok()
109                else {
110                    continue;
111                };
112                task.await.log_err();
113            }
114        })
115        .detach();
116}