Fix --user-data-dir (#44235)

Closes #40067

Release Notes:

- The `--user-data-dir` flag now works on Windows and Linux, as well as
macOS if you pass `--foreground`.

---------

Co-authored-by: Lukas Wirth <me@lukaswirth.dev>
This commit is contained in:
Julia Ryan
2025-12-10 00:42:19 +00:00
committed by GitHub
co-authored by Lukas Wirth
parent 736a712387
commit 4353b8ecd5
2 changed files with 35 additions and 16 deletions
+34 -15
View File
@@ -32,7 +32,7 @@ struct Detect;
trait InstalledApp { trait InstalledApp {
fn zed_version_string(&self) -> String; fn zed_version_string(&self) -> String;
fn launch(&self, ipc_url: String) -> anyhow::Result<()>; fn launch(&self, ipc_url: String, user_data_dir: Option<&str>) -> anyhow::Result<()>;
fn run_foreground( fn run_foreground(
&self, &self,
ipc_url: String, ipc_url: String,
@@ -588,7 +588,7 @@ fn main() -> Result<()> {
if args.foreground { if args.foreground {
app.run_foreground(url, user_data_dir.as_deref())?; app.run_foreground(url, user_data_dir.as_deref())?;
} else { } else {
app.launch(url)?; app.launch(url, user_data_dir.as_deref())?;
sender.join().unwrap()?; sender.join().unwrap()?;
if let Some(handle) = stdin_pipe_handle { if let Some(handle) = stdin_pipe_handle {
handle.join().unwrap()?; handle.join().unwrap()?;
@@ -709,14 +709,18 @@ mod linux {
) )
} }
fn launch(&self, ipc_url: String) -> anyhow::Result<()> { fn launch(&self, ipc_url: String, user_data_dir: Option<&str>) -> anyhow::Result<()> {
let sock_path = paths::data_dir().join(format!( let data_dir = user_data_dir
.map(PathBuf::from)
.unwrap_or_else(|| paths::data_dir().clone());
let sock_path = data_dir.join(format!(
"zed-{}.sock", "zed-{}.sock",
*release_channel::RELEASE_CHANNEL_NAME *release_channel::RELEASE_CHANNEL_NAME
)); ));
let sock = UnixDatagram::unbound()?; let sock = UnixDatagram::unbound()?;
if sock.connect(&sock_path).is_err() { if sock.connect(&sock_path).is_err() {
self.boot_background(ipc_url)?; self.boot_background(ipc_url, user_data_dir)?;
} else { } else {
sock.send(ipc_url.as_bytes())?; sock.send(ipc_url.as_bytes())?;
} }
@@ -742,7 +746,11 @@ mod linux {
} }
impl App { impl App {
fn boot_background(&self, ipc_url: String) -> anyhow::Result<()> { fn boot_background(
&self,
ipc_url: String,
user_data_dir: Option<&str>,
) -> anyhow::Result<()> {
let path = &self.0; let path = &self.0;
match fork::fork() { match fork::fork() {
@@ -756,8 +764,13 @@ mod linux {
if fork::close_fd().is_err() { if fork::close_fd().is_err() {
eprintln!("failed to close_fd: {}", std::io::Error::last_os_error()); eprintln!("failed to close_fd: {}", std::io::Error::last_os_error());
} }
let error = let mut args: Vec<OsString> =
exec::execvp(path.clone(), &[path.as_os_str(), &OsString::from(ipc_url)]); vec![path.as_os_str().to_owned(), OsString::from(ipc_url)];
if let Some(dir) = user_data_dir {
args.push(OsString::from("--user-data-dir"));
args.push(OsString::from(dir));
}
let error = exec::execvp(path.clone(), &args);
// if exec succeeded, we never get here. // if exec succeeded, we never get here.
eprintln!("failed to exec {:?}: {}", path, error); eprintln!("failed to exec {:?}: {}", path, error);
process::exit(1) process::exit(1)
@@ -943,11 +956,14 @@ mod windows {
) )
} }
fn launch(&self, ipc_url: String) -> anyhow::Result<()> { fn launch(&self, ipc_url: String, user_data_dir: Option<&str>) -> anyhow::Result<()> {
if check_single_instance() { if check_single_instance() {
std::process::Command::new(self.0.clone()) let mut cmd = std::process::Command::new(self.0.clone());
.arg(ipc_url) cmd.arg(ipc_url);
.spawn()?; if let Some(dir) = user_data_dir {
cmd.arg("--user-data-dir").arg(dir);
}
cmd.spawn()?;
} else { } else {
unsafe { unsafe {
let pipe = CreateFileW( let pipe = CreateFileW(
@@ -1096,7 +1112,7 @@ mod mac_os {
format!("Zed {} – {}", self.version(), self.path().display(),) format!("Zed {} – {}", self.version(), self.path().display(),)
} }
fn launch(&self, url: String) -> anyhow::Result<()> { fn launch(&self, url: String, user_data_dir: Option<&str>) -> anyhow::Result<()> {
match self { match self {
Self::App { app_bundle, .. } => { Self::App { app_bundle, .. } => {
let app_path = app_bundle; let app_path = app_bundle;
@@ -1146,8 +1162,11 @@ mod mac_os {
format!("Cloning descriptor for file {subprocess_stdout_file:?}") format!("Cloning descriptor for file {subprocess_stdout_file:?}")
})?; })?;
let mut command = std::process::Command::new(executable); let mut command = std::process::Command::new(executable);
let command = command command.env(FORCE_CLI_MODE_ENV_VAR_NAME, "");
.env(FORCE_CLI_MODE_ENV_VAR_NAME, "") if let Some(dir) = user_data_dir {
command.arg("--user-data-dir").arg(dir);
}
command
.stderr(subprocess_stdout_file) .stderr(subprocess_stdout_file)
.stdout(subprocess_stdin_file) .stdout(subprocess_stdin_file)
.arg(url); .arg(url);
+1 -1
View File
@@ -3,7 +3,7 @@ mod zed;
use agent_ui::AgentPanel; use agent_ui::AgentPanel;
use anyhow::{Context as _, Error, Result}; use anyhow::{Context as _, Error, Result};
use clap::{Parser, command}; use clap::Parser;
use cli::FORCE_CLI_MODE_ENV_VAR_NAME; use cli::FORCE_CLI_MODE_ENV_VAR_NAME;
use client::{Client, ProxySettings, UserStore, parse_zed_link}; use client::{Client, ProxySettings, UserStore, parse_zed_link};
use collab_ui::channel_view::ChannelView; use collab_ui::channel_view::ChannelView;