pub mod copilot_chat;mod copilot_completion_provider;pub mod request;mod sign_in; use crate::sign_in::initiate_sign_in_within_workspace;use ::fs::Fs;use anyhow::{Context as _, Result, anyhow};use collections::{HashMap, HashSet};use command_palette_hooks::CommandPaletteFilter;use futures::{Future, FutureExt, TryFutureExt, channel::oneshot, future::Shared};use gpui::{ App, AppContext as _, AsyncApp, Context, Entity, EntityId, EventEmitter, Global, Task, WeakEntity, actions,};use http_client::HttpClient;use language::language_settings::CopilotSettings;use language::{ Anchor, Bias, Buffer, BufferSnapshot, Language, PointUtf16, ToPointUtf16, language_settings::{EditPredictionProvider, all_language_settings, language_settings}, point_from_lsp, point_to_lsp,};use lsp::{LanguageServer, LanguageServerBinary, LanguageServerId, LanguageServerName};use node_runtime::NodeRuntime;use parking_lot::Mutex;use request::StatusNotification;use serde_json::json;use settings::SettingsStore;use sign_in::{reinstall_and_sign_in_within_workspace, sign_out_within_workspace};use std::collections::hash_map::Entry;use std::{ any::TypeId, env, ffi::OsString, mem, ops::Range, path::{Path, PathBuf}, sync::Arc,};use util::{ResultExt, fs::remove_matching};use workspace::Workspace; pub use crate::copilot_completion_provider::CopilotCompletionProvider;pub use crate::sign_in::{CopilotCodeVerification, initiate_sign_in, reinstall_and_sign_in}; actions!( copilot, [ Suggest, NextSuggestion, PreviousSuggestion, Reinstall, SignIn, SignOut ]); pub fn init( new_server_id: LanguageServerId, fs: Arc<dyn Fs>, http: Arc<dyn HttpClient>, node_runtime: NodeRuntime, cx: &mut App,) { let language_settings = all_language_settings(None, cx); let configuration = copilot_chat::CopilotChatConfiguration { enterprise_uri: language_settings .edit_predictions .copilot .enterprise_uri .clone(), }; copilot_chat::init(fs.clone(), http.clone(), configuration, cx); let copilot = cx.new({ let node_runtime = node_runtime.clone(); move |cx| Copilot::start(new_server_id, fs, node_runtime, cx) }); Copilot::set_global(copilot.clone(), cx); cx.observe(&copilot, |handle, cx| { let copilot_action_types = [ TypeId::of::<Suggest>(), TypeId::of::<NextSuggestion>(), TypeId::of::<PreviousSuggestion>(), TypeId::of::<Reinstall>(), ]; let copilot_auth_action_types = [TypeId::of::<SignOut>()]; let copilot_no_auth_action_types = [TypeId::of::<SignIn>()]; let status = handle.read(cx).status(); let filter = CommandPaletteFilter::global_mut(cx); match status { Status::Disabled => { filter.hide_action_types(&copilot_action_types); filter.hide_action_types(&copilot_auth_action_types); filter.hide_action_types(&copilot_no_auth_action_types); } Status::Authorized => { filter.hide_action_types(&copilot_no_auth_action_types); filter.show_action_types( copilot_action_types .iter() .chain(&copilot_auth_action_types), ); } _ => { filter.hide_action_types(&copilot_action_types); filter.hide_action_types(&copilot_auth_action_types); filter.show_action_types(copilot_no_auth_action_types.iter()); } } }) .detach(); cx.observe_new(|workspace: &mut Workspace, _window, _cx| { workspace.register_action(|workspace, _: &SignIn, window, cx| { if let Some(copilot) = Copilot::global(cx) { let is_reinstall = false; initiate_sign_in_within_workspace(workspace, copilot, is_reinstall, window, cx); } }); workspace.register_action(|workspace, _: &Reinstall, window, cx| { if let Some(copilot) = Copilot::global(cx) { reinstall_and_sign_in_within_workspace(workspace, copilot, window, cx); } }); workspace.register_action(|workspace, _: &SignOut, _window, cx| { if let Some(copilot) = Copilot::global(cx) { sign_out_within_workspace(workspace, copilot, cx); } }); }) .detach();} enum CopilotServer { Disabled, Starting { task: Shared<Task<()>> }, Error(Arc<str>), Running(RunningCopilotServer),} impl CopilotServer { fn as_authenticated(&mut self) -> Result<&mut RunningCopilotServer> { let server = self.as_running()?; anyhow::ensure!( matches!(server.sign_in_status, SignInStatus::Authorized { .. }), "must sign in before using copilot" ); Ok(server) } fn as_running(&mut self) -> Result<&mut RunningCopilotServer> { match self { CopilotServer::Starting { .. } => anyhow::bail!("copilot is still starting"), CopilotServer::Disabled => anyhow::bail!("copilot is disabled"), CopilotServer::Error(error) => { anyhow::bail!("copilot was not started because of an error: {error}") } CopilotServer::Running(server) => Ok(server), } }} struct RunningCopilotServer { lsp: Arc<LanguageServer>, sign_in_status: SignInStatus, registered_buffers: HashMap<EntityId, RegisteredBuffer>,} #[derive(Clone, Debug)]enum SignInStatus { Authorized, Unauthorized, SigningIn { prompt: Option<request::PromptUserDeviceFlow>, task: Shared<Task<Result<(), Arc<anyhow::Error>>>>, }, SignedOut { awaiting_signing_in: bool, },} #[derive(Debug, Clone)]pub enum Status { Starting { task: Shared<Task<()>>, }, Error(Arc<str>), Disabled, SignedOut { awaiting_signing_in: bool, }, SigningIn { prompt: Option<request::PromptUserDeviceFlow>, }, Unauthorized, Authorized,} impl Status { pub fn is_authorized(&self) -> bool { matches!(self, Status::Authorized) } pub fn is_disabled(&self) -> bool { matches!(self, Status::Disabled) }} struct RegisteredBuffer { uri: lsp::Url, language_id: String, snapshot: BufferSnapshot, snapshot_version: i32, _subscriptions: [gpui::Subscription; 2], pending_buffer_change: Task<Option<()>>,} impl RegisteredBuffer { fn report_changes( &mut self, buffer: &Entity<Buffer>, cx: &mut Context<Copilot>, ) -> oneshot::Receiver<(i32, BufferSnapshot)> { let (done_tx, done_rx) = oneshot::channel(); if buffer.read(cx).version() == self.snapshot.version { let _ = done_tx.send((self.snapshot_version, self.snapshot.clone())); } else { let buffer = buffer.downgrade(); let id = buffer.entity_id(); let prev_pending_change = mem::replace(&mut self.pending_buffer_change, Task::ready(None)); self.pending_buffer_change = cx.spawn(async move |copilot, cx| { prev_pending_change.await; let old_version = copilot .update(cx, |copilot, _| { let server = copilot.server.as_authenticated().log_err()?; let buffer = server.registered_buffers.get_mut(&id)?; Some(buffer.snapshot.version.clone()) }) .ok()??; let new_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot()).ok()?; let content_changes = cx .background_spawn({ let new_snapshot = new_snapshot.clone(); async move { new_snapshot .edits_since::<(PointUtf16, usize)>(&old_version) .map(|edit| { let edit_start = edit.new.start.0; let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0); let new_text = new_snapshot .text_for_range(edit.new.start.1..edit.new.end.1) .collect(); lsp::TextDocumentContentChangeEvent { range: Some(lsp::Range::new( point_to_lsp(edit_start), point_to_lsp(edit_end), )), range_length: None, text: new_text, } }) .collect::<Vec<_>>() } }) .await; copilot .update(cx, |copilot, _| { let server = copilot.server.as_authenticated().log_err()?; let buffer = server.registered_buffers.get_mut(&id)?; if !content_changes.is_empty() { buffer.snapshot_version += 1; buffer.snapshot = new_snapshot; server .lsp .notify::<lsp::notification::DidChangeTextDocument>( &lsp::DidChangeTextDocumentParams { text_document: lsp::VersionedTextDocumentIdentifier::new( buffer.uri.clone(), buffer.snapshot_version, ), content_changes, }, ) .ok(); } let _ = done_tx.send((buffer.snapshot_version, buffer.snapshot.clone())); Some(()) }) .ok()?; Some(()) }); } done_rx }} #[derive(Debug)]pub struct Completion { pub uuid: String, pub range: Range<Anchor>, pub text: String,} pub struct Copilot { fs: Arc<dyn Fs>, node_runtime: NodeRuntime, server: CopilotServer, buffers: HashSet<WeakEntity<Buffer>>, server_id: LanguageServerId, _subscription: gpui::Subscription,} pub enum Event { CopilotLanguageServerStarted, CopilotAuthSignedIn, CopilotAuthSignedOut,} impl EventEmitter<Event> for Copilot {} struct GlobalCopilot(Entity<Copilot>); impl Global for GlobalCopilot {} impl Copilot { pub fn global(cx: &App) -> Option<Entity<Self>> { cx.try_global::<GlobalCopilot>() .map(|model| model.0.clone()) } pub fn set_global(copilot: Entity<Self>, cx: &mut App) { cx.set_global(GlobalCopilot(copilot)); } fn start( new_server_id: LanguageServerId, fs: Arc<dyn Fs>, node_runtime: NodeRuntime, cx: &mut Context<Self>, ) -> Self { let mut this = Self { server_id: new_server_id, fs, node_runtime, server: CopilotServer::Disabled, buffers: Default::default(), _subscription: cx.on_app_quit(Self::shutdown_language_server), }; this.start_copilot(true, false, cx); cx.observe_global::<SettingsStore>(move |this, cx| { this.start_copilot(true, false, cx); this.send_configuration_update(cx); }) .detach(); this } fn shutdown_language_server( &mut self, _cx: &mut Context<Self>, ) -> impl Future<Output = ()> + use<> { let shutdown = match mem::replace(&mut self.server, CopilotServer::Disabled) { CopilotServer::Running(server) => Some(Box::pin(async move { server.lsp.shutdown() })), _ => None, }; async move { if let Some(shutdown) = shutdown { shutdown.await; } } } fn start_copilot( &mut self, check_edit_prediction_provider: bool, awaiting_sign_in_after_start: bool, cx: &mut Context<Self>, ) { if !matches!(self.server, CopilotServer::Disabled) { return; } let language_settings = all_language_settings(None, cx); if check_edit_prediction_provider && language_settings.edit_predictions.provider != EditPredictionProvider::Copilot { return; } let server_id = self.server_id; let fs = self.fs.clone(); let node_runtime = self.node_runtime.clone(); let env = self.build_env(&language_settings.edit_predictions.copilot); let start_task = cx .spawn(async move |this, cx| { Self::start_language_server( server_id, fs, node_runtime, env, this, awaiting_sign_in_after_start, cx, ) .await }) .shared(); self.server = CopilotServer::Starting { task: start_task }; cx.notify(); } fn build_env(&self, copilot_settings: &CopilotSettings) -> Option<HashMap<String, String>> { let proxy_url = copilot_settings.proxy.clone()?; let no_verify = copilot_settings.proxy_no_verify; let http_or_https_proxy = if proxy_url.starts_with("http:") { Some("HTTP_PROXY") } else if proxy_url.starts_with("https:") { Some("HTTPS_PROXY") } else { log::error!( "Unsupported protocol scheme for language server proxy (must be http or https)" ); None }; let mut env = HashMap::default(); if let Some(proxy_type) = http_or_https_proxy { env.insert(proxy_type.to_string(), proxy_url); if let Some(true) = no_verify { env.insert("NODE_TLS_REJECT_UNAUTHORIZED".to_string(), "0".to_string()); }; } if let Ok(oauth_token) = env::var(copilot_chat::COPILOT_OAUTH_ENV_VAR) { env.insert(copilot_chat::COPILOT_OAUTH_ENV_VAR.to_string(), oauth_token); } if env.is_empty() { None } else { Some(env) } } fn send_configuration_update(&mut self, cx: &mut Context<Self>) { let copilot_settings = all_language_settings(None, cx) .edit_predictions .copilot .clone(); let settings = json!({ "http": { "proxy": copilot_settings.proxy, "proxyStrictSSL": !copilot_settings.proxy_no_verify.unwrap_or(false) }, "github-enterprise": { "uri": copilot_settings.enterprise_uri } }); if let Some(copilot_chat) = copilot_chat::CopilotChat::global(cx) { copilot_chat.update(cx, |chat, cx| { chat.set_configuration( copilot_chat::CopilotChatConfiguration { enterprise_uri: copilot_settings.enterprise_uri.clone(), }, cx, ); }); } if let Ok(server) = self.server.as_running() { server .lsp .notify::<lsp::notification::DidChangeConfiguration>( &lsp::DidChangeConfigurationParams { settings }, ) .log_err(); } } #[cfg(any(test, feature = "test-support"))] pub fn fake(cx: &mut gpui::TestAppContext) -> (Entity<Self>, lsp::FakeLanguageServer) { use fs::FakeFs; use lsp::FakeLanguageServer; use node_runtime::NodeRuntime; let (server, fake_server) = FakeLanguageServer::new( LanguageServerId(0), LanguageServerBinary { path: "path/to/copilot".into(), arguments: vec![], env: None, }, "copilot".into(),Lines 1–500 of 1390. Load more
pub mod copilot_chat; mod copilot_completion_provider; pub mod request; mod sign_in; use crate::sign_in::initiate_sign_in_within_workspace; use ::fs::Fs; use anyhow::{Context as _, Result, anyhow}; use collections::{HashMap, HashSet}; use command_palette_hooks::CommandPaletteFilter; use futures::{Future, FutureExt, TryFutureExt, channel::oneshot, future::Shared}; use gpui::{ App, AppContext as _, AsyncApp, Context, Entity, EntityId, EventEmitter, Global, Task, WeakEntity, actions, }; use http_client::HttpClient; use language::language_settings::CopilotSettings; use language::{ Anchor, Bias, Buffer, BufferSnapshot, Language, PointUtf16, ToPointUtf16, language_settings::{EditPredictionProvider, all_language_settings, language_settings}, point_from_lsp, point_to_lsp, }; use lsp::{LanguageServer, LanguageServerBinary, LanguageServerId, LanguageServerName}; use node_runtime::NodeRuntime; use parking_lot::Mutex; use request::StatusNotification; use serde_json::json; use settings::SettingsStore; use sign_in::{reinstall_and_sign_in_within_workspace, sign_out_within_workspace}; use std::collections::hash_map::Entry; use std::{ any::TypeId, env, ffi::OsString, mem, ops::Range, path::{Path, PathBuf}, sync::Arc, }; use util::{ResultExt, fs::remove_matching}; use workspace::Workspace; pub use crate::copilot_completion_provider::CopilotCompletionProvider; pub use crate::sign_in::{CopilotCodeVerification, initiate_sign_in, reinstall_and_sign_in}; actions!( copilot, [ Suggest, NextSuggestion, PreviousSuggestion, Reinstall, SignIn, SignOut ] ); pub fn init( new_server_id: LanguageServerId, fs: Arc<dyn Fs>, http: Arc<dyn HttpClient>, node_runtime: NodeRuntime, cx: &mut App, ) { let language_settings = all_language_settings(None, cx); let configuration = copilot_chat::CopilotChatConfiguration { enterprise_uri: language_settings .edit_predictions .copilot .enterprise_uri .clone(), }; copilot_chat::init(fs.clone(), http.clone(), configuration, cx); let copilot = cx.new({ let node_runtime = node_runtime.clone(); move |cx| Copilot::start(new_server_id, fs, node_runtime, cx) }); Copilot::set_global(copilot.clone(), cx); cx.observe(&copilot, |handle, cx| { let copilot_action_types = [ TypeId::of::<Suggest>(), TypeId::of::<NextSuggestion>(), TypeId::of::<PreviousSuggestion>(), TypeId::of::<Reinstall>(), ]; let copilot_auth_action_types = [TypeId::of::<SignOut>()]; let copilot_no_auth_action_types = [TypeId::of::<SignIn>()]; let status = handle.read(cx).status(); let filter = CommandPaletteFilter::global_mut(cx); match status { Status::Disabled => { filter.hide_action_types(&copilot_action_types); filter.hide_action_types(&copilot_auth_action_types); filter.hide_action_types(&copilot_no_auth_action_types); } Status::Authorized => { filter.hide_action_types(&copilot_no_auth_action_types); filter.show_action_types( copilot_action_types .iter() .chain(&copilot_auth_action_types), ); } _ => { filter.hide_action_types(&copilot_action_types); filter.hide_action_types(&copilot_auth_action_types); filter.show_action_types(copilot_no_auth_action_types.iter()); } } }) .detach(); cx.observe_new(|workspace: &mut Workspace, _window, _cx| { workspace.register_action(|workspace, _: &SignIn, window, cx| { if let Some(copilot) = Copilot::global(cx) { let is_reinstall = false; initiate_sign_in_within_workspace(workspace, copilot, is_reinstall, window, cx); } }); workspace.register_action(|workspace, _: &Reinstall, window, cx| { if let Some(copilot) = Copilot::global(cx) { reinstall_and_sign_in_within_workspace(workspace, copilot, window, cx); } }); workspace.register_action(|workspace, _: &SignOut, _window, cx| { if let Some(copilot) = Copilot::global(cx) { sign_out_within_workspace(workspace, copilot, cx); } }); }) .detach(); } enum CopilotServer { Disabled, Starting { task: Shared<Task<()>> }, Error(Arc<str>), Running(RunningCopilotServer), } impl CopilotServer { fn as_authenticated(&mut self) -> Result<&mut RunningCopilotServer> { let server = self.as_running()?; anyhow::ensure!( matches!(server.sign_in_status, SignInStatus::Authorized { .. }), "must sign in before using copilot" ); Ok(server) } fn as_running(&mut self) -> Result<&mut RunningCopilotServer> { match self { CopilotServer::Starting { .. } => anyhow::bail!("copilot is still starting"), CopilotServer::Disabled => anyhow::bail!("copilot is disabled"), CopilotServer::Error(error) => { anyhow::bail!("copilot was not started because of an error: {error}") } CopilotServer::Running(server) => Ok(server), } } } struct RunningCopilotServer { lsp: Arc<LanguageServer>, sign_in_status: SignInStatus, registered_buffers: HashMap<EntityId, RegisteredBuffer>, } #[derive(Clone, Debug)] enum SignInStatus { Authorized, Unauthorized, SigningIn { prompt: Option<request::PromptUserDeviceFlow>, task: Shared<Task<Result<(), Arc<anyhow::Error>>>>, }, SignedOut { awaiting_signing_in: bool, }, } #[derive(Debug, Clone)] pub enum Status { Starting { task: Shared<Task<()>>, }, Error(Arc<str>), Disabled, SignedOut { awaiting_signing_in: bool, }, SigningIn { prompt: Option<request::PromptUserDeviceFlow>, }, Unauthorized, Authorized, } impl Status { pub fn is_authorized(&self) -> bool { matches!(self, Status::Authorized) } pub fn is_disabled(&self) -> bool { matches!(self, Status::Disabled) } } struct RegisteredBuffer { uri: lsp::Url, language_id: String, snapshot: BufferSnapshot, snapshot_version: i32, _subscriptions: [gpui::Subscription; 2], pending_buffer_change: Task<Option<()>>, } impl RegisteredBuffer { fn report_changes( &mut self, buffer: &Entity<Buffer>, cx: &mut Context<Copilot>, ) -> oneshot::Receiver<(i32, BufferSnapshot)> { let (done_tx, done_rx) = oneshot::channel(); if buffer.read(cx).version() == self.snapshot.version { let _ = done_tx.send((self.snapshot_version, self.snapshot.clone())); } else { let buffer = buffer.downgrade(); let id = buffer.entity_id(); let prev_pending_change = mem::replace(&mut self.pending_buffer_change, Task::ready(None)); self.pending_buffer_change = cx.spawn(async move |copilot, cx| { prev_pending_change.await; let old_version = copilot .update(cx, |copilot, _| { let server = copilot.server.as_authenticated().log_err()?; let buffer = server.registered_buffers.get_mut(&id)?; Some(buffer.snapshot.version.clone()) }) .ok()??; let new_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot()).ok()?; let content_changes = cx .background_spawn({ let new_snapshot = new_snapshot.clone(); async move { new_snapshot .edits_since::<(PointUtf16, usize)>(&old_version) .map(|edit| { let edit_start = edit.new.start.0; let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0); let new_text = new_snapshot .text_for_range(edit.new.start.1..edit.new.end.1) .collect(); lsp::TextDocumentContentChangeEvent { range: Some(lsp::Range::new( point_to_lsp(edit_start), point_to_lsp(edit_end), )), range_length: None, text: new_text, } }) .collect::<Vec<_>>() } }) .await; copilot .update(cx, |copilot, _| { let server = copilot.server.as_authenticated().log_err()?; let buffer = server.registered_buffers.get_mut(&id)?; if !content_changes.is_empty() { buffer.snapshot_version += 1; buffer.snapshot = new_snapshot; server .lsp .notify::<lsp::notification::DidChangeTextDocument>( &lsp::DidChangeTextDocumentParams { text_document: lsp::VersionedTextDocumentIdentifier::new( buffer.uri.clone(), buffer.snapshot_version, ), content_changes, }, ) .ok(); } let _ = done_tx.send((buffer.snapshot_version, buffer.snapshot.clone())); Some(()) }) .ok()?; Some(()) }); } done_rx } } #[derive(Debug)] pub struct Completion { pub uuid: String, pub range: Range<Anchor>, pub text: String, } pub struct Copilot { fs: Arc<dyn Fs>, node_runtime: NodeRuntime, server: CopilotServer, buffers: HashSet<WeakEntity<Buffer>>, server_id: LanguageServerId, _subscription: gpui::Subscription, } pub enum Event { CopilotLanguageServerStarted, CopilotAuthSignedIn, CopilotAuthSignedOut, } impl EventEmitter<Event> for Copilot {} struct GlobalCopilot(Entity<Copilot>); impl Global for GlobalCopilot {} impl Copilot { pub fn global(cx: &App) -> Option<Entity<Self>> { cx.try_global::<GlobalCopilot>() .map(|model| model.0.clone()) } pub fn set_global(copilot: Entity<Self>, cx: &mut App) { cx.set_global(GlobalCopilot(copilot)); } fn start( new_server_id: LanguageServerId, fs: Arc<dyn Fs>, node_runtime: NodeRuntime, cx: &mut Context<Self>, ) -> Self { let mut this = Self { server_id: new_server_id, fs, node_runtime, server: CopilotServer::Disabled, buffers: Default::default(), _subscription: cx.on_app_quit(Self::shutdown_language_server), }; this.start_copilot(true, false, cx); cx.observe_global::<SettingsStore>(move |this, cx| { this.start_copilot(true, false, cx); this.send_configuration_update(cx); }) .detach(); this } fn shutdown_language_server( &mut self, _cx: &mut Context<Self>, ) -> impl Future<Output = ()> + use<> { let shutdown = match mem::replace(&mut self.server, CopilotServer::Disabled) { CopilotServer::Running(server) => Some(Box::pin(async move { server.lsp.shutdown() })), _ => None, }; async move { if let Some(shutdown) = shutdown { shutdown.await; } } } fn start_copilot( &mut self, check_edit_prediction_provider: bool, awaiting_sign_in_after_start: bool, cx: &mut Context<Self>, ) { if !matches!(self.server, CopilotServer::Disabled) { return; } let language_settings = all_language_settings(None, cx); if check_edit_prediction_provider && language_settings.edit_predictions.provider != EditPredictionProvider::Copilot { return; } let server_id = self.server_id; let fs = self.fs.clone(); let node_runtime = self.node_runtime.clone(); let env = self.build_env(&language_settings.edit_predictions.copilot); let start_task = cx .spawn(async move |this, cx| { Self::start_language_server( server_id, fs, node_runtime, env, this, awaiting_sign_in_after_start, cx, ) .await }) .shared(); self.server = CopilotServer::Starting { task: start_task }; cx.notify(); } fn build_env(&self, copilot_settings: &CopilotSettings) -> Option<HashMap<String, String>> { let proxy_url = copilot_settings.proxy.clone()?; let no_verify = copilot_settings.proxy_no_verify; let http_or_https_proxy = if proxy_url.starts_with("http:") { Some("HTTP_PROXY") } else if proxy_url.starts_with("https:") { Some("HTTPS_PROXY") } else { log::error!( "Unsupported protocol scheme for language server proxy (must be http or https)" ); None }; let mut env = HashMap::default(); if let Some(proxy_type) = http_or_https_proxy { env.insert(proxy_type.to_string(), proxy_url); if let Some(true) = no_verify { env.insert("NODE_TLS_REJECT_UNAUTHORIZED".to_string(), "0".to_string()); }; } if let Ok(oauth_token) = env::var(copilot_chat::COPILOT_OAUTH_ENV_VAR) { env.insert(copilot_chat::COPILOT_OAUTH_ENV_VAR.to_string(), oauth_token); } if env.is_empty() { None } else { Some(env) } } fn send_configuration_update(&mut self, cx: &mut Context<Self>) { let copilot_settings = all_language_settings(None, cx) .edit_predictions .copilot .clone(); let settings = json!({ "http": { "proxy": copilot_settings.proxy, "proxyStrictSSL": !copilot_settings.proxy_no_verify.unwrap_or(false) }, "github-enterprise": { "uri": copilot_settings.enterprise_uri } }); if let Some(copilot_chat) = copilot_chat::CopilotChat::global(cx) { copilot_chat.update(cx, |chat, cx| { chat.set_configuration( copilot_chat::CopilotChatConfiguration { enterprise_uri: copilot_settings.enterprise_uri.clone(), }, cx, ); }); } if let Ok(server) = self.server.as_running() { server .lsp .notify::<lsp::notification::DidChangeConfiguration>( &lsp::DidChangeConfigurationParams { settings }, ) .log_err(); } } #[cfg(any(test, feature = "test-support"))] pub fn fake(cx: &mut gpui::TestAppContext) -> (Entity<Self>, lsp::FakeLanguageServer) { use fs::FakeFs; use lsp::FakeLanguageServer; use node_runtime::NodeRuntime; let (server, fake_server) = FakeLanguageServer::new( LanguageServerId(0), LanguageServerBinary { path: "path/to/copilot".into(), arguments: vec![], env: None, }, "copilot".into(),