Detailed changes
@@ -3112,7 +3112,9 @@ dependencies = [
"clock",
"collections",
"command_palette_hooks",
+ "ctor",
"editor",
+ "env_logger 0.11.6",
"fs",
"futures 0.3.31",
"gpui",
@@ -3120,6 +3122,7 @@ dependencies = [
"indoc",
"inline_completion",
"language",
+ "log",
"lsp",
"menu",
"node_runtime",
@@ -38,6 +38,7 @@ gpui.workspace = true
http_client.workspace = true
inline_completion.workspace = true
language.workspace = true
+log.workspace = true
lsp.workspace = true
menu.workspace = true
node_runtime.workspace = true
@@ -62,7 +63,9 @@ async-std = { version = "1.12.0", features = ["unstable"] }
client = { workspace = true, features = ["test-support"] }
clock = { workspace = true, features = ["test-support"] }
collections = { workspace = true, features = ["test-support"] }
+ctor.workspace = true
editor = { workspace = true, features = ["test-support"] }
+env_logger.workspace = true
fs = { workspace = true, features = ["test-support"] }
gpui = { workspace = true, features = ["test-support"] }
http_client = { workspace = true, features = ["test-support"] }
@@ -16,6 +16,7 @@ use gpui::{
};
use http_client::github::get_release_by_tag_name;
use http_client::HttpClient;
+use language::language_settings::CopilotSettings;
use language::{
language_settings::{all_language_settings, language_settings, EditPredictionProvider},
point_from_lsp, point_to_lsp, Anchor, Bias, Buffer, BufferSnapshot, Language, PointUtf16,
@@ -367,13 +368,13 @@ impl Copilot {
let server_id = self.server_id;
let http = self.http.clone();
let node_runtime = self.node_runtime.clone();
- if all_language_settings(None, cx).edit_predictions.provider
- == EditPredictionProvider::Copilot
- {
+ let language_settings = all_language_settings(None, cx);
+ if language_settings.edit_predictions.provider == EditPredictionProvider::Copilot {
if matches!(self.server, CopilotServer::Disabled) {
+ let env = self.build_env(&language_settings.edit_predictions.copilot);
let start_task = cx
.spawn(move |this, cx| {
- Self::start_language_server(server_id, http, node_runtime, this, cx)
+ Self::start_language_server(server_id, http, node_runtime, env, this, cx)
})
.shared();
self.server = CopilotServer::Starting { task: start_task };
@@ -385,6 +386,30 @@ impl Copilot {
}
}
+ 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:") {
+ "HTTP_PROXY"
+ } else if proxy_url.starts_with("https:") {
+ "HTTPS_PROXY"
+ } else {
+ log::error!(
+ "Unsupported protocol scheme for language server proxy (must be http or https)"
+ );
+ return None;
+ };
+
+ let mut env = HashMap::default();
+ env.insert(http_or_https_proxy.to_string(), proxy_url);
+
+ if let Some(true) = no_verify {
+ env.insert("NODE_TLS_REJECT_UNAUTHORIZED".to_string(), "0".to_string());
+ };
+
+ Some(env)
+ }
+
#[cfg(any(test, feature = "test-support"))]
pub fn fake(cx: &mut gpui::TestAppContext) -> (Entity<Self>, lsp::FakeLanguageServer) {
use lsp::FakeLanguageServer;
@@ -422,6 +447,7 @@ impl Copilot {
new_server_id: LanguageServerId,
http: Arc<dyn HttpClient>,
node_runtime: NodeRuntime,
+ env: Option<HashMap<String, String>>,
this: WeakEntity<Self>,
mut cx: AsyncApp,
) {
@@ -432,8 +458,7 @@ impl Copilot {
let binary = LanguageServerBinary {
path: node_path,
arguments,
- // TODO: We could set HTTP_PROXY etc here and fix the copilot issue.
- env: None,
+ env,
};
let root_path = if cfg!(target_os = "windows") {
@@ -611,6 +636,8 @@ impl Copilot {
}
pub fn reinstall(&mut self, cx: &mut Context<Self>) -> Task<()> {
+ let language_settings = all_language_settings(None, cx);
+ let env = self.build_env(&language_settings.edit_predictions.copilot);
let start_task = cx
.spawn({
let http = self.http.clone();
@@ -618,7 +645,7 @@ impl Copilot {
let server_id = self.server_id;
move |this, cx| async move {
clear_copilot_dir().await;
- Self::start_language_server(server_id, http, node_runtime, this, cx).await
+ Self::start_language_server(server_id, http, node_runtime, env, this, cx).await
}
})
.shared();
@@ -1279,3 +1306,11 @@ mod tests {
}
}
}
+
+#[cfg(test)]
+#[ctor::ctor]
+fn init_logger() {
+ if std::env::var("RUST_LOG").is_ok() {
+ env_logger::init();
+ }
+}
@@ -234,6 +234,8 @@ pub struct EditPredictionSettings {
pub disabled_globs: Vec<GlobMatcher>,
/// Configures how edit predictions are displayed in the buffer.
pub mode: EditPredictionsMode,
+ /// Settings specific to GitHub Copilot.
+ pub copilot: CopilotSettings,
}
/// The mode in which edit predictions should be displayed.
@@ -248,6 +250,14 @@ pub enum EditPredictionsMode {
EagerPreview,
}
+#[derive(Clone, Debug, Default)]
+pub struct CopilotSettings {
+ /// HTTP/HTTPS proxy to use for Copilot.
+ pub proxy: Option<String>,
+ /// Disable certificate verification for proxy (not recommended).
+ pub proxy_no_verify: Option<bool>,
+}
+
/// The settings for all languages.
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct AllLanguageSettingsContent {
@@ -465,6 +475,23 @@ pub struct EditPredictionSettingsContent {
/// Provider support required.
#[serde(default)]
pub mode: EditPredictionsMode,
+ /// Settings specific to GitHub Copilot.
+ #[serde(default)]
+ pub copilot: CopilotSettingsContent,
+}
+
+#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq)]
+pub struct CopilotSettingsContent {
+ /// HTTP/HTTPS proxy to use for Copilot.
+ ///
+ /// Default: none
+ #[serde(default)]
+ pub proxy: Option<String>,
+ /// Disable certificate verification for the proxy (not recommended).
+ ///
+ /// Default: false
+ #[serde(default)]
+ pub proxy_no_verify: Option<bool>,
}
/// The settings for enabling/disabling features.
@@ -1064,6 +1091,16 @@ impl settings::Settings for AllLanguageSettings {
.map(|globs| globs.iter().collect())
.ok_or_else(Self::missing_default)?;
+ let mut copilot_settings = default_value
+ .edit_predictions
+ .as_ref()
+ .map(|settings| settings.copilot.clone())
+ .map(|copilot| CopilotSettings {
+ proxy: copilot.proxy,
+ proxy_no_verify: copilot.proxy_no_verify,
+ })
+ .unwrap_or_default();
+
let mut file_types: HashMap<Arc<str>, GlobSet> = HashMap::default();
for (language, suffixes) in &default_value.file_types {
@@ -1096,6 +1133,22 @@ impl settings::Settings for AllLanguageSettings {
}
}
+ if let Some(proxy) = user_settings
+ .edit_predictions
+ .as_ref()
+ .and_then(|settings| settings.copilot.proxy.clone())
+ {
+ copilot_settings.proxy = Some(proxy);
+ }
+
+ if let Some(proxy_no_verify) = user_settings
+ .edit_predictions
+ .as_ref()
+ .and_then(|settings| settings.copilot.proxy_no_verify)
+ {
+ copilot_settings.proxy_no_verify = Some(proxy_no_verify);
+ }
+
// A user's global settings override the default global settings and
// all default language-specific settings.
merge_settings(&mut defaults, &user_settings.defaults);
@@ -1147,6 +1200,7 @@ impl settings::Settings for AllLanguageSettings {
.filter_map(|g| Some(globset::Glob::new(g).ok()?.compile_matcher()))
.collect(),
mode: edit_predictions_mode,
+ copilot: copilot_settings,
},
defaults,
languages,