From 8a737ebf5d2747873523639108aeff4dfc15c0e5 Mon Sep 17 00:00:00 2001 From: Sturdyfool10 Date: Fri, 8 Aug 2025 15:12:08 -0700 Subject: [PATCH 1/2] Add portable mode to Zed, which allows teams to share preconfigured instances, batteries included --- .cargo/config.toml | 2 + Cargo.toml | 8 ++- crates/paths/src/paths.rs | 117 ++++++++++++++++++++++++++++---------- 3 files changed, 94 insertions(+), 33 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 8db58d2380..f812a52e4e 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -21,6 +21,8 @@ rustflags = [ "target-feature=+crt-static", # This fixes the linking issue when compiling livekit on Windows "-C", "link-arg=-fuse-ld=lld", + "-C", + "target-cpu=x86-64-v4" ] [env] diff --git a/Cargo.toml b/Cargo.toml index 998e727602..923621f669 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -796,9 +796,13 @@ ui_input = { codegen-units = 1 } zed_actions = { codegen-units = 1 } [profile.release] -debug = "limited" -lto = "thin" +debug = false +lto = "fat" codegen-units = 1 +opt-level = 3 +strip = true +overflow-checks = false +panic = "abort" [profile.release.package] zed = { codegen-units = 16 } diff --git a/crates/paths/src/paths.rs b/crates/paths/src/paths.rs index 47a0f12c06..25b2e41e49 100644 --- a/crates/paths/src/paths.rs +++ b/crates/paths/src/paths.rs @@ -6,6 +6,26 @@ use std::sync::OnceLock; pub use util::paths::home_dir; +/// Macro to DRY up portable directory logic. +/// Usage: portable_dir!("dirname", fallback_expr) +#[macro_export] +macro_rules! portable_dir { + ($name:expr, $fallback:expr) => {{ + use std::fs; + if let Ok(exe_path) = std::env::current_exe() { + if let Some(exe_dir) = exe_path.parent() { + let portable_path = exe_dir.join($name); + if fs::metadata(&portable_path) + .map(|m| m.is_dir()) + .unwrap_or(false) + { + return portable_path; + } + } + } + $fallback + }}; +} /// A default editorconfig file name to use when resolving project settings. pub const EDITORCONFIG_NAME: &str = ".editorconfig"; @@ -195,10 +215,30 @@ pub fn crashes_retired_dir() -> &'static Option { CRASHES_RETIRED_DIR.get_or_init(|| crashes_dir().as_ref().map(|dir| dir.join("Retired"))) } -/// Returns the path to the `settings.json` file. +/// Returns the path to the `settings.json` file, preferring a portable ./settings.json next to the executable if present. + pub fn settings_file() -> &'static PathBuf { + use std::fs; + use std::path::PathBuf; + static SETTINGS_FILE: OnceLock = OnceLock::new(); - SETTINGS_FILE.get_or_init(|| config_dir().join("settings.json")) + + SETTINGS_FILE.get_or_init(|| { + // Try portable mode: ./settings.json next to the executable + if let Ok(exe_path) = std::env::current_exe() { + if let Some(exe_dir) = exe_path.parent() { + let portable_path = exe_dir.join("settings.json"); + if fs::metadata(&portable_path) + .map(|m| m.is_file()) + .unwrap_or(false) + { + return portable_path; + } + } + } + // Fallback to config dir + config_dir().join("settings.json") + }) } /// Returns the path to the global settings file. @@ -242,7 +282,7 @@ pub fn debug_scenarios_file() -> &'static PathBuf { /// This is where installed extensions are stored. pub fn extensions_dir() -> &'static PathBuf { static EXTENSIONS_DIR: OnceLock = OnceLock::new(); - EXTENSIONS_DIR.get_or_init(|| data_dir().join("extensions")) + EXTENSIONS_DIR.get_or_init(|| portable_dir!("extensions", data_dir().join("extensions"))) } /// Returns the path to the extensions directory. @@ -250,7 +290,8 @@ pub fn extensions_dir() -> &'static PathBuf { /// This is where installed extensions are stored on a remote. pub fn remote_extensions_dir() -> &'static PathBuf { static EXTENSIONS_DIR: OnceLock = OnceLock::new(); - EXTENSIONS_DIR.get_or_init(|| data_dir().join("remote_extensions")) + EXTENSIONS_DIR + .get_or_init(|| portable_dir!("remote_extensions", data_dir().join("remote_extensions"))) } /// Returns the path to the extensions directory. @@ -258,7 +299,12 @@ pub fn remote_extensions_dir() -> &'static PathBuf { /// This is where installed extensions are stored on a remote. pub fn remote_extensions_uploads_dir() -> &'static PathBuf { static UPLOAD_DIR: OnceLock = OnceLock::new(); - UPLOAD_DIR.get_or_init(|| remote_extensions_dir().join("uploads")) + UPLOAD_DIR.get_or_init(|| { + portable_dir!( + "remote_extensions/uploads", + remote_extensions_dir().join("uploads") + ) + }) } /// Returns the path to the themes directory. @@ -266,13 +312,13 @@ pub fn remote_extensions_uploads_dir() -> &'static PathBuf { /// This is where themes that are not provided by extensions are stored. pub fn themes_dir() -> &'static PathBuf { static THEMES_DIR: OnceLock = OnceLock::new(); - THEMES_DIR.get_or_init(|| config_dir().join("themes")) + THEMES_DIR.get_or_init(|| portable_dir!("themes", config_dir().join("themes"))) } /// Returns the path to the snippets directory. pub fn snippets_dir() -> &'static PathBuf { static SNIPPETS_DIR: OnceLock = OnceLock::new(); - SNIPPETS_DIR.get_or_init(|| config_dir().join("snippets")) + SNIPPETS_DIR.get_or_init(|| portable_dir!("snippets", config_dir().join("snippets"))) } /// Returns the path to the contexts directory. @@ -281,11 +327,13 @@ pub fn snippets_dir() -> &'static PathBuf { pub fn contexts_dir() -> &'static PathBuf { static CONTEXTS_DIR: OnceLock = OnceLock::new(); CONTEXTS_DIR.get_or_init(|| { - if cfg!(target_os = "macos") { - config_dir().join("conversations") - } else { - data_dir().join("conversations") - } + portable_dir!("conversations", { + if cfg!(target_os = "macos") { + config_dir().join("conversations") + } else { + data_dir().join("conversations") + } + }) }) } @@ -295,11 +343,13 @@ pub fn contexts_dir() -> &'static PathBuf { pub fn prompts_dir() -> &'static PathBuf { static PROMPTS_DIR: OnceLock = OnceLock::new(); PROMPTS_DIR.get_or_init(|| { - if cfg!(target_os = "macos") { - config_dir().join("prompts") - } else { - data_dir().join("prompts") - } + portable_dir!("prompts", { + if cfg!(target_os = "macos") { + config_dir().join("prompts") + } else { + data_dir().join("prompts") + } + }) }) } @@ -321,11 +371,13 @@ pub fn prompt_overrides_dir(repo_path: Option<&Path>) -> PathBuf { static PROMPT_TEMPLATES_DIR: OnceLock = OnceLock::new(); PROMPT_TEMPLATES_DIR .get_or_init(|| { - if cfg!(target_os = "macos") { - config_dir().join("prompt_overrides") - } else { - data_dir().join("prompt_overrides") - } + portable_dir!("prompt_overrides", { + if cfg!(target_os = "macos") { + config_dir().join("prompt_overrides") + } else { + data_dir().join("prompt_overrides") + } + }) }) .clone() } @@ -336,11 +388,13 @@ pub fn prompt_overrides_dir(repo_path: Option<&Path>) -> PathBuf { pub fn embeddings_dir() -> &'static PathBuf { static EMBEDDINGS_DIR: OnceLock = OnceLock::new(); EMBEDDINGS_DIR.get_or_init(|| { - if cfg!(target_os = "macos") { - config_dir().join("embeddings") - } else { - data_dir().join("embeddings") - } + portable_dir!("embeddings", { + if cfg!(target_os = "macos") { + config_dir().join("embeddings") + } else { + data_dir().join("embeddings") + } + }) }) } @@ -349,7 +403,7 @@ pub fn embeddings_dir() -> &'static PathBuf { /// This is where language servers are downloaded to for languages built-in to Zed. pub fn languages_dir() -> &'static PathBuf { static LANGUAGES_DIR: OnceLock = OnceLock::new(); - LANGUAGES_DIR.get_or_init(|| data_dir().join("languages")) + LANGUAGES_DIR.get_or_init(|| portable_dir!("languages", data_dir().join("languages"))) } /// Returns the path to the debug adapters directory @@ -365,19 +419,20 @@ pub fn debug_adapters_dir() -> &'static PathBuf { /// This is where agent servers are downloaded to pub fn agent_servers_dir() -> &'static PathBuf { static AGENT_SERVERS_DIR: OnceLock = OnceLock::new(); - AGENT_SERVERS_DIR.get_or_init(|| data_dir().join("agent_servers")) + AGENT_SERVERS_DIR + .get_or_init(|| portable_dir!("agent_servers", data_dir().join("agent_servers"))) } /// Returns the path to the Copilot directory. pub fn copilot_dir() -> &'static PathBuf { static COPILOT_DIR: OnceLock = OnceLock::new(); - COPILOT_DIR.get_or_init(|| data_dir().join("copilot")) + COPILOT_DIR.get_or_init(|| portable_dir!("copilot", data_dir().join("copilot"))) } /// Returns the path to the Supermaven directory. pub fn supermaven_dir() -> &'static PathBuf { static SUPERMAVEN_DIR: OnceLock = OnceLock::new(); - SUPERMAVEN_DIR.get_or_init(|| data_dir().join("supermaven")) + SUPERMAVEN_DIR.get_or_init(|| portable_dir!("supermaven", data_dir().join("supermaven"))) } /// Returns the path to the default Prettier directory. From 196238d03eed8899d4b6413b4ff3dddf92da39b1 Mon Sep 17 00:00:00 2001 From: Sturdyfool10 Date: Fri, 8 Aug 2025 15:17:26 -0700 Subject: [PATCH 2/2] fix errors in inclusion of cargo.toml and .cargo/config.toml --- .cargo/config.toml | 2 -- Cargo.toml | 8 ++------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index f812a52e4e..8db58d2380 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -21,8 +21,6 @@ rustflags = [ "target-feature=+crt-static", # This fixes the linking issue when compiling livekit on Windows "-C", "link-arg=-fuse-ld=lld", - "-C", - "target-cpu=x86-64-v4" ] [env] diff --git a/Cargo.toml b/Cargo.toml index 923621f669..998e727602 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -796,13 +796,9 @@ ui_input = { codegen-units = 1 } zed_actions = { codegen-units = 1 } [profile.release] -debug = false -lto = "fat" +debug = "limited" +lto = "thin" codegen-units = 1 -opt-level = 3 -strip = true -overflow-checks = false -panic = "abort" [profile.release.package] zed = { codegen-units = 16 }