From a873cf402c8d5ffa13ab54efd29ccd4df59c7e46 Mon Sep 17 00:00:00 2001 From: Cole Miller Date: Tue, 16 Jun 2026 09:47:55 -0400 Subject: [PATCH] Remove gpui's dependency on `async-process` (#59358) This removes gpui's dependency on the `util` crate, which depends on async process. It now depends on `gpui_util` only, and uses `std::process::Command` for the two cases where it was previously using an async `Command`. This lifts the requirement of non-Zed consumers of gpui to depend on our forked async-process (see #59156). Release Notes: - N/A --- Cargo.lock | 10 +- crates/gpui_linux/Cargo.toml | 2 +- crates/gpui_linux/src/linux/dispatcher.rs | 2 +- .../gpui_linux/src/linux/headless/client.rs | 2 +- crates/gpui_linux/src/linux/platform.rs | 17 ++- crates/gpui_linux/src/linux/wayland/client.rs | 2 +- crates/gpui_linux/src/linux/wayland/cursor.rs | 2 +- crates/gpui_linux/src/linux/x11/client.rs | 2 +- crates/gpui_linux/src/linux/x11/clipboard.rs | 2 +- crates/gpui_linux/src/linux/x11/window.rs | 2 +- crates/gpui_macos/Cargo.toml | 2 +- crates/gpui_macos/src/dispatcher.rs | 2 +- crates/gpui_macos/src/display_link.rs | 2 +- crates/gpui_macos/src/platform.rs | 18 ++- crates/gpui_macos/src/window.rs | 2 +- crates/gpui_tokio/Cargo.toml | 2 +- crates/gpui_tokio/src/gpui_tokio.rs | 2 +- crates/gpui_util/Cargo.toml | 3 + crates/gpui_util/src/lib.rs | 132 ++++++++++++++++++ crates/gpui_windows/Cargo.toml | 3 +- .../gpui_windows/src/direct_manipulation.rs | 2 +- crates/gpui_windows/src/direct_write.rs | 2 +- crates/gpui_windows/src/directx_devices.rs | 2 +- crates/gpui_windows/src/directx_renderer.rs | 2 +- crates/gpui_windows/src/dispatcher.rs | 4 +- crates/gpui_windows/src/display.rs | 2 +- crates/gpui_windows/src/events.rs | 2 +- crates/gpui_windows/src/platform.rs | 15 +- crates/gpui_windows/src/system_settings.rs | 2 +- crates/gpui_windows/src/util.rs | 2 +- crates/gpui_windows/src/vsync.rs | 2 +- crates/gpui_windows/src/window.rs | 2 +- crates/http_client/Cargo.toml | 17 ++- crates/http_client/src/http_client.rs | 2 +- crates/languages/Cargo.toml | 2 +- crates/project/Cargo.toml | 2 +- crates/util/src/command.rs | 16 +-- crates/util/src/shell.rs | 113 +-------------- 38 files changed, 213 insertions(+), 189 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 085dd33797b..591b6310a6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7828,6 +7828,7 @@ dependencies = [ "filedescriptor", "futures 0.3.32", "gpui", + "gpui_util", "gpui_wgpu", "http_client", "image", @@ -7846,7 +7847,6 @@ dependencies = [ "strum 0.27.2", "swash", "url", - "util", "uuid", "wayland-backend", "wayland-client", @@ -7885,6 +7885,7 @@ dependencies = [ "foreign-types 0.5.0", "futures 0.3.32", "gpui", + "gpui_util", "image", "itertools 0.14.0", "libc", @@ -7902,7 +7903,6 @@ dependencies = [ "semver", "smallvec", "strum 0.27.2", - "util", "uuid", "zed-font-kit", ] @@ -7945,8 +7945,8 @@ version = "0.1.0" dependencies = [ "anyhow", "gpui", + "gpui_util", "tokio", - "util", ] [[package]] @@ -7955,6 +7955,7 @@ version = "0.1.0" dependencies = [ "anyhow", "log", + "which 6.0.3", ] [[package]] @@ -8017,9 +8018,11 @@ dependencies = [ "accesskit_windows", "anyhow", "collections", + "dunce", "etagere", "futures 0.3.32", "gpui", + "gpui_util", "image", "itertools 0.14.0", "log", @@ -8027,7 +8030,6 @@ dependencies = [ "rand 0.9.4", "raw-window-handle", "smallvec", - "util", "uuid", "windows 0.61.3", "windows-core 0.61.2", diff --git a/crates/gpui_linux/Cargo.toml b/crates/gpui_linux/Cargo.toml index 0e9de0ebc0c..a1e0531f3d5 100644 --- a/crates/gpui_linux/Cargo.toml +++ b/crates/gpui_linux/Cargo.toml @@ -59,6 +59,7 @@ collections.workspace = true image.workspace = true futures.workspace = true gpui.workspace = true +gpui_util.workspace = true gpui_wgpu = { workspace = true, optional = true, features = ["font-kit"] } http_client.workspace = true itertools.workspace = true @@ -72,7 +73,6 @@ smallvec.workspace = true smol.workspace = true strum.workspace = true url.workspace = true -util.workspace = true uuid.workspace = true # Always used diff --git a/crates/gpui_linux/src/linux/dispatcher.rs b/crates/gpui_linux/src/linux/dispatcher.rs index 06d29d74f8f..2a178521edc 100644 --- a/crates/gpui_linux/src/linux/dispatcher.rs +++ b/crates/gpui_linux/src/linux/dispatcher.rs @@ -3,7 +3,7 @@ use calloop::{ channel::{self, Sender}, timer::TimeoutAction, }; -use util::ResultExt; +use gpui_util::ResultExt; use std::{mem::MaybeUninit, thread, time::Duration}; diff --git a/crates/gpui_linux/src/linux/headless/client.rs b/crates/gpui_linux/src/linux/headless/client.rs index 56cc9e8df00..716354a8850 100644 --- a/crates/gpui_linux/src/linux/headless/client.rs +++ b/crates/gpui_linux/src/linux/headless/client.rs @@ -2,7 +2,7 @@ use std::cell::RefCell; use std::rc::Rc; use calloop::{EventLoop, LoopHandle}; -use util::ResultExt; +use gpui_util::ResultExt; use crate::linux::{LinuxClient, LinuxCommon, LinuxKeyboardLayout}; use gpui::{ diff --git a/crates/gpui_linux/src/linux/platform.rs b/crates/gpui_linux/src/linux/platform.rs index be41f241935..2eea2e2a0ed 100644 --- a/crates/gpui_linux/src/linux/platform.rs +++ b/crates/gpui_linux/src/linux/platform.rs @@ -16,8 +16,7 @@ use std::{ use anyhow::{Context as _, anyhow}; use calloop::LoopSignal; use futures::channel::oneshot; -use util::ResultExt as _; -use util::command::{new_command, new_std_command}; +use gpui_util::{ResultExt as _, new_std_command}; #[cfg(any(feature = "wayland", feature = "x11"))] use xkbcommon::xkb::{self, Keycode, Keysym, State}; @@ -461,15 +460,15 @@ impl Platform for LinuxPlatform

{ let path = path.to_owned(); self.background_executor() .spawn(async move { - let _ = new_command("xdg-open") + #[allow( + clippy::disallowed_methods, + reason = "running on a background thread, so blocking is fine" + )] + new_std_command("xdg-open") .arg(path) - .spawn() - .context("invoking xdg-open") - .log_err()? .status() - .await - .log_err()?; - Some(()) + .context("invoking xdg-open") + .log_err(); }) .detach(); } diff --git a/crates/gpui_linux/src/linux/wayland/client.rs b/crates/gpui_linux/src/linux/wayland/client.rs index 5decbc34e6f..c7e1ed4a403 100644 --- a/crates/gpui_linux/src/linux/wayland/client.rs +++ b/crates/gpui_linux/src/linux/wayland/client.rs @@ -15,9 +15,9 @@ use calloop::{ use calloop_wayland_source::WaylandSource; use collections::HashMap; use filedescriptor::Pipe; +use gpui_util::ResultExt as _; use http_client::Url; use smallvec::SmallVec; -use util::ResultExt as _; use wayland_backend::client::ObjectId; use wayland_backend::protocol::WEnum; use wayland_client::event_created_child; diff --git a/crates/gpui_linux/src/linux/wayland/cursor.rs b/crates/gpui_linux/src/linux/wayland/cursor.rs index 957fcf39be8..2d66fed95c1 100644 --- a/crates/gpui_linux/src/linux/wayland/cursor.rs +++ b/crates/gpui_linux/src/linux/wayland/cursor.rs @@ -1,7 +1,7 @@ use crate::linux::Globals; use crate::linux::{DEFAULT_CURSOR_ICON_NAME, log_cursor_icon_warning}; use anyhow::{Context as _, anyhow}; -use util::ResultExt; +use gpui_util::ResultExt; use wayland_client::Connection; use wayland_client::protocol::wl_surface::WlSurface; diff --git a/crates/gpui_linux/src/linux/x11/client.rs b/crates/gpui_linux/src/linux/x11/client.rs index b923fde4388..7ee0aa579eb 100644 --- a/crates/gpui_linux/src/linux/x11/client.rs +++ b/crates/gpui_linux/src/linux/x11/client.rs @@ -7,6 +7,7 @@ use calloop::{ use collections::HashMap; use core::str; use gpui::{Capslock, profiler}; +use gpui_util::ResultExt as _; use http_client::Url; use log::Level; use smallvec::SmallVec; @@ -18,7 +19,6 @@ use std::{ rc::{Rc, Weak}, time::{Duration, Instant}, }; -use util::ResultExt as _; use x11rb::{ connection::{Connection, RequestConnection}, diff --git a/crates/gpui_linux/src/linux/x11/clipboard.rs b/crates/gpui_linux/src/linux/x11/clipboard.rs index fb6cecd9045..706e7b09658 100644 --- a/crates/gpui_linux/src/linux/x11/clipboard.rs +++ b/crates/gpui_linux/src/linux/x11/clipboard.rs @@ -844,7 +844,7 @@ fn serve_requests(context: Arc) -> Result<(), Box> log::trace!("Started serve requests thread."); - let _guard = util::defer(|| { + let _guard = gpui_util::defer(|| { context.serve_stopped.store(true, Ordering::Relaxed); }); diff --git a/crates/gpui_linux/src/linux/x11/window.rs b/crates/gpui_linux/src/linux/x11/window.rs index 1f3ca51155d..147630d054d 100644 --- a/crates/gpui_linux/src/linux/x11/window.rs +++ b/crates/gpui_linux/src/linux/x11/window.rs @@ -12,8 +12,8 @@ use gpui::{ use gpui_wgpu::{CompositorGpuHint, WgpuRenderer, WgpuSurfaceConfig}; use collections::FxHashSet; +use gpui_util::{ResultExt, maybe}; use raw_window_handle as rwh; -use util::{ResultExt, maybe}; use x11rb::{ connection::Connection, cookie::{Cookie, VoidCookie}, diff --git a/crates/gpui_macos/Cargo.toml b/crates/gpui_macos/Cargo.toml index fbb439be303..75ce276bf02 100644 --- a/crates/gpui_macos/Cargo.toml +++ b/crates/gpui_macos/Cargo.toml @@ -42,6 +42,7 @@ etagere = "0.2" font-kit = { git = "https://github.com/zed-industries/font-kit", rev = "94b0f28166665e8fd2f53ff6d268a14955c82269", package = "zed-font-kit", version = "0.14.1-zed", optional = true } foreign-types = "0.5" futures.workspace = true +gpui_util.workspace = true image.workspace = true itertools.workspace = true libc.workspace = true @@ -59,7 +60,6 @@ raw-window-handle = "0.6" semver.workspace = true smallvec.workspace = true strum.workspace = true -util.workspace = true uuid.workspace = true [target.'cfg(target_os = "macos")'.build-dependencies] diff --git a/crates/gpui_macos/src/dispatcher.rs b/crates/gpui_macos/src/dispatcher.rs index 5699fdae1da..0e5ebdcaf3b 100644 --- a/crates/gpui_macos/src/dispatcher.rs +++ b/crates/gpui_macos/src/dispatcher.rs @@ -1,5 +1,6 @@ use dispatch2::{DispatchQueue, DispatchQueueGlobalPriority, DispatchTime, GlobalQueueIdentifier}; use gpui::{PlatformDispatcher, Priority, RunnableMeta, RunnableVariant}; +use gpui_util::ResultExt; use mach2::{ kern_return::KERN_SUCCESS, mach_time::mach_timebase_info_data_t, @@ -10,7 +11,6 @@ use mach2::{ thread_precedence_policy_data_t, thread_time_constraint_policy_data_t, }, }; -use util::ResultExt; use async_task::Runnable; use objc::{ diff --git a/crates/gpui_macos/src/display_link.rs b/crates/gpui_macos/src/display_link.rs index 86e9b4072ba..468f3d8bde1 100644 --- a/crates/gpui_macos/src/display_link.rs +++ b/crates/gpui_macos/src/display_link.rs @@ -3,8 +3,8 @@ use core_graphics::display::CGDirectDisplayID; use dispatch2::{ _dispatch_source_type_data_add, DispatchObject, DispatchQueue, DispatchRetained, DispatchSource, }; +use gpui_util::ResultExt; use std::ffi::c_void; -use util::ResultExt; pub struct DisplayLink { display_link: Option, diff --git a/crates/gpui_macos/src/platform.rs b/crates/gpui_macos/src/platform.rs index aedb2d38274..d9bcc6b0a04 100644 --- a/crates/gpui_macos/src/platform.rs +++ b/crates/gpui_macos/src/platform.rs @@ -33,6 +33,7 @@ use gpui::{ PlatformDisplay, PlatformKeyboardLayout, PlatformKeyboardMapper, PlatformTextSystem, PlatformWindow, Result, SystemMenuType, Task, ThermalState, WindowAppearance, WindowParams, }; +use gpui_util::{ResultExt, new_std_command}; use itertools::Itertools; use objc::{ class, @@ -57,10 +58,6 @@ use std::{ atomic::{AtomicBool, Ordering}, }, }; -use util::{ - ResultExt, - command::{new_command, new_std_command}, -}; #[allow(non_upper_case_globals)] const NSUTF8StringEncoding: NSUInteger = 4; @@ -880,15 +877,16 @@ impl Platform for MacPlatform { .lock() .background_executor .spawn(async move { - if let Some(mut child) = new_command("open") + #[allow( + clippy::disallowed_methods, + reason = "running on a background thread, so blocking is fine" + )] + new_std_command("open") .arg("--") .arg(path) - .spawn() + .status() .context("invoking open command") - .log_err() - { - child.status().await.log_err(); - } + .log_err(); }) .detach(); } diff --git a/crates/gpui_macos/src/window.rs b/crates/gpui_macos/src/window.rs index 02cf460fa12..507e51c26f8 100644 --- a/crates/gpui_macos/src/window.rs +++ b/crates/gpui_macos/src/window.rs @@ -41,6 +41,7 @@ use core_foundation_sys::number::{CFBooleanGetValue, CFBooleanRef}; use core_graphics::display::{CGDirectDisplayID, CGRect}; use ctor::ctor; use futures::channel::oneshot; +use gpui_util::ResultExt; use objc::{ class, declare::ClassDecl, @@ -71,7 +72,6 @@ use std::{ }, time::Duration, }; -use util::ResultExt; const WINDOW_STATE_IVAR: &str = "windowState"; diff --git a/crates/gpui_tokio/Cargo.toml b/crates/gpui_tokio/Cargo.toml index e9d72b8ec25..5ea343862f4 100644 --- a/crates/gpui_tokio/Cargo.toml +++ b/crates/gpui_tokio/Cargo.toml @@ -14,6 +14,6 @@ doctest = false [dependencies] anyhow.workspace = true -util.workspace = true gpui.workspace = true +gpui_util.workspace = true tokio = { workspace = true, features = ["rt", "rt-multi-thread"] } diff --git a/crates/gpui_tokio/src/gpui_tokio.rs b/crates/gpui_tokio/src/gpui_tokio.rs index d32843ae86f..6ef71b48901 100644 --- a/crates/gpui_tokio/src/gpui_tokio.rs +++ b/crates/gpui_tokio/src/gpui_tokio.rs @@ -1,7 +1,7 @@ use std::future::Future; use gpui::{App, AppContext, Global, ReadGlobal, Task}; -use util::defer; +use gpui_util::defer; pub use tokio::task::JoinError; diff --git a/crates/gpui_util/Cargo.toml b/crates/gpui_util/Cargo.toml index 5f2267c7f34..cad692b04dc 100644 --- a/crates/gpui_util/Cargo.toml +++ b/crates/gpui_util/Cargo.toml @@ -8,5 +8,8 @@ edition.workspace = true log.workspace = true anyhow.workspace = true +[target.'cfg(target_os = "windows")'.dependencies] +which.workspace = true + [lints] workspace = true diff --git a/crates/gpui_util/src/lib.rs b/crates/gpui_util/src/lib.rs index ee210cb7487..fe6a3cfca66 100644 --- a/crates/gpui_util/src/lib.rs +++ b/crates/gpui_util/src/lib.rs @@ -3,6 +3,7 @@ use std::{ env, + ffi::OsStr, ops::AddAssign, panic::Location, pin::Pin, @@ -13,6 +14,137 @@ use std::{ pub mod arc_cow; +#[cfg(target_os = "windows")] +const CREATE_NO_WINDOW: u32 = 0x0800_0000_u32; + +#[cfg(target_os = "windows")] +pub fn new_std_command(program: impl AsRef) -> std::process::Command { + use std::os::windows::process::CommandExt; + + let mut command = std::process::Command::new(program); + command.creation_flags(CREATE_NO_WINDOW); + command +} + +#[cfg(not(target_os = "windows"))] +pub fn new_std_command(program: impl AsRef) -> std::process::Command { + std::process::Command::new(program) +} + +#[cfg(target_os = "windows")] +pub fn get_windows_system_shell() -> String { + use std::path::PathBuf; + + fn find_pwsh_in_programfiles(find_alternate: bool, find_preview: bool) -> Option { + #[cfg(target_pointer_width = "64")] + let env_var = if find_alternate { + "ProgramFiles(x86)" + } else { + "ProgramFiles" + }; + + #[cfg(target_pointer_width = "32")] + let env_var = if find_alternate { + "ProgramW6432" + } else { + "ProgramFiles" + }; + + let install_base_dir = PathBuf::from(std::env::var_os(env_var)?).join("PowerShell"); + install_base_dir + .read_dir() + .ok()? + .filter_map(Result::ok) + .filter(|entry| matches!(entry.file_type(), Ok(ft) if ft.is_dir())) + .filter_map(|entry| { + let dir_name = entry.file_name(); + let dir_name = dir_name.to_string_lossy(); + + let version = if find_preview { + let dash_index = dir_name.find('-')?; + if &dir_name[dash_index + 1..] != "preview" { + return None; + }; + dir_name[..dash_index].parse::().ok()? + } else { + dir_name.parse::().ok()? + }; + + let exe_path = entry.path().join("pwsh.exe"); + if exe_path.exists() { + Some((version, exe_path)) + } else { + None + } + }) + .max_by_key(|(version, _)| *version) + .map(|(_, path)| path) + } + + fn find_pwsh_in_msix(find_preview: bool) -> Option { + let msix_app_dir = + PathBuf::from(std::env::var_os("LOCALAPPDATA")?).join("Microsoft\\WindowsApps"); + if !msix_app_dir.exists() { + return None; + } + + let prefix = if find_preview { + "Microsoft.PowerShellPreview_" + } else { + "Microsoft.PowerShell_" + }; + msix_app_dir + .read_dir() + .ok()? + .filter_map(|entry| { + let entry = entry.ok()?; + if !matches!(entry.file_type(), Ok(ft) if ft.is_dir()) { + return None; + } + + if !entry.file_name().to_string_lossy().starts_with(prefix) { + return None; + } + + let exe_path = entry.path().join("pwsh.exe"); + exe_path.exists().then_some(exe_path) + }) + .next() + } + + fn find_pwsh_in_scoop() -> Option { + let pwsh_exe = + PathBuf::from(std::env::var_os("USERPROFILE")?).join("scoop\\shims\\pwsh.exe"); + pwsh_exe.exists().then_some(pwsh_exe) + } + + static SYSTEM_SHELL: std::sync::LazyLock = std::sync::LazyLock::new(|| { + let locations = [ + || find_pwsh_in_programfiles(false, false), + || find_pwsh_in_programfiles(true, false), + || find_pwsh_in_msix(false), + || find_pwsh_in_programfiles(false, true), + || find_pwsh_in_msix(true), + || find_pwsh_in_programfiles(true, true), + || find_pwsh_in_scoop(), + || which::which_global("pwsh.exe").ok(), + || which::which_global("powershell.exe").ok(), + ]; + + locations + .into_iter() + .find_map(|f| f()) + .map(|p| p.to_string_lossy().trim().to_owned()) + .inspect(|shell| log::info!("Found powershell in: {}", shell)) + .unwrap_or_else(|| { + log::warn!("Powershell not found, falling back to `cmd`"); + "cmd.exe".to_string() + }) + }); + + (*SYSTEM_SHELL).clone() +} + pub fn post_inc + AddAssign + Copy>(value: &mut T) -> T { let prev = *value; *value += T::from(1); diff --git a/crates/gpui_windows/Cargo.toml b/crates/gpui_windows/Cargo.toml index f5a93e7f5aa..24799c0258c 100644 --- a/crates/gpui_windows/Cargo.toml +++ b/crates/gpui_windows/Cargo.toml @@ -24,8 +24,10 @@ accesskit.workspace = true accesskit_windows.workspace = true anyhow.workspace = true collections.workspace = true +dunce.workspace = true etagere = "0.2" futures.workspace = true +gpui_util.workspace = true image.workspace = true itertools.workspace = true log.workspace = true @@ -33,7 +35,6 @@ parking_lot.workspace = true rand.workspace = true raw-window-handle = "0.6" smallvec.workspace = true -util.workspace = true uuid.workspace = true windows.workspace = true windows-core.workspace = true diff --git a/crates/gpui_windows/src/direct_manipulation.rs b/crates/gpui_windows/src/direct_manipulation.rs index 08a1e5243e1..9adcbed343b 100644 --- a/crates/gpui_windows/src/direct_manipulation.rs +++ b/crates/gpui_windows/src/direct_manipulation.rs @@ -1,9 +1,9 @@ use std::cell::{Cell, RefCell}; use std::rc::Rc; -use ::util::ResultExt; use anyhow::Result; use gpui::*; +use gpui_util::ResultExt; use windows::Win32::{ Foundation::*, Graphics::{DirectManipulation::*, Gdi::*}, diff --git a/crates/gpui_windows/src/direct_write.rs b/crates/gpui_windows/src/direct_write.rs index 5cdd01f70af..ebf99c8951a 100644 --- a/crates/gpui_windows/src/direct_write.rs +++ b/crates/gpui_windows/src/direct_write.rs @@ -4,9 +4,9 @@ use std::{ mem::ManuallyDrop, }; -use ::util::{ResultExt, maybe}; use anyhow::{Context, Result}; use collections::HashMap; +use gpui_util::{ResultExt, maybe}; use parking_lot::{RwLock, RwLockUpgradableReadGuard}; use windows::{ Win32::{ diff --git a/crates/gpui_windows/src/directx_devices.rs b/crates/gpui_windows/src/directx_devices.rs index 882e404a56c..8e65e6e626a 100644 --- a/crates/gpui_windows/src/directx_devices.rs +++ b/crates/gpui_windows/src/directx_devices.rs @@ -1,6 +1,6 @@ use anyhow::{Context, Result}; +use gpui_util::ResultExt; use itertools::Itertools; -use util::ResultExt; use windows::Win32::{ Foundation::HMODULE, Graphics::{ diff --git a/crates/gpui_windows/src/directx_renderer.rs b/crates/gpui_windows/src/directx_renderer.rs index b5c4d3bf34a..03666241e67 100644 --- a/crates/gpui_windows/src/directx_renderer.rs +++ b/crates/gpui_windows/src/directx_renderer.rs @@ -3,8 +3,8 @@ use std::{ sync::{Arc, OnceLock}, }; -use ::util::ResultExt; use anyhow::{Context, Result}; +use gpui_util::ResultExt; use windows::{ Win32::{ Foundation::HWND, diff --git a/crates/gpui_windows/src/dispatcher.rs b/crates/gpui_windows/src/dispatcher.rs index 1f74aa8ad0e..d1dd5685b07 100644 --- a/crates/gpui_windows/src/dispatcher.rs +++ b/crates/gpui_windows/src/dispatcher.rs @@ -5,7 +5,7 @@ use std::{ }; use anyhow::Context; -use util::ResultExt; +use gpui_util::ResultExt; use windows::{ System::Threading::{ ThreadPool, ThreadPoolTimer, TimerElapsedHandler, WorkItemHandler, WorkItemPriority, @@ -152,7 +152,7 @@ impl PlatformDispatcher for WindowsDispatcher { unsafe { timeBeginPeriod(1); } - util::defer(Box::new(|| unsafe { + gpui_util::defer(Box::new(|| unsafe { timeEndPeriod(1); })) } diff --git a/crates/gpui_windows/src/display.rs b/crates/gpui_windows/src/display.rs index 3b81dc63a00..bb75bf7dd58 100644 --- a/crates/gpui_windows/src/display.rs +++ b/crates/gpui_windows/src/display.rs @@ -1,7 +1,7 @@ +use gpui_util::ResultExt; use itertools::Itertools; use smallvec::SmallVec; use std::rc::Rc; -use util::ResultExt; use uuid::Uuid; use windows::{ Win32::{ diff --git a/crates/gpui_windows/src/events.rs b/crates/gpui_windows/src/events.rs index 51205946ef0..f101d82f017 100644 --- a/crates/gpui_windows/src/events.rs +++ b/crates/gpui_windows/src/events.rs @@ -1,7 +1,7 @@ use std::{rc::Rc, sync::atomic::Ordering}; -use ::util::ResultExt; use anyhow::Context as _; +use gpui_util::ResultExt; use windows::{ Win32::{ Foundation::*, diff --git a/crates/gpui_windows/src/platform.rs b/crates/gpui_windows/src/platform.rs index 7b76c4d12a8..294cef136ee 100644 --- a/crates/gpui_windows/src/platform.rs +++ b/crates/gpui_windows/src/platform.rs @@ -9,9 +9,9 @@ use std::{ }, }; -use ::util::{ResultExt, paths::SanitizedPath}; use anyhow::{Context as _, Result, anyhow}; use futures::channel::oneshot::{self, Receiver}; +use gpui_util::{ResultExt, get_windows_system_shell, new_std_command}; use itertools::Itertools; use parking_lot::RwLock; use smallvec::SmallVec; @@ -467,11 +467,10 @@ impl Platform for WindowsPlatform { clippy::disallowed_methods, reason = "We are restarting ourselves, using std command thus is fine" )] - let restart_process = - ::util::command::new_std_command(::util::shell::get_windows_system_shell()) - .arg("-command") - .arg(script) - .spawn(); + let restart_process = new_std_command(get_windows_system_shell()) + .arg("-command") + .arg(script) + .spawn(); match restart_process { Ok(_) => unsafe { PostQuitMessage(0) }, @@ -1186,8 +1185,8 @@ fn file_save_dialog( .context("failed to canonicalize directory") .log_err() { - let full_path = SanitizedPath::new(&full_path); - let full_path_string = full_path.to_string(); + let full_path = dunce::simplified(&full_path); + let full_path_string = full_path.display().to_string(); let path_item: IShellItem = unsafe { SHCreateItemFromParsingName(&HSTRING::from(full_path_string), None)? }; unsafe { diff --git a/crates/gpui_windows/src/system_settings.rs b/crates/gpui_windows/src/system_settings.rs index 53214f40deb..8cce544be1b 100644 --- a/crates/gpui_windows/src/system_settings.rs +++ b/crates/gpui_windows/src/system_settings.rs @@ -3,7 +3,7 @@ use std::{ ffi::{c_uint, c_void}, }; -use ::util::ResultExt; +use gpui_util::ResultExt; use windows::Win32::UI::WindowsAndMessaging::{ SPI_GETWHEELSCROLLCHARS, SPI_GETWHEELSCROLLLINES, SYSTEM_PARAMETERS_INFO_ACTION, SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS, SystemParametersInfoW, diff --git a/crates/gpui_windows/src/util.rs b/crates/gpui_windows/src/util.rs index 15dd4c69984..b3badd84d10 100644 --- a/crates/gpui_windows/src/util.rs +++ b/crates/gpui_windows/src/util.rs @@ -1,7 +1,7 @@ use std::sync::OnceLock; -use ::util::ResultExt; use anyhow::Context; +use gpui_util::ResultExt; use windows::{ UI::{ Color, diff --git a/crates/gpui_windows/src/vsync.rs b/crates/gpui_windows/src/vsync.rs index 73c32cf9b92..51fbdf6c500 100644 --- a/crates/gpui_windows/src/vsync.rs +++ b/crates/gpui_windows/src/vsync.rs @@ -4,7 +4,7 @@ use std::{ }; use anyhow::{Context, Result}; -use util::ResultExt; +use gpui_util::ResultExt; use windows::Win32::{ Foundation::HWND, Graphics::Dwm::{DWM_TIMING_INFO, DwmFlush, DwmGetCompositionTimingInfo}, diff --git a/crates/gpui_windows/src/window.rs b/crates/gpui_windows/src/window.rs index b33d8702f2f..c9352a60035 100644 --- a/crates/gpui_windows/src/window.rs +++ b/crates/gpui_windows/src/window.rs @@ -10,9 +10,9 @@ use std::{ time::{Duration, Instant}, }; -use ::util::ResultExt; use anyhow::{Context as _, Result}; use futures::channel::oneshot::{self, Receiver}; +use gpui_util::ResultExt; use raw_window_handle as rwh; use smallvec::SmallVec; use windows::{ diff --git a/crates/http_client/Cargo.toml b/crates/http_client/Cargo.toml index 6273d773d8c..efae728ddb4 100644 --- a/crates/http_client/Cargo.toml +++ b/crates/http_client/Cargo.toml @@ -11,6 +11,13 @@ workspace = true [features] test-support = [] +github-download = [ + "dep:async-fs", + "dep:async-tar", + "dep:sha2", + "dep:tempfile", + "dep:util", +] [lib] path = "src/http_client.rs" @@ -32,8 +39,8 @@ serde_urlencoded.workspace = true url.workspace = true [target.'cfg(not(target_family = "wasm"))'.dependencies] -util.workspace = true -async-fs.workspace = true -async-tar.workspace = true -sha2.workspace = true -tempfile.workspace = true +util = { workspace = true, optional = true } +async-fs = { workspace = true, optional = true } +async-tar = { workspace = true, optional = true } +sha2 = { workspace = true, optional = true } +tempfile = { workspace = true, optional = true } diff --git a/crates/http_client/src/http_client.rs b/crates/http_client/src/http_client.rs index 1c3e1859b7f..7f65b9126f0 100644 --- a/crates/http_client/src/http_client.rs +++ b/crates/http_client/src/http_client.rs @@ -1,7 +1,7 @@ mod async_body; #[cfg(not(target_family = "wasm"))] pub mod github; -#[cfg(not(target_family = "wasm"))] +#[cfg(all(not(target_family = "wasm"), feature = "github-download"))] pub mod github_download; pub use anyhow::{Result, anyhow}; diff --git a/crates/languages/Cargo.toml b/crates/languages/Cargo.toml index 8db195ba7de..358a9ad267e 100644 --- a/crates/languages/Cargo.toml +++ b/crates/languages/Cargo.toml @@ -30,7 +30,7 @@ futures.workspace = true globset.workspace = true gpui.workspace = true grammars.workspace = true -http_client.workspace = true +http_client = { workspace = true, features = ["github-download"] } itertools.workspace = true json_schema_store.workspace = true language.workspace = true diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index df57a8fdf5e..5fd388ddaf8 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -58,7 +58,7 @@ git.workspace = true git_hosting_providers.workspace = true globset.workspace = true gpui.workspace = true -http_client.workspace = true +http_client = { workspace = true, features = ["github-download"] } image.workspace = true itertools.workspace = true indexmap.workspace = true diff --git a/crates/util/src/command.rs b/crates/util/src/command.rs index a131d3c15b9..846a8570760 100644 --- a/crates/util/src/command.rs +++ b/crates/util/src/command.rs @@ -11,24 +11,12 @@ pub use darwin::{Child, Command, Stdio}; #[cfg(target_os = "windows")] const CREATE_NO_WINDOW: u32 = 0x0800_0000_u32; +pub use gpui_util::new_std_command; + pub fn new_command(program: impl AsRef) -> Command { Command::new(program) } -#[cfg(target_os = "windows")] -pub fn new_std_command(program: impl AsRef) -> std::process::Command { - use std::os::windows::process::CommandExt; - - let mut command = std::process::Command::new(program); - command.creation_flags(CREATE_NO_WINDOW); - command -} - -#[cfg(not(target_os = "windows"))] -pub fn new_std_command(program: impl AsRef) -> std::process::Command { - std::process::Command::new(program) -} - #[cfg(not(target_os = "macos"))] pub type Child = smol::process::Child; diff --git a/crates/util/src/shell.rs b/crates/util/src/shell.rs index 87872856d91..e9b6d054996 100644 --- a/crates/util/src/shell.rs +++ b/crates/util/src/shell.rs @@ -121,116 +121,11 @@ pub fn get_windows_bash() -> Option { } pub fn get_windows_system_shell() -> String { - use std::path::PathBuf; + #[cfg(windows)] + return gpui_util::get_windows_system_shell(); - fn find_pwsh_in_programfiles(find_alternate: bool, find_preview: bool) -> Option { - #[cfg(target_pointer_width = "64")] - let env_var = if find_alternate { - "ProgramFiles(x86)" - } else { - "ProgramFiles" - }; - - #[cfg(target_pointer_width = "32")] - let env_var = if find_alternate { - "ProgramW6432" - } else { - "ProgramFiles" - }; - - let install_base_dir = PathBuf::from(std::env::var_os(env_var)?).join("PowerShell"); - install_base_dir - .read_dir() - .ok()? - .filter_map(Result::ok) - .filter(|entry| matches!(entry.file_type(), Ok(ft) if ft.is_dir())) - .filter_map(|entry| { - let dir_name = entry.file_name(); - let dir_name = dir_name.to_string_lossy(); - - let version = if find_preview { - let dash_index = dir_name.find('-')?; - if &dir_name[dash_index + 1..] != "preview" { - return None; - }; - dir_name[..dash_index].parse::().ok()? - } else { - dir_name.parse::().ok()? - }; - - let exe_path = entry.path().join("pwsh.exe"); - if exe_path.exists() { - Some((version, exe_path)) - } else { - None - } - }) - .max_by_key(|(version, _)| *version) - .map(|(_, path)| path) - } - - fn find_pwsh_in_msix(find_preview: bool) -> Option { - let msix_app_dir = - PathBuf::from(std::env::var_os("LOCALAPPDATA")?).join("Microsoft\\WindowsApps"); - if !msix_app_dir.exists() { - return None; - } - - let prefix = if find_preview { - "Microsoft.PowerShellPreview_" - } else { - "Microsoft.PowerShell_" - }; - msix_app_dir - .read_dir() - .ok()? - .filter_map(|entry| { - let entry = entry.ok()?; - if !matches!(entry.file_type(), Ok(ft) if ft.is_dir()) { - return None; - } - - if !entry.file_name().to_string_lossy().starts_with(prefix) { - return None; - } - - let exe_path = entry.path().join("pwsh.exe"); - exe_path.exists().then_some(exe_path) - }) - .next() - } - - fn find_pwsh_in_scoop() -> Option { - let pwsh_exe = - PathBuf::from(std::env::var_os("USERPROFILE")?).join("scoop\\shims\\pwsh.exe"); - pwsh_exe.exists().then_some(pwsh_exe) - } - - static SYSTEM_SHELL: LazyLock = LazyLock::new(|| { - let locations = [ - || find_pwsh_in_programfiles(false, false), - || find_pwsh_in_programfiles(true, false), - || find_pwsh_in_msix(false), - || find_pwsh_in_programfiles(false, true), - || find_pwsh_in_msix(true), - || find_pwsh_in_programfiles(true, true), - || find_pwsh_in_scoop(), - || which::which_global("pwsh.exe").ok(), - || which::which_global("powershell.exe").ok(), - ]; - - locations - .into_iter() - .find_map(|f| f()) - .map(|p| p.to_string_lossy().trim().to_owned()) - .inspect(|shell| log::info!("Found powershell in: {}", shell)) - .unwrap_or_else(|| { - log::warn!("Powershell not found, falling back to `cmd`"); - "cmd.exe".to_string() - }) - }); - - (*SYSTEM_SHELL).clone() + #[cfg(not(windows))] + return "cmd.exe".to_string(); } impl fmt::Display for ShellKind {