Add --user-data-dir CLI flag and propose renaming support_dir to data_dir (#26886)
This PR introduces support for a `--user-data-dir` CLI flag to override Zed's data directory and proposes renaming `support_dir` to `data_dir` for better cross-platform clarity. It builds on the discussion in #25349 about custom data directories, aiming to provide a flexible cross-platform solution. ### Changes The PR is split into two commits: 1. **[feat(cli): add --user-data-dir to override data directory](28e8889105
)** 2. **[refactor(paths): rename support_dir to data_dir for cross-platform clarity](affd2fc606
)** ### Context Inspired by the need for custom data directories discussed in #25349, this PR provides an immediate implementation in the first commit, while the second commit suggests a naming improvement for broader appeal. @mikayla-maki, I’d appreciate your feedback, especially on the rename proposal, given your involvement in the original discussion! ### Testing - `cargo build ` - `./target/debug/zed --user-data-dir ~/custom-data-dir` Release Notes: - Added --user-data-dir CLI flag --------- Signed-off-by: Marko Kungla <marko.kungla@gmail.com>
This commit is contained in:
parent
d88694f8da
commit
384868e597
@ -491,7 +491,7 @@ impl ThreadsDatabase {
|
|||||||
let database_future = executor
|
let database_future = executor
|
||||||
.spawn({
|
.spawn({
|
||||||
let executor = executor.clone();
|
let executor = executor.clone();
|
||||||
let database_path = paths::support_dir().join("threads/threads-db.1.mdb");
|
let database_path = paths::data_dir().join("threads/threads-db.1.mdb");
|
||||||
async move { ThreadsDatabase::new(database_path, executor) }
|
async move { ThreadsDatabase::new(database_path, executor) }
|
||||||
})
|
})
|
||||||
.then(|result| future::ready(result.map(Arc::new).map_err(Arc::new)))
|
.then(|result| future::ready(result.map(Arc::new).map_err(Arc::new)))
|
||||||
|
@ -16,6 +16,7 @@ pub enum CliRequest {
|
|||||||
wait: bool,
|
wait: bool,
|
||||||
open_new_workspace: Option<bool>,
|
open_new_workspace: Option<bool>,
|
||||||
env: Option<HashMap<String, String>>,
|
env: Option<HashMap<String, String>>,
|
||||||
|
user_data_dir: Option<String>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,11 @@ 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) -> anyhow::Result<()>;
|
||||||
fn run_foreground(&self, ipc_url: String) -> io::Result<ExitStatus>;
|
fn run_foreground(
|
||||||
|
&self,
|
||||||
|
ipc_url: String,
|
||||||
|
user_data_dir: Option<&str>,
|
||||||
|
) -> io::Result<ExitStatus>;
|
||||||
fn path(&self) -> PathBuf;
|
fn path(&self) -> PathBuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +62,13 @@ struct Args {
|
|||||||
/// Create a new workspace
|
/// Create a new workspace
|
||||||
#[arg(short, long, overrides_with = "add")]
|
#[arg(short, long, overrides_with = "add")]
|
||||||
new: bool,
|
new: bool,
|
||||||
|
/// Sets a custom directory for all user data (e.g., database, extensions, logs).
|
||||||
|
/// This overrides the default platform-specific data directory location.
|
||||||
|
/// On macOS, the default is `~/Library/Application Support/Zed`.
|
||||||
|
/// On Linux/FreeBSD, the default is `$XDG_DATA_HOME/zed`.
|
||||||
|
/// On Windows, the default is `%LOCALAPPDATA%\Zed`.
|
||||||
|
#[arg(long, value_name = "DIR")]
|
||||||
|
user_data_dir: Option<String>,
|
||||||
/// The paths to open in Zed (space-separated).
|
/// The paths to open in Zed (space-separated).
|
||||||
///
|
///
|
||||||
/// Use `path:line:column` syntax to open a file at the given line and column.
|
/// Use `path:line:column` syntax to open a file at the given line and column.
|
||||||
@ -135,6 +146,12 @@ fn main() -> Result<()> {
|
|||||||
}
|
}
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
|
// Set custom data directory before any path operations
|
||||||
|
let user_data_dir = args.user_data_dir.clone();
|
||||||
|
if let Some(dir) = &user_data_dir {
|
||||||
|
paths::set_custom_data_dir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||||
let args = flatpak::set_bin_if_no_escape(args);
|
let args = flatpak::set_bin_if_no_escape(args);
|
||||||
|
|
||||||
@ -246,6 +263,7 @@ fn main() -> Result<()> {
|
|||||||
|
|
||||||
let sender: JoinHandle<anyhow::Result<()>> = thread::spawn({
|
let sender: JoinHandle<anyhow::Result<()>> = thread::spawn({
|
||||||
let exit_status = exit_status.clone();
|
let exit_status = exit_status.clone();
|
||||||
|
let user_data_dir_for_thread = user_data_dir.clone();
|
||||||
move || {
|
move || {
|
||||||
let (_, handshake) = server.accept().context("Handshake after Zed spawn")?;
|
let (_, handshake) = server.accept().context("Handshake after Zed spawn")?;
|
||||||
let (tx, rx) = (handshake.requests, handshake.responses);
|
let (tx, rx) = (handshake.requests, handshake.responses);
|
||||||
@ -256,6 +274,7 @@ fn main() -> Result<()> {
|
|||||||
wait: args.wait,
|
wait: args.wait,
|
||||||
open_new_workspace,
|
open_new_workspace,
|
||||||
env,
|
env,
|
||||||
|
user_data_dir: user_data_dir_for_thread,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
while let Ok(response) = rx.recv() {
|
while let Ok(response) = rx.recv() {
|
||||||
@ -291,7 +310,7 @@ fn main() -> Result<()> {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if args.foreground {
|
if args.foreground {
|
||||||
app.run_foreground(url)?;
|
app.run_foreground(url, user_data_dir.as_deref())?;
|
||||||
} else {
|
} else {
|
||||||
app.launch(url)?;
|
app.launch(url)?;
|
||||||
sender.join().unwrap()?;
|
sender.join().unwrap()?;
|
||||||
@ -437,7 +456,7 @@ mod linux {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn launch(&self, ipc_url: String) -> anyhow::Result<()> {
|
fn launch(&self, ipc_url: String) -> anyhow::Result<()> {
|
||||||
let sock_path = paths::support_dir().join(format!("zed-{}.sock", *RELEASE_CHANNEL));
|
let sock_path = paths::data_dir().join(format!("zed-{}.sock", *RELEASE_CHANNEL));
|
||||||
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)?;
|
||||||
@ -447,10 +466,17 @@ mod linux {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_foreground(&self, ipc_url: String) -> io::Result<ExitStatus> {
|
fn run_foreground(
|
||||||
std::process::Command::new(self.0.clone())
|
&self,
|
||||||
.arg(ipc_url)
|
ipc_url: String,
|
||||||
.status()
|
user_data_dir: Option<&str>,
|
||||||
|
) -> io::Result<ExitStatus> {
|
||||||
|
let mut cmd = std::process::Command::new(self.0.clone());
|
||||||
|
cmd.arg(ipc_url);
|
||||||
|
if let Some(dir) = user_data_dir {
|
||||||
|
cmd.arg("--user-data-dir").arg(dir);
|
||||||
|
}
|
||||||
|
cmd.status()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn path(&self) -> PathBuf {
|
fn path(&self) -> PathBuf {
|
||||||
@ -688,12 +714,17 @@ mod windows {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_foreground(&self, ipc_url: String) -> io::Result<ExitStatus> {
|
fn run_foreground(
|
||||||
std::process::Command::new(self.0.clone())
|
&self,
|
||||||
.arg(ipc_url)
|
ipc_url: String,
|
||||||
.arg("--foreground")
|
user_data_dir: Option<&str>,
|
||||||
.spawn()?
|
) -> io::Result<ExitStatus> {
|
||||||
.wait()
|
let mut cmd = std::process::Command::new(self.0.clone());
|
||||||
|
cmd.arg(ipc_url).arg("--foreground");
|
||||||
|
if let Some(dir) = user_data_dir {
|
||||||
|
cmd.arg("--user-data-dir").arg(dir);
|
||||||
|
}
|
||||||
|
cmd.spawn()?.wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn path(&self) -> PathBuf {
|
fn path(&self) -> PathBuf {
|
||||||
@ -875,13 +906,22 @@ mod mac_os {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_foreground(&self, ipc_url: String) -> io::Result<ExitStatus> {
|
fn run_foreground(
|
||||||
|
&self,
|
||||||
|
ipc_url: String,
|
||||||
|
user_data_dir: Option<&str>,
|
||||||
|
) -> io::Result<ExitStatus> {
|
||||||
let path = match self {
|
let path = match self {
|
||||||
Bundle::App { app_bundle, .. } => app_bundle.join("Contents/MacOS/zed"),
|
Bundle::App { app_bundle, .. } => app_bundle.join("Contents/MacOS/zed"),
|
||||||
Bundle::LocalPath { executable, .. } => executable.clone(),
|
Bundle::LocalPath { executable, .. } => executable.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
std::process::Command::new(path).arg(ipc_url).status()
|
let mut cmd = std::process::Command::new(path);
|
||||||
|
cmd.arg(ipc_url);
|
||||||
|
if let Some(dir) = user_data_dir {
|
||||||
|
cmd.arg("--user-data-dir").arg(dir);
|
||||||
|
}
|
||||||
|
cmd.status()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn path(&self) -> PathBuf {
|
fn path(&self) -> PathBuf {
|
||||||
|
@ -53,7 +53,7 @@ impl IndexedDocsProvider for LocalRustdocProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn database_path(&self) -> PathBuf {
|
fn database_path(&self) -> PathBuf {
|
||||||
paths::support_dir().join("docs/rust/rustdoc-db.1.mdb")
|
paths::data_dir().join("docs/rust/rustdoc-db.1.mdb")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn suggest_packages(&self) -> Result<Vec<PackageName>> {
|
async fn suggest_packages(&self) -> Result<Vec<PackageName>> {
|
||||||
@ -144,7 +144,7 @@ impl IndexedDocsProvider for DocsDotRsProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn database_path(&self) -> PathBuf {
|
fn database_path(&self) -> PathBuf {
|
||||||
paths::support_dir().join("docs/rust/docs-rs-db.1.mdb")
|
paths::data_dir().join("docs/rust/docs-rs-db.1.mdb")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn suggest_packages(&self) -> Result<Vec<PackageName>> {
|
async fn suggest_packages(&self) -> Result<Vec<PackageName>> {
|
||||||
|
@ -312,7 +312,7 @@ impl ManagedNodeRuntime {
|
|||||||
|
|
||||||
let version = Self::VERSION;
|
let version = Self::VERSION;
|
||||||
let folder_name = format!("node-{version}-{os}-{arch}");
|
let folder_name = format!("node-{version}-{os}-{arch}");
|
||||||
let node_containing_dir = paths::support_dir().join("node");
|
let node_containing_dir = paths::data_dir().join("node");
|
||||||
let node_dir = node_containing_dir.join(folder_name);
|
let node_dir = node_containing_dir.join(folder_name);
|
||||||
let node_binary = node_dir.join(Self::NODE_PATH);
|
let node_binary = node_dir.join(Self::NODE_PATH);
|
||||||
let npm_file = node_dir.join(Self::NPM_PATH);
|
let npm_file = node_dir.join(Self::NPM_PATH);
|
||||||
@ -498,7 +498,7 @@ impl SystemNodeRuntime {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let scratch_dir = paths::support_dir().join("node");
|
let scratch_dir = paths::data_dir().join("node");
|
||||||
fs::create_dir(&scratch_dir).await.ok();
|
fs::create_dir(&scratch_dir).await.ok();
|
||||||
fs::create_dir(scratch_dir.join("cache")).await.ok();
|
fs::create_dir(scratch_dir.join("cache")).await.ok();
|
||||||
|
|
||||||
|
@ -5,61 +5,109 @@ use std::sync::OnceLock;
|
|||||||
|
|
||||||
pub use util::paths::home_dir;
|
pub use util::paths::home_dir;
|
||||||
|
|
||||||
|
/// A default editorconfig file name to use when resolving project settings.
|
||||||
|
pub const EDITORCONFIG_NAME: &str = ".editorconfig";
|
||||||
|
|
||||||
|
/// A custom data directory override, set only by `set_custom_data_dir`.
|
||||||
|
/// This is used to override the default data directory location.
|
||||||
|
/// The directory will be created if it doesn't exist when set.
|
||||||
|
static CUSTOM_DATA_DIR: OnceLock<PathBuf> = OnceLock::new();
|
||||||
|
|
||||||
|
/// The resolved data directory, combining custom override or platform defaults.
|
||||||
|
/// This is set once and cached for subsequent calls.
|
||||||
|
/// On macOS, this is `~/Library/Application Support/Zed`.
|
||||||
|
/// On Linux/FreeBSD, this is `$XDG_DATA_HOME/zed`.
|
||||||
|
/// On Windows, this is `%LOCALAPPDATA%\Zed`.
|
||||||
|
static CURRENT_DATA_DIR: OnceLock<PathBuf> = OnceLock::new();
|
||||||
|
|
||||||
|
/// The resolved config directory, combining custom override or platform defaults.
|
||||||
|
/// This is set once and cached for subsequent calls.
|
||||||
|
/// On macOS, this is `~/.config/zed`.
|
||||||
|
/// On Linux/FreeBSD, this is `$XDG_CONFIG_HOME/zed`.
|
||||||
|
/// On Windows, this is `%APPDATA%\Zed`.
|
||||||
|
static CONFIG_DIR: OnceLock<PathBuf> = OnceLock::new();
|
||||||
|
|
||||||
/// Returns the relative path to the zed_server directory on the ssh host.
|
/// Returns the relative path to the zed_server directory on the ssh host.
|
||||||
pub fn remote_server_dir_relative() -> &'static Path {
|
pub fn remote_server_dir_relative() -> &'static Path {
|
||||||
Path::new(".zed_server")
|
Path::new(".zed_server")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets a custom directory for all user data, overriding the default data directory.
|
||||||
|
/// This function must be called before any other path operations that depend on the data directory.
|
||||||
|
/// The directory will be created if it doesn't exist.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `dir` - The path to use as the custom data directory. This will be used as the base
|
||||||
|
/// directory for all user data, including databases, extensions, and logs.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A reference to the static `PathBuf` containing the custom data directory path.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if:
|
||||||
|
/// * Called after the data directory has been initialized (e.g., via `data_dir` or `config_dir`)
|
||||||
|
/// * The directory cannot be created
|
||||||
|
pub fn set_custom_data_dir(dir: &str) -> &'static PathBuf {
|
||||||
|
if CURRENT_DATA_DIR.get().is_some() || CONFIG_DIR.get().is_some() {
|
||||||
|
panic!("set_custom_data_dir called after data_dir or config_dir was initialized");
|
||||||
|
}
|
||||||
|
CUSTOM_DATA_DIR.get_or_init(|| {
|
||||||
|
let path = PathBuf::from(dir);
|
||||||
|
std::fs::create_dir_all(&path).expect("failed to create custom data directory");
|
||||||
|
path
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the path to the configuration directory used by Zed.
|
/// Returns the path to the configuration directory used by Zed.
|
||||||
pub fn config_dir() -> &'static PathBuf {
|
pub fn config_dir() -> &'static PathBuf {
|
||||||
static CONFIG_DIR: OnceLock<PathBuf> = OnceLock::new();
|
|
||||||
CONFIG_DIR.get_or_init(|| {
|
CONFIG_DIR.get_or_init(|| {
|
||||||
if cfg!(target_os = "windows") {
|
if let Some(custom_dir) = CUSTOM_DATA_DIR.get() {
|
||||||
return dirs::config_dir()
|
custom_dir.join("config")
|
||||||
|
} else if cfg!(target_os = "windows") {
|
||||||
|
dirs::config_dir()
|
||||||
.expect("failed to determine RoamingAppData directory")
|
.expect("failed to determine RoamingAppData directory")
|
||||||
.join("Zed");
|
.join("Zed")
|
||||||
}
|
} else if cfg!(any(target_os = "linux", target_os = "freebsd")) {
|
||||||
|
if let Ok(flatpak_xdg_config) = std::env::var("FLATPAK_XDG_CONFIG_HOME") {
|
||||||
if cfg!(any(target_os = "linux", target_os = "freebsd")) {
|
|
||||||
return if let Ok(flatpak_xdg_config) = std::env::var("FLATPAK_XDG_CONFIG_HOME") {
|
|
||||||
flatpak_xdg_config.into()
|
flatpak_xdg_config.into()
|
||||||
} else {
|
} else {
|
||||||
dirs::config_dir().expect("failed to determine XDG_CONFIG_HOME directory")
|
dirs::config_dir()
|
||||||
|
.expect("failed to determine XDG_CONFIG_HOME directory")
|
||||||
|
.join("zed")
|
||||||
}
|
}
|
||||||
.join("zed");
|
} else {
|
||||||
|
home_dir().join(".config").join("zed")
|
||||||
}
|
}
|
||||||
|
|
||||||
home_dir().join(".config").join("zed")
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the path to the support directory used by Zed.
|
/// Returns the path to the data directory used by Zed.
|
||||||
pub fn support_dir() -> &'static PathBuf {
|
pub fn data_dir() -> &'static PathBuf {
|
||||||
static SUPPORT_DIR: OnceLock<PathBuf> = OnceLock::new();
|
CURRENT_DATA_DIR.get_or_init(|| {
|
||||||
SUPPORT_DIR.get_or_init(|| {
|
if let Some(custom_dir) = CUSTOM_DATA_DIR.get() {
|
||||||
if cfg!(target_os = "macos") {
|
custom_dir.clone()
|
||||||
return home_dir().join("Library/Application Support/Zed");
|
} else if cfg!(target_os = "macos") {
|
||||||
}
|
home_dir().join("Library/Application Support/Zed")
|
||||||
|
} else if cfg!(any(target_os = "linux", target_os = "freebsd")) {
|
||||||
if cfg!(any(target_os = "linux", target_os = "freebsd")) {
|
if let Ok(flatpak_xdg_data) = std::env::var("FLATPAK_XDG_DATA_HOME") {
|
||||||
return if let Ok(flatpak_xdg_data) = std::env::var("FLATPAK_XDG_DATA_HOME") {
|
|
||||||
flatpak_xdg_data.into()
|
flatpak_xdg_data.into()
|
||||||
} else {
|
} else {
|
||||||
dirs::data_local_dir().expect("failed to determine XDG_DATA_HOME directory")
|
dirs::data_local_dir()
|
||||||
|
.expect("failed to determine XDG_DATA_HOME directory")
|
||||||
|
.join("zed")
|
||||||
}
|
}
|
||||||
.join("zed");
|
} else if cfg!(target_os = "windows") {
|
||||||
}
|
dirs::data_local_dir()
|
||||||
|
|
||||||
if cfg!(target_os = "windows") {
|
|
||||||
return dirs::data_local_dir()
|
|
||||||
.expect("failed to determine LocalAppData directory")
|
.expect("failed to determine LocalAppData directory")
|
||||||
.join("Zed");
|
.join("Zed")
|
||||||
|
} else {
|
||||||
|
config_dir().clone() // Fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
config_dir().clone()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the path to the temp directory used by Zed.
|
/// Returns the path to the temp directory used by Zed.
|
||||||
pub fn temp_dir() -> &'static PathBuf {
|
pub fn temp_dir() -> &'static PathBuf {
|
||||||
static TEMP_DIR: OnceLock<PathBuf> = OnceLock::new();
|
static TEMP_DIR: OnceLock<PathBuf> = OnceLock::new();
|
||||||
@ -96,7 +144,7 @@ pub fn logs_dir() -> &'static PathBuf {
|
|||||||
if cfg!(target_os = "macos") {
|
if cfg!(target_os = "macos") {
|
||||||
home_dir().join("Library/Logs/Zed")
|
home_dir().join("Library/Logs/Zed")
|
||||||
} else {
|
} else {
|
||||||
support_dir().join("logs")
|
data_dir().join("logs")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -104,7 +152,7 @@ pub fn logs_dir() -> &'static PathBuf {
|
|||||||
/// Returns the path to the Zed server directory on this SSH host.
|
/// Returns the path to the Zed server directory on this SSH host.
|
||||||
pub fn remote_server_state_dir() -> &'static PathBuf {
|
pub fn remote_server_state_dir() -> &'static PathBuf {
|
||||||
static REMOTE_SERVER_STATE: OnceLock<PathBuf> = OnceLock::new();
|
static REMOTE_SERVER_STATE: OnceLock<PathBuf> = OnceLock::new();
|
||||||
REMOTE_SERVER_STATE.get_or_init(|| support_dir().join("server_state"))
|
REMOTE_SERVER_STATE.get_or_init(|| data_dir().join("server_state"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the path to the `Zed.log` file.
|
/// Returns the path to the `Zed.log` file.
|
||||||
@ -122,7 +170,7 @@ pub fn old_log_file() -> &'static PathBuf {
|
|||||||
/// Returns the path to the database directory.
|
/// Returns the path to the database directory.
|
||||||
pub fn database_dir() -> &'static PathBuf {
|
pub fn database_dir() -> &'static PathBuf {
|
||||||
static DATABASE_DIR: OnceLock<PathBuf> = OnceLock::new();
|
static DATABASE_DIR: OnceLock<PathBuf> = OnceLock::new();
|
||||||
DATABASE_DIR.get_or_init(|| support_dir().join("db"))
|
DATABASE_DIR.get_or_init(|| data_dir().join("db"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the path to the crashes directory, if it exists for the current platform.
|
/// Returns the path to the crashes directory, if it exists for the current platform.
|
||||||
@ -180,7 +228,7 @@ pub fn debug_tasks_file() -> &'static PathBuf {
|
|||||||
/// This is where installed extensions are stored.
|
/// This is where installed extensions are stored.
|
||||||
pub fn extensions_dir() -> &'static PathBuf {
|
pub fn extensions_dir() -> &'static PathBuf {
|
||||||
static EXTENSIONS_DIR: OnceLock<PathBuf> = OnceLock::new();
|
static EXTENSIONS_DIR: OnceLock<PathBuf> = OnceLock::new();
|
||||||
EXTENSIONS_DIR.get_or_init(|| support_dir().join("extensions"))
|
EXTENSIONS_DIR.get_or_init(|| data_dir().join("extensions"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the path to the extensions directory.
|
/// Returns the path to the extensions directory.
|
||||||
@ -188,7 +236,7 @@ pub fn extensions_dir() -> &'static PathBuf {
|
|||||||
/// This is where installed extensions are stored on a remote.
|
/// This is where installed extensions are stored on a remote.
|
||||||
pub fn remote_extensions_dir() -> &'static PathBuf {
|
pub fn remote_extensions_dir() -> &'static PathBuf {
|
||||||
static EXTENSIONS_DIR: OnceLock<PathBuf> = OnceLock::new();
|
static EXTENSIONS_DIR: OnceLock<PathBuf> = OnceLock::new();
|
||||||
EXTENSIONS_DIR.get_or_init(|| support_dir().join("remote_extensions"))
|
EXTENSIONS_DIR.get_or_init(|| data_dir().join("remote_extensions"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the path to the extensions directory.
|
/// Returns the path to the extensions directory.
|
||||||
@ -222,7 +270,7 @@ pub fn contexts_dir() -> &'static PathBuf {
|
|||||||
if cfg!(target_os = "macos") {
|
if cfg!(target_os = "macos") {
|
||||||
config_dir().join("conversations")
|
config_dir().join("conversations")
|
||||||
} else {
|
} else {
|
||||||
support_dir().join("conversations")
|
data_dir().join("conversations")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -236,7 +284,7 @@ pub fn prompts_dir() -> &'static PathBuf {
|
|||||||
if cfg!(target_os = "macos") {
|
if cfg!(target_os = "macos") {
|
||||||
config_dir().join("prompts")
|
config_dir().join("prompts")
|
||||||
} else {
|
} else {
|
||||||
support_dir().join("prompts")
|
data_dir().join("prompts")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -262,7 +310,7 @@ pub fn prompt_overrides_dir(repo_path: Option<&Path>) -> PathBuf {
|
|||||||
if cfg!(target_os = "macos") {
|
if cfg!(target_os = "macos") {
|
||||||
config_dir().join("prompt_overrides")
|
config_dir().join("prompt_overrides")
|
||||||
} else {
|
} else {
|
||||||
support_dir().join("prompt_overrides")
|
data_dir().join("prompt_overrides")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.clone()
|
.clone()
|
||||||
@ -277,7 +325,7 @@ pub fn embeddings_dir() -> &'static PathBuf {
|
|||||||
if cfg!(target_os = "macos") {
|
if cfg!(target_os = "macos") {
|
||||||
config_dir().join("embeddings")
|
config_dir().join("embeddings")
|
||||||
} else {
|
} else {
|
||||||
support_dir().join("embeddings")
|
data_dir().join("embeddings")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -287,7 +335,7 @@ pub fn embeddings_dir() -> &'static PathBuf {
|
|||||||
/// This is where language servers are downloaded to for languages built-in to Zed.
|
/// This is where language servers are downloaded to for languages built-in to Zed.
|
||||||
pub fn languages_dir() -> &'static PathBuf {
|
pub fn languages_dir() -> &'static PathBuf {
|
||||||
static LANGUAGES_DIR: OnceLock<PathBuf> = OnceLock::new();
|
static LANGUAGES_DIR: OnceLock<PathBuf> = OnceLock::new();
|
||||||
LANGUAGES_DIR.get_or_init(|| support_dir().join("languages"))
|
LANGUAGES_DIR.get_or_init(|| data_dir().join("languages"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the path to the debug adapters directory
|
/// Returns the path to the debug adapters directory
|
||||||
@ -295,31 +343,31 @@ pub fn languages_dir() -> &'static PathBuf {
|
|||||||
/// This is where debug adapters are downloaded to for DAPs that are built-in to Zed.
|
/// This is where debug adapters are downloaded to for DAPs that are built-in to Zed.
|
||||||
pub fn debug_adapters_dir() -> &'static PathBuf {
|
pub fn debug_adapters_dir() -> &'static PathBuf {
|
||||||
static DEBUG_ADAPTERS_DIR: OnceLock<PathBuf> = OnceLock::new();
|
static DEBUG_ADAPTERS_DIR: OnceLock<PathBuf> = OnceLock::new();
|
||||||
DEBUG_ADAPTERS_DIR.get_or_init(|| support_dir().join("debug_adapters"))
|
DEBUG_ADAPTERS_DIR.get_or_init(|| data_dir().join("debug_adapters"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the path to the Copilot directory.
|
/// Returns the path to the Copilot directory.
|
||||||
pub fn copilot_dir() -> &'static PathBuf {
|
pub fn copilot_dir() -> &'static PathBuf {
|
||||||
static COPILOT_DIR: OnceLock<PathBuf> = OnceLock::new();
|
static COPILOT_DIR: OnceLock<PathBuf> = OnceLock::new();
|
||||||
COPILOT_DIR.get_or_init(|| support_dir().join("copilot"))
|
COPILOT_DIR.get_or_init(|| data_dir().join("copilot"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the path to the Supermaven directory.
|
/// Returns the path to the Supermaven directory.
|
||||||
pub fn supermaven_dir() -> &'static PathBuf {
|
pub fn supermaven_dir() -> &'static PathBuf {
|
||||||
static SUPERMAVEN_DIR: OnceLock<PathBuf> = OnceLock::new();
|
static SUPERMAVEN_DIR: OnceLock<PathBuf> = OnceLock::new();
|
||||||
SUPERMAVEN_DIR.get_or_init(|| support_dir().join("supermaven"))
|
SUPERMAVEN_DIR.get_or_init(|| data_dir().join("supermaven"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the path to the default Prettier directory.
|
/// Returns the path to the default Prettier directory.
|
||||||
pub fn default_prettier_dir() -> &'static PathBuf {
|
pub fn default_prettier_dir() -> &'static PathBuf {
|
||||||
static DEFAULT_PRETTIER_DIR: OnceLock<PathBuf> = OnceLock::new();
|
static DEFAULT_PRETTIER_DIR: OnceLock<PathBuf> = OnceLock::new();
|
||||||
DEFAULT_PRETTIER_DIR.get_or_init(|| support_dir().join("prettier"))
|
DEFAULT_PRETTIER_DIR.get_or_init(|| data_dir().join("prettier"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the path to the remote server binaries directory.
|
/// Returns the path to the remote server binaries directory.
|
||||||
pub fn remote_servers_dir() -> &'static PathBuf {
|
pub fn remote_servers_dir() -> &'static PathBuf {
|
||||||
static REMOTE_SERVERS_DIR: OnceLock<PathBuf> = OnceLock::new();
|
static REMOTE_SERVERS_DIR: OnceLock<PathBuf> = OnceLock::new();
|
||||||
REMOTE_SERVERS_DIR.get_or_init(|| support_dir().join("remote_servers"))
|
REMOTE_SERVERS_DIR.get_or_init(|| data_dir().join("remote_servers"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the relative path to a `.zed` folder within a project.
|
/// Returns the relative path to a `.zed` folder within a project.
|
||||||
@ -359,6 +407,3 @@ pub fn local_debug_file_relative_path() -> &'static Path {
|
|||||||
pub fn local_vscode_launch_file_relative_path() -> &'static Path {
|
pub fn local_vscode_launch_file_relative_path() -> &'static Path {
|
||||||
Path::new(".vscode/launch.json")
|
Path::new(".vscode/launch.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A default editorconfig file name to use when resolving project settings.
|
|
||||||
pub const EDITORCONFIG_NAME: &str = ".editorconfig";
|
|
||||||
|
@ -172,6 +172,11 @@ fn fail_to_open_window(e: anyhow::Error, _cx: &mut App) {
|
|||||||
fn main() {
|
fn main() {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
|
// Set custom data directory.
|
||||||
|
if let Some(dir) = &args.user_data_dir {
|
||||||
|
paths::set_custom_data_dir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(all(not(debug_assertions), target_os = "windows"))]
|
#[cfg(all(not(debug_assertions), target_os = "windows"))]
|
||||||
unsafe {
|
unsafe {
|
||||||
use windows::Win32::System::Console::{ATTACH_PARENT_PROCESS, AttachConsole};
|
use windows::Win32::System::Console::{ATTACH_PARENT_PROCESS, AttachConsole};
|
||||||
@ -962,6 +967,14 @@ struct Args {
|
|||||||
/// URLs can either be `file://` or `zed://` scheme, or relative to <https://zed.dev>.
|
/// URLs can either be `file://` or `zed://` scheme, or relative to <https://zed.dev>.
|
||||||
paths_or_urls: Vec<String>,
|
paths_or_urls: Vec<String>,
|
||||||
|
|
||||||
|
/// Sets a custom directory for all user data (e.g., database, extensions, logs).
|
||||||
|
/// This overrides the default platform-specific data directory location.
|
||||||
|
/// On macOS, the default is `~/Library/Application Support/Zed`.
|
||||||
|
/// On Linux/FreeBSD, the default is `$XDG_DATA_HOME/zed`.
|
||||||
|
/// On Windows, the default is `%LOCALAPPDATA%\Zed`.
|
||||||
|
#[arg(long, value_name = "DIR")]
|
||||||
|
user_data_dir: Option<String>,
|
||||||
|
|
||||||
/// Instructs zed to run as a dev server on this machine. (not implemented)
|
/// Instructs zed to run as a dev server on this machine. (not implemented)
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
dev_server_token: Option<String>,
|
dev_server_token: Option<String>,
|
||||||
|
@ -151,7 +151,7 @@ pub fn listen_for_cli_connections(opener: OpenListener) -> Result<()> {
|
|||||||
use release_channel::RELEASE_CHANNEL_NAME;
|
use release_channel::RELEASE_CHANNEL_NAME;
|
||||||
use std::os::unix::net::UnixDatagram;
|
use std::os::unix::net::UnixDatagram;
|
||||||
|
|
||||||
let sock_path = paths::support_dir().join(format!("zed-{}.sock", *RELEASE_CHANNEL_NAME));
|
let sock_path = paths::data_dir().join(format!("zed-{}.sock", *RELEASE_CHANNEL_NAME));
|
||||||
// remove the socket if the process listening on it has died
|
// remove the socket if the process listening on it has died
|
||||||
if let Err(e) = UnixDatagram::unbound()?.connect(&sock_path) {
|
if let Err(e) = UnixDatagram::unbound()?.connect(&sock_path) {
|
||||||
if e.kind() == std::io::ErrorKind::ConnectionRefused {
|
if e.kind() == std::io::ErrorKind::ConnectionRefused {
|
||||||
@ -261,6 +261,7 @@ pub async fn handle_cli_connection(
|
|||||||
wait,
|
wait,
|
||||||
open_new_workspace,
|
open_new_workspace,
|
||||||
env,
|
env,
|
||||||
|
user_data_dir: _, // Ignore user_data_dir
|
||||||
} => {
|
} => {
|
||||||
if !urls.is_empty() {
|
if !urls.is_empty() {
|
||||||
cx.update(|cx| {
|
cx.update(|cx| {
|
||||||
|
@ -130,6 +130,7 @@ fn send_args_to_instance(args: &Args) -> anyhow::Result<()> {
|
|||||||
wait: false,
|
wait: false,
|
||||||
open_new_workspace: None,
|
open_new_workspace: None,
|
||||||
env: None,
|
env: None,
|
||||||
|
user_data_dir: args.user_data_dir.clone(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user