//! Platform path resolution for Zed editor directories. //! //! Resolves configuration and data directories for each Zed release channel //! across Linux, macOS, and Windows. use std::path::PathBuf; /// Zed release channel. Each channel has independent config and data directories. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ZedChannel { Stable, Preview, Nightly, Dev, } impl ZedChannel { /// All known release channels. pub fn all() -> &'static [ZedChannel] { &[ ZedChannel::Stable, ZedChannel::Preview, ZedChannel::Nightly, ZedChannel::Dev, ] } /// Socket/identifier name used in IPC paths. pub fn socket_name(&self) -> &'static str { match self { ZedChannel::Stable => "stable", ZedChannel::Preview => "preview", ZedChannel::Nightly => "nightly", ZedChannel::Dev => "dev", } } /// Display name for the channel. pub fn display_name(&self) -> &'static str { match self { ZedChannel::Stable => "Stable", ZedChannel::Preview => "Preview", ZedChannel::Nightly => "Nightly", ZedChannel::Dev => "Dev", } } } impl std::fmt::Display for ZedChannel { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str(self.display_name()) } } /// Resolve the Zed configuration directory for this platform. /// /// | Platform | Path | /// |----------|------| /// | Linux | `$XDG_CONFIG_HOME/zed` (default: `~/.config/zed`) | /// | macOS | `~/.config/zed` | /// | Windows | `%APPDATA%\Zed` | pub fn zed_config_dir() -> Option { #[cfg(target_os = "macos")] { dirs::home_dir().map(|d| d.join(".config").join("zed")) } #[cfg(target_os = "windows")] { dirs::config_dir().map(|d| d.join("Zed")) } #[cfg(not(any(target_os = "macos", target_os = "windows")))] { dirs::config_dir().map(|d| d.join("zed")) } } /// Resolve the Zed data directory for this platform. /// /// | Platform | Path | /// |----------|------| /// | Linux | `$XDG_DATA_HOME/zed` (default: `~/.local/share/zed`) | /// | macOS | `~/Library/Application Support/Zed` | /// | Windows | `%LOCALAPPDATA%\Zed` | pub fn zed_data_dir() -> Option { #[cfg(target_os = "windows")] { dirs::data_local_dir().map(|d| d.join("Zed")) } #[cfg(not(target_os = "windows"))] { dirs::data_dir().map(|d| d.join("zed")) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_all_channels() { let channels = ZedChannel::all(); assert_eq!(channels.len(), 4); assert!(channels.contains(&ZedChannel::Stable)); assert!(channels.contains(&ZedChannel::Preview)); assert!(channels.contains(&ZedChannel::Nightly)); assert!(channels.contains(&ZedChannel::Dev)); } #[test] fn test_socket_names() { assert_eq!(ZedChannel::Stable.socket_name(), "stable"); assert_eq!(ZedChannel::Preview.socket_name(), "preview"); assert_eq!(ZedChannel::Nightly.socket_name(), "nightly"); assert_eq!(ZedChannel::Dev.socket_name(), "dev"); } #[test] fn test_display_names() { assert_eq!(ZedChannel::Stable.to_string(), "Stable"); assert_eq!(ZedChannel::Dev.to_string(), "Dev"); } #[test] fn test_config_dir_is_some() { // On any supported platform, this should resolve. let dir = zed_config_dir(); assert!(dir.is_some(), "zed_config_dir should resolve on this platform"); let path = dir.unwrap(); let path_str = path.to_string_lossy(); assert!( path_str.contains("zed") || path_str.contains("Zed"), "config dir should contain 'zed': {path_str}" ); } #[test] fn test_data_dir_is_some() { let dir = zed_data_dir(); assert!(dir.is_some(), "zed_data_dir should resolve on this platform"); let path = dir.unwrap(); let path_str = path.to_string_lossy(); assert!( path_str.contains("zed") || path_str.contains("Zed"), "data dir should contain 'zed': {path_str}" ); } }