@@ -11,6 +11,41 @@ use util::rel_path::RelPath;
/// A default editorconfig file name to use when resolving project settings.
pub const EDITORCONFIG_NAME: &str = ".editorconfig";
+/// The application name, used to derive platform-specific data, config, cache,
+/// and state directory paths.
+///
+/// Forks should change this to avoid colliding with Zed's user data.
+pub const APP_NAME: &str = "Zed";
+
+/// Lowercased form of [`APP_NAME`], for use in XDG-style paths on
+/// Linux/FreeBSD and the macOS `~/.config` fallback.
+pub const APP_NAME_LOWERCASE: &str = {
+ assert!(!APP_NAME.is_empty(), "APP_NAME must not be empty");
+ assert!(APP_NAME.as_bytes().is_ascii(), "APP_NAME must be ASCII");
+ const BYTES: [u8; APP_NAME.len()] = {
+ let mut bytes = [0u8; APP_NAME.len()];
+ let mut i = 0;
+ while i < APP_NAME.len() {
+ assert!(
+ APP_NAME.as_bytes()[i] != b'/' && APP_NAME.as_bytes()[i] != b'\\',
+ "APP_NAME must not contain path separators",
+ );
+ assert!(
+ APP_NAME.as_bytes()[i] >= 0x20,
+ "APP_NAME must not contain control characters"
+ );
+ bytes[i] = APP_NAME.as_bytes()[i];
+ i += 1;
+ }
+ bytes.make_ascii_lowercase();
+ bytes
+ };
+ match std::str::from_utf8(&BYTES) {
+ Ok(s) => s,
+ Err(_) => unreachable!(),
+ }
+};
+
/// 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.
@@ -91,16 +126,16 @@ pub fn config_dir() -> &'static PathBuf {
} else if cfg!(target_os = "windows") {
dirs::config_dir()
.expect("failed to determine RoamingAppData directory")
- .join("Zed")
+ .join(APP_NAME)
} else if cfg!(any(target_os = "linux", target_os = "freebsd")) {
if let Ok(flatpak_xdg_config) = std::env::var("FLATPAK_XDG_CONFIG_HOME") {
flatpak_xdg_config.into()
} else {
dirs::config_dir().expect("failed to determine XDG_CONFIG_HOME directory")
}
- .join("zed")
+ .join(APP_NAME_LOWERCASE)
} else {
- home_dir().join(".config").join("zed")
+ home_dir().join(".config").join(APP_NAME_LOWERCASE)
}
})
}
@@ -111,18 +146,20 @@ pub fn data_dir() -> &'static PathBuf {
if let Some(custom_dir) = CUSTOM_DATA_DIR.get() {
custom_dir.clone()
} else if cfg!(target_os = "macos") {
- home_dir().join("Library/Application Support/Zed")
+ home_dir()
+ .join("Library/Application Support")
+ .join(APP_NAME)
} else if cfg!(any(target_os = "linux", target_os = "freebsd")) {
if let Ok(flatpak_xdg_data) = std::env::var("FLATPAK_XDG_DATA_HOME") {
flatpak_xdg_data.into()
} else {
dirs::data_local_dir().expect("failed to determine XDG_DATA_HOME directory")
}
- .join("zed")
+ .join(APP_NAME_LOWERCASE)
} else if cfg!(target_os = "windows") {
dirs::data_local_dir()
.expect("failed to determine LocalAppData directory")
- .join("Zed")
+ .join(APP_NAME)
} else {
config_dir().clone() // Fallback
}
@@ -133,7 +170,7 @@ pub fn state_dir() -> &'static PathBuf {
static STATE_DIR: OnceLock<PathBuf> = OnceLock::new();
STATE_DIR.get_or_init(|| {
if cfg!(target_os = "macos") {
- return home_dir().join(".local").join("state").join("Zed");
+ return home_dir().join(".local").join("state").join(APP_NAME);
}
if cfg!(any(target_os = "linux", target_os = "freebsd")) {
@@ -142,12 +179,12 @@ pub fn state_dir() -> &'static PathBuf {
} else {
dirs::state_dir().expect("failed to determine XDG_STATE_HOME directory")
}
- .join("zed");
+ .join(APP_NAME_LOWERCASE);
} else {
// Windows
return dirs::data_local_dir()
.expect("failed to determine LocalAppData directory")
- .join("Zed");
+ .join(APP_NAME);
}
})
}
@@ -159,13 +196,13 @@ pub fn temp_dir() -> &'static PathBuf {
if cfg!(target_os = "macos") {
return dirs::cache_dir()
.expect("failed to determine cachesDirectory directory")
- .join("Zed");
+ .join(APP_NAME);
}
if cfg!(target_os = "windows") {
return dirs::cache_dir()
.expect("failed to determine LocalAppData directory")
- .join("Zed");
+ .join(APP_NAME);
}
if cfg!(any(target_os = "linux", target_os = "freebsd")) {
@@ -174,10 +211,10 @@ pub fn temp_dir() -> &'static PathBuf {
} else {
dirs::cache_dir().expect("failed to determine XDG_CACHE_HOME directory")
}
- .join("zed");
+ .join(APP_NAME_LOWERCASE);
}
- home_dir().join(".cache").join("zed")
+ home_dir().join(".cache").join(APP_NAME_LOWERCASE)
})
}
@@ -192,7 +229,7 @@ pub fn logs_dir() -> &'static PathBuf {
static LOGS_DIR: OnceLock<PathBuf> = OnceLock::new();
LOGS_DIR.get_or_init(|| {
if cfg!(target_os = "macos") {
- home_dir().join("Library/Logs/Zed")
+ home_dir().join("Library/Logs").join(APP_NAME)
} else {
data_dir().join("logs")
}
@@ -208,13 +245,13 @@ pub fn remote_server_state_dir() -> &'static PathBuf {
/// Returns the path to the `Zed.log` file.
pub fn log_file() -> &'static PathBuf {
static LOG_FILE: OnceLock<PathBuf> = OnceLock::new();
- LOG_FILE.get_or_init(|| logs_dir().join("Zed.log"))
+ LOG_FILE.get_or_init(|| logs_dir().join(format!("{}.log", APP_NAME)))
}
/// Returns the path to the `Zed.log.old` file.
pub fn old_log_file() -> &'static PathBuf {
static OLD_LOG_FILE: OnceLock<PathBuf> = OnceLock::new();
- OLD_LOG_FILE.get_or_init(|| logs_dir().join("Zed.log.old"))
+ OLD_LOG_FILE.get_or_init(|| logs_dir().join(format!("{}.log.old", APP_NAME)))
}
/// Returns the path to the database directory.
@@ -4,6 +4,16 @@
mod reliability;
mod zed;
+// Ensure the binary name stays in sync with APP_NAME so that the paths used
+// at runtime (data dir, config dir, etc.) match what the binary is called.
+const _: () = assert!(
+ paths::APP_NAME_LOWERCASE
+ .as_bytes()
+ .eq_ignore_ascii_case(env!("CARGO_BIN_NAME").as_bytes()),
+ "paths::APP_NAME_LOWERCASE must match the binary name. \
+ Forks: update APP_NAME in crates/paths/src/paths.rs when renaming the binary.",
+);
+
use agent::{SharedThread, ThreadStore};
use agent_client_protocol::schema as acp;
use agent_ui::AgentPanel;