From d5aa81a5b22e101617679a1e4f521a65088977e2 Mon Sep 17 00:00:00 2001 From: Martin Pool Date: Fri, 26 Sep 2025 07:20:01 -0700 Subject: [PATCH 001/262] Fix up Wild package name and decompression (#38961) Wild changed in 0.6.0 to using gzip rather than xz, and changed the format of the package name. Follows on from and fixes https://github.com/zed-industries/zed/pull/37717 cc @dvdsk @mati865 Release Notes: - N/A --- script/install-wild | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/script/install-wild b/script/install-wild index 7e35452db7f627378e8d4ab660187eb8fcdbeca2..5ce3de36036b82926b297c70da120c67967db5ac 100755 --- a/script/install-wild +++ b/script/install-wild @@ -20,10 +20,10 @@ if [ "$(whoami)" = root ]; then SUDO=; else SUDO="$(command -v sudo || command - ARCH="$(uname -m)" WILD_REPO="${WILD_REPO:-https://github.com/davidlattimore/wild}" -WILD_PACKAGE="wild-linker-${ARCH}-unknown-linux-gnu" +WILD_PACKAGE="wild-linker-${WILD_VERSION}-${ARCH}-unknown-linux-gnu" WILD_URL="${WILD_URL:-$WILD_REPO}/releases/download/$WILD_VERSION/${WILD_PACKAGE}.tar.gz" echo "Downloading from $WILD_URL" curl -fsSL --output - "$WILD_URL" \ - | $SUDO tar -C /usr/local/bin --strip-components=1 --no-overwrite-dir -xJf - \ - "wild-linker-${ARCH}-unknown-linux-gnu/wild" + | $SUDO tar -C /usr/local/bin --strip-components=1 --no-overwrite-dir -xzf - \ + "${WILD_PACKAGE}/wild" From 5ee73d3e3c9dfe858fb448faeea11f9984e80ed5 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Fri, 26 Sep 2025 10:20:36 -0400 Subject: [PATCH 002/262] Move `settings_macros` to Cargo workspace (#38962) Release Notes: - N/A --- Cargo.toml | 1 + crates/settings/Cargo.toml | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index be6699edb6d19efac2cb981cbd75efd64580629e..a40d75fb72f5f0c05ec6d8a4130fab90d256f866 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -384,6 +384,7 @@ search = { path = "crates/search" } semantic_version = { path = "crates/semantic_version" } session = { path = "crates/session" } settings = { path = "crates/settings" } +settings_macros = { path = "crates/settings_macros" } settings_ui = { path = "crates/settings_ui" } snippet = { path = "crates/snippet" } snippet_provider = { path = "crates/snippet_provider" } diff --git a/crates/settings/Cargo.toml b/crates/settings/Cargo.toml index eb884c1e3f856a58938c679c3d781c1716e516fd..b5cf8a0acfd036767a84a9ac41afc178447ec9f2 100644 --- a/crates/settings/Cargo.toml +++ b/crates/settings/Cargo.toml @@ -28,13 +28,13 @@ paths.workspace = true release_channel.workspace = true rust-embed.workspace = true schemars.workspace = true -serde_json_lenient.workspace = true +serde.workspace = true serde_json.workspace = true +serde_json_lenient.workspace = true serde_path_to_error.workspace = true serde_repr.workspace = true serde_with.workspace = true -serde.workspace = true -settings_macros = { path = "../settings_macros" } +settings_macros.workspace = true smallvec.workspace = true strum.workspace = true tree-sitter-json.workspace = true From 7f14ab26ddb5cccf971650d70ab4ea2b23d732b3 Mon Sep 17 00:00:00 2001 From: Smit Barmase Date: Fri, 26 Sep 2025 20:08:21 +0530 Subject: [PATCH 003/262] copilot: Ensure minimum Node version (#38945) Closes #38918 Release Notes: - N/A --- Cargo.lock | 1 + crates/copilot/Cargo.toml | 1 + crates/copilot/src/copilot.rs | 41 +++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 5bbe2f880ba8fb631ccbe382aa0a029f05a78ce2..a24c27144fee39f15b6ca4f46d79cef6ac46656b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3696,6 +3696,7 @@ dependencies = [ "paths", "project", "rpc", + "semver", "serde", "serde_json", "settings", diff --git a/crates/copilot/Cargo.toml b/crates/copilot/Cargo.toml index 0fc119f31125f4ef3925799fd98fd47cac7ca9da..a0a49d6f25d42e6a578db1f1ec886e50f437e414 100644 --- a/crates/copilot/Cargo.toml +++ b/crates/copilot/Cargo.toml @@ -43,6 +43,7 @@ node_runtime.workspace = true parking_lot.workspace = true paths.workspace = true project.workspace = true +semver.workspace = true serde.workspace = true serde_json.workspace = true settings.workspace = true diff --git a/crates/copilot/src/copilot.rs b/crates/copilot/src/copilot.rs index 49753c3a6d9460b86d50e395d394b6af9a819693..ffcae93b40ad07de9e577e1d2d1558505c8b6de2 100644 --- a/crates/copilot/src/copilot.rs +++ b/crates/copilot/src/copilot.rs @@ -25,6 +25,7 @@ use node_runtime::{NodeRuntime, VersionStrategy}; use parking_lot::Mutex; use project::DisableAiSettings; use request::StatusNotification; +use semver::Version; use serde_json::json; use settings::Settings; use settings::SettingsStore; @@ -485,6 +486,8 @@ impl Copilot { let start_language_server = async { let server_path = get_copilot_lsp(fs, node_runtime.clone()).await?; let node_path = node_runtime.binary_path().await?; + ensure_node_version_for_copilot(&node_path).await?; + let arguments: Vec = vec![server_path.into(), "--stdio".into()]; let binary = LanguageServerBinary { path: node_path, @@ -1161,6 +1164,44 @@ async fn clear_copilot_config_dir() { remove_matching(copilot_chat::copilot_chat_config_dir(), |_| true).await } +async fn ensure_node_version_for_copilot(node_path: &Path) -> anyhow::Result<()> { + const MIN_COPILOT_NODE_VERSION: Version = Version::new(20, 8, 0); + + log::info!("Checking Node.js version for Copilot at: {:?}", node_path); + + let output = util::command::new_smol_command(node_path) + .arg("--version") + .output() + .await + .with_context(|| format!("checking Node.js version at {:?}", node_path))?; + + if !output.status.success() { + anyhow::bail!( + "failed to run node --version for Copilot. stdout: {}, stderr: {}", + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr), + ); + } + + let version_str = String::from_utf8_lossy(&output.stdout); + let version = Version::parse(version_str.trim().trim_start_matches('v')) + .with_context(|| format!("parsing Node.js version from '{}'", version_str.trim()))?; + + if version < MIN_COPILOT_NODE_VERSION { + anyhow::bail!( + "GitHub Copilot language server requires Node.js {MIN_COPILOT_NODE_VERSION} or later, but found {version}. \ + Please update your Node.js version or configure a different Node.js path in settings." + ); + } + + log::info!( + "Node.js version {} meets Copilot requirements (>= {})", + version, + MIN_COPILOT_NODE_VERSION + ); + Ok(()) +} + async fn get_copilot_lsp(fs: Arc, node_runtime: NodeRuntime) -> anyhow::Result { const PACKAGE_NAME: &str = "@github/copilot-language-server"; const SERVER_PATH: &str = From c69912c76a8ee359ef4224d983e63e3178334f32 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 26 Sep 2025 17:17:36 +0200 Subject: [PATCH 004/262] Forbid `std::process::Command` spawning, replace with `smol` where appropriate (#38894) std commands can block for an arbitrary duration and so runs risk of blocking tasks for too long. This replaces all such uses where sensible with async processes. Release Notes: - N/A *or* Added/Fixed/Improved ... --- Cargo.toml | 1 + clippy.toml | 11 +++ crates/auto_update/src/auto_update.rs | 21 +++--- crates/auto_update_helper/src/updater.rs | 1 + crates/cli/build.rs | 1 + crates/cli/src/main.rs | 4 ++ crates/collections/src/collections.rs | 19 ----- crates/crashes/src/crashes.rs | 11 +-- .../src/explorer_command_injector.rs | 1 + crates/extension/src/extension_builder.rs | 40 +++++++---- crates/extension_cli/src/main.rs | 3 +- crates/fs/src/fs.rs | 25 ++++--- crates/git/src/repository.rs | 70 ++++++++++++------- crates/gpui/build.rs | 1 + crates/gpui/src/platform/linux/platform.rs | 22 ++++-- crates/gpui/src/platform/mac/platform.rs | 11 ++- crates/gpui/src/platform/windows/platform.rs | 5 ++ crates/media/build.rs | 1 + crates/project/src/environment.rs | 2 +- crates/project/src/git_store.rs | 2 +- crates/project/src/terminals.rs | 6 +- crates/remote_server/build.rs | 1 + crates/remote_server/src/unix.rs | 67 ++++++++++-------- crates/system_specs/src/system_specs.rs | 4 ++ crates/util/src/shell_env.rs | 11 ++- crates/util/src/util.rs | 4 +- crates/vim/src/command.rs | 11 ++- crates/zed/build.rs | 1 + crates/zed/src/main.rs | 2 +- tooling/perf/Cargo.toml | 1 + tooling/xtask/src/tasks/clippy.rs | 1 + 31 files changed, 220 insertions(+), 141 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a40d75fb72f5f0c05ec6d8a4130fab90d256f866..60722aca42712698912cf600ccb867b97a16d8b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -862,6 +862,7 @@ todo = "deny" declare_interior_mutable_const = "deny" redundant_clone = "deny" +disallowed_methods = "deny" # We currently do not restrict any style rules # as it slows down shipping code to Zed. diff --git a/clippy.toml b/clippy.toml index e606ad4c79b5cfe289b1f8460b1f46715103fe1b..57f6f59385a4885730015c3d09f040a5f340d379 100644 --- a/clippy.toml +++ b/clippy.toml @@ -5,3 +5,14 @@ ignore-interior-mutability = [ # and Hash impls do not use fields with interior mutability. "agent::context::AgentContextKey" ] +disallowed-methods = [ + { path = "std::process::Command::spawn", reason = "Spawning `std::process::Command` can block the current thread for an unknown duration", replacement = "smol::process::Command::spawn" }, + { path = "std::process::Command::output", reason = "Spawning `std::process::Command` can block the current thread for an unknown duration", replacement = "smol::process::Command::output" }, + { path = "std::process::Command::status", reason = "Spawning `std::process::Command` can block the current thread for an unknown duration", replacement = "smol::process::Command::status" }, +] +disallowed-types = [ + # { path = "std::collections::HashMap", replacement = "collections::HashMap" }, + # { path = "std::collections::HashSet", replacement = "collections::HashSet" }, + # { path = "indexmap::IndexSet", replacement = "collections::IndexSet" }, + # { path = "indexmap::IndexMap", replacement = "collections::IndexMap" }, +] diff --git a/crates/auto_update/src/auto_update.rs b/crates/auto_update/src/auto_update.rs index 31121aa6f6d68984e1b9a81a4e500d6a3e9c21d1..0d66ddf52fcec527b63f2f57c7a32c62b65bcf3a 100644 --- a/crates/auto_update/src/auto_update.rs +++ b/crates/auto_update/src/auto_update.rs @@ -310,10 +310,10 @@ impl AutoUpdater { // the app after an update, we use `set_restart_path` to run the auto // update helper instead of the app, so that it can overwrite the app // and then spawn the new binary. - let quit_subscription = Some(cx.on_app_quit(|_, _| async move { - #[cfg(target_os = "windows")] - finalize_auto_update_on_quit(); - })); + #[cfg(target_os = "windows")] + let quit_subscription = Some(cx.on_app_quit(|_, _| finalize_auto_update_on_quit())); + #[cfg(not(target_os = "windows"))] + let quit_subscription = None; cx.on_app_restart(|this, _| { this.quit_subscription.take(); @@ -942,11 +942,12 @@ async fn install_release_windows(downloaded_installer: PathBuf) -> Result