From 8af3f583c2776f5b5ab1d1c2ec1bb2e00f151f74 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 29 Sep 2025 22:08:35 +0200 Subject: [PATCH] Better conpty (#39090) Closes #22657 Closes #37863 # Background Several users have noted that the terminal shipped with Zed on Windows is either misbehaving or missing several features including lack of consistent clearing behaviour. After some investigation which included digging into the Microsoft Terminal project and VSCode editor, it turns out that the pseudoconsole provided by Windows OS is severely outdated which manifests itself in problems such as lack of clearing behaviour, etc. Interestingly however, neither MS Terminal nor VSCode exhibit this limitation so the question was why. Enter custom `conpty.dll` and `OpenConsole.exe` runtime. These are updated, developed in MS Terminal tree subprojects that aim to replace native Windows API as well as augment the `conhost.exe` process that runs by default in Windows. They also fix all the woes we had with the terminal on Windows (there is a chance that ctrl-c behaviour is also fixed with these, but still need to double check that this is indeed the case). This PR ensures that Zed also benefits from the update pseudoconsole API. # Proposed approach It is possible to fork MS Terminal and instrument the necessary subprojects for Rust-awareness (using `cc-rs` or otherwise to compile the C++ code and then embed it in Rust-produced binaries for easier inclusion in projects) but it comes at a cost of added complexity, maintenance burden, etc. An alternative approach was proposed by @reflectronic to download the binary from the official Nuget repo and bundle it for release/local use. This PR aims to do just that. There are two bits to this PR: 1. ~~when building Zed locally, and more specifically, when the `zed` crate is being built, we will strive to download and unpack the binaries into `OUT_DIR` provided by `cargo`. We will then set `ZED_CONPTY_INSTALL_PATH=${OUT_DIR}/conpty` and use it at runtime in Zed binary to tweak the loader's search path with that additional path. This effectively ensures that Zed built from source on Windows has full terminal support.~~ EDIT: after several discussions offline, we've decided that keeping it minimal will serve us best, meaning: when developing locally it is up to the developer of Zed to install `conpty.dll` and put it in the loader's search path. 2. when bundling Windows release, we will download and unpack the nuget package into Zed's bundle which will ensure it is installed in the same directory as Zed by the installer. **Note** I realise that 1. may actually not be needed - instead we could leave that bit for the user who wants to run Zed from source to ensure that they have `conpty.dll` in the loader's search path. I'd love to hear opinions on this! Release Notes: - N/A --------- Co-authored-by: Cole Miller --- Cargo.lock | 9 +++++---- Cargo.toml | 1 + crates/zed/Cargo.toml | 1 + crates/zed/src/main.rs | 12 ++++++++++++ script/bundle-windows.ps1 | 11 +++++++++++ 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4c41ad427d31b8928a573174b14aa94605c1e5bc..a79d0971db2102bdf5f9787e5afce214264ae120 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4111,9 +4111,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.2.1" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" dependencies = [ "crc-catalog", ] @@ -14573,9 +14573,9 @@ checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -20347,6 +20347,7 @@ dependencies = [ "web_search", "web_search_providers", "windows 0.61.1", + "windows-sys 0.61.0", "winresource", "workspace", "workspace-hack", diff --git a/Cargo.toml b/Cargo.toml index 3d84e6bc06f174ecd74d4a8ea620538e177d671a..d23d3b089707763310f05168bbe6fe9bb607d33e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -714,6 +714,7 @@ wasmtime = { version = "29", default-features = false, features = [ wasmtime-wasi = "29" which = "6.0.0" windows-core = "0.61" +windows-sys = "0.61" wit-component = "0.221" workspace-hack = "0.1.0" yawc = "0.2.5" diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 5dfdfd7bf2d55944f3974a1552f0f968c0b21f74..69402cc90876917fcabfb90cbe85af635489fad8 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -170,6 +170,7 @@ zlog_settings.workspace = true [target.'cfg(target_os = "windows")'.dependencies] windows.workspace = true +windows-sys.workspace = true [target.'cfg(target_os = "windows")'.build-dependencies] winresource = "0.1" diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 2f132b27af3f07d1f50d4fa7a9fbc7bb39259248..8dd5d8b1d612a105b3917d7170ff3904ea05f447 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -259,6 +259,9 @@ pub fn main() { .unwrap_or("unknown"), ); + #[cfg(windows)] + check_for_conpty_dll(); + let app = Application::new().with_assets(Assets); let system_id = app.background_executor().block(system_id()).ok(); @@ -1514,3 +1517,12 @@ fn dump_all_gpui_actions() { ) .unwrap(); } + +#[cfg(windows)] +fn check_for_conpty_dll() { + use windows_sys::{Win32::System::LibraryLoader::LoadLibraryW, w}; + let hmodule = unsafe { LoadLibraryW(w!("conpty.dll")) }; + if hmodule.is_null() { + log::warn!("Failed to load conpty.dll. Terminal will work with reduced functionality."); + } +} diff --git a/script/bundle-windows.ps1 b/script/bundle-windows.ps1 index a26abf8413f375b611d01d57b61ac3f91a960dd7..7fa7771e720ee2f0a16ca5a9f1dec2d422fb8e55 100644 --- a/script/bundle-windows.ps1 +++ b/script/bundle-windows.ps1 @@ -146,6 +146,14 @@ function DownloadAMDGpuServices { Expand-Archive -Path $zipPath -DestinationPath "." -Force } +function DownloadConpty { + # If you update the Conpty version, please also update the version in `crates/zed/build.rs`. + $url = "https://www.nuget.org/api/v2/package/CI.Microsoft.Windows.Console.ConPTY/1.22.250314001" + $zipPath = ".\conpty.zip" + Invoke-WebRequest -Uri $url -OutFile $zipPath + Expand-Archive -Path $zipPath -DestinationPath ".\conpty" -Force +} + function CollectFiles { Move-Item -Path "$innoDir\zed_explorer_command_injector.appx" -Destination "$innoDir\appx\zed_explorer_command_injector.appx" -Force Move-Item -Path "$innoDir\zed_explorer_command_injector.dll" -Destination "$innoDir\appx\zed_explorer_command_injector.dll" -Force @@ -153,6 +161,8 @@ function CollectFiles { Move-Item -Path "$innoDir\zed.sh" -Destination "$innoDir\bin\zed" -Force Move-Item -Path "$innoDir\auto_update_helper.exe" -Destination "$innoDir\tools\auto_update_helper.exe" -Force Move-Item -Path ".\AGS_SDK-6.3.0\ags_lib\lib\amd_ags_x64.dll" -Destination "$innoDir\amd_ags_x64.dll" -Force + Move-Item -Path ".\conpty\build\native\runtimes\*" -Destination "$innoDir\bin" -Force + Move-Item -Path ".\conpty\runtimes\win10-x64\native\conpty.dll" -Destination "$innoDir\bin\conpty.dll" -Force } function BuildInstaller { @@ -280,6 +290,7 @@ MakeAppx SignZedAndItsFriends ZipZedAndItsFriendsDebug DownloadAMDGpuServices +DownloadConpty CollectFiles BuildInstaller