| 1 | #[derive (Clone, Debug, Default, PartialEq, Eq)] |
| 2 | #[cfg_attr (feature = "serde" , derive(serde::Serialize, serde::Deserialize))] |
| 3 | pub struct Dir { |
| 4 | pub prefix: DirPrefix, |
| 5 | pub salt: String, |
| 6 | pub path: String, |
| 7 | } |
| 8 | |
| 9 | #[derive (Clone, Debug, Default, PartialEq, Eq)] |
| 10 | #[cfg_attr (feature = "serde" , derive(serde::Serialize, serde::Deserialize))] |
| 11 | pub struct CacheDir { |
| 12 | pub prefix: DirPrefix, |
| 13 | pub path: String, |
| 14 | } |
| 15 | |
| 16 | #[derive (Clone, Debug, Default, PartialEq, Eq)] |
| 17 | #[cfg_attr (feature = "serde" , derive(serde::Serialize, serde::Deserialize))] |
| 18 | pub struct Include { |
| 19 | pub prefix: DirPrefix, |
| 20 | pub ignore_missing: bool, |
| 21 | pub path: String, |
| 22 | } |
| 23 | |
| 24 | /// This element contains a directory name where will be mapped as the path 'as-path' in cached information. This is useful if the directory name is an alias (via a bind mount or symlink) to another directory in the system for which cached font information is likely to exist. |
| 25 | |
| 26 | /// 'salt' property affects to determine cache filename as same as [`Dir`] element. |
| 27 | #[derive (Clone, Debug, Default, PartialEq, Eq)] |
| 28 | #[cfg_attr (feature = "serde" , derive(serde::Serialize, serde::Deserialize))] |
| 29 | pub struct RemapDir { |
| 30 | pub prefix: DirPrefix, |
| 31 | pub as_path: String, |
| 32 | pub salt: String, |
| 33 | pub path: String, |
| 34 | } |
| 35 | |
| 36 | #[derive (Clone, Copy, Debug, PartialEq, Eq)] |
| 37 | #[cfg_attr (feature = "serde" , derive(serde::Serialize, serde::Deserialize))] |
| 38 | pub enum DirPrefix { |
| 39 | Default, |
| 40 | Cwd, |
| 41 | Xdg, |
| 42 | Relative, |
| 43 | } |
| 44 | |
| 45 | pub enum PrefixBehavior { |
| 46 | Config, |
| 47 | Cwd, |
| 48 | Xdg, |
| 49 | Relative, |
| 50 | } |
| 51 | |
| 52 | parse_enum! { |
| 53 | DirPrefix, |
| 54 | (Default, "default" ), |
| 55 | (Cwd, "cwd" ), |
| 56 | (Xdg, "xdg" ), |
| 57 | (Relative, "relative" ), |
| 58 | } |
| 59 | |
| 60 | impl Default for DirPrefix { |
| 61 | fn default() -> Self { |
| 62 | DirPrefix::Default |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | /// Get the location to user home directory. |
| 67 | /// |
| 68 | /// This implementation follows `FcConfigHome` function of freedesktop.org's |
| 69 | /// Fontconfig library. |
| 70 | #[allow (unused_mut, clippy::let_and_return)] |
| 71 | fn config_home() -> Result<String, std::env::VarError> { |
| 72 | let mut home: Result = std::env::var(key:"HOME" ); |
| 73 | |
| 74 | #[cfg (target_os = "windows" )] |
| 75 | { |
| 76 | home = home.or_else(|_| std::env::var("USERPROFILE" )); |
| 77 | } |
| 78 | |
| 79 | home |
| 80 | } |
| 81 | |
| 82 | /// Given a relative path to a config file, this function returns |
| 83 | /// the complete file name to load. |
| 84 | /// |
| 85 | /// This is a simplified version of `FcConfigGetFilename` from the Fontconfig |
| 86 | /// library. |
| 87 | fn config_get_file_name(p: &std::path::PathBuf) -> std::path::PathBuf { |
| 88 | if cfg!(target_os = "windows" ) { |
| 89 | // TODO: get config file path properly for Windows |
| 90 | return p.clone(); |
| 91 | } else { |
| 92 | std::path::Path::new("/etc/fonts" ).join(path:p) |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | fn expand_tilde(path: &String) -> std::path::PathBuf { |
| 97 | let parsed_path: &Path = std::path::Path::new(path); |
| 98 | if let Ok(stripped_path: &Path) = parsed_path.strip_prefix(base:"~" ) { |
| 99 | let home: String = config_home().unwrap_or(default:"/" .to_string()); |
| 100 | std::path::Path::new(&home).join(stripped_path) |
| 101 | } else { |
| 102 | parsed_path.into() |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | macro_rules! define_calculate_path { |
| 107 | ($ty:ident, $xdg_env:expr, $xdg_fallback:expr, $default_prefix_behavior:expr) => { |
| 108 | impl $ty { |
| 109 | /// Environment variable name which used `xdg` prefix |
| 110 | pub const XDG_ENV: &'static str = $xdg_env; |
| 111 | /// Fallback path when `XDG_ENV` is not exists |
| 112 | pub const XDG_FALLBACK_PATH: &'static str = $xdg_fallback; |
| 113 | const DEFAULT_PREFIX_BEHAVIOR: PrefixBehavior = $default_prefix_behavior; |
| 114 | |
| 115 | fn get_prefix_behavior(prefix: DirPrefix) -> PrefixBehavior { |
| 116 | match prefix { |
| 117 | DirPrefix::Default => Self::DEFAULT_PREFIX_BEHAVIOR, |
| 118 | DirPrefix::Cwd => PrefixBehavior::Cwd, |
| 119 | DirPrefix::Xdg => PrefixBehavior::Xdg, |
| 120 | DirPrefix::Relative => PrefixBehavior::Relative, |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | /// Calculate actual path |
| 125 | pub fn calculate_path<P: AsRef<std::path::Path> + ?Sized>( |
| 126 | &self, |
| 127 | config_file_path: &P, |
| 128 | ) -> std::path::PathBuf { |
| 129 | let expanded_path = expand_tilde(&self.path); |
| 130 | |
| 131 | if expanded_path.is_absolute() { |
| 132 | return expanded_path; |
| 133 | } |
| 134 | |
| 135 | let prefix = Self::get_prefix_behavior(self.prefix); |
| 136 | |
| 137 | match prefix { |
| 138 | PrefixBehavior::Config => config_get_file_name(&expanded_path), |
| 139 | PrefixBehavior::Cwd => std::path::Path::new("." ).join(expanded_path), |
| 140 | PrefixBehavior::Relative => match config_file_path.as_ref().parent() { |
| 141 | Some(parent) => parent.join(expanded_path), |
| 142 | None => std::path::Path::new("." ).join(expanded_path), |
| 143 | }, |
| 144 | PrefixBehavior::Xdg => { |
| 145 | let xdg_path = |
| 146 | std::env::var($xdg_env).unwrap_or_else(|_| $xdg_fallback.into()); |
| 147 | expand_tilde(&xdg_path).join(expanded_path) |
| 148 | } |
| 149 | } |
| 150 | } |
| 151 | } |
| 152 | }; |
| 153 | } |
| 154 | |
| 155 | define_calculate_path!(Dir, "XDG_DATA_HOME" , "~/.local/share" , PrefixBehavior::Cwd); |
| 156 | define_calculate_path!(CacheDir, "XDG_CACHE_HOME" , "~/.cache" , PrefixBehavior::Cwd); |
| 157 | define_calculate_path!( |
| 158 | Include, |
| 159 | "XDG_CONFIG_HOME" , |
| 160 | "~/.config" , |
| 161 | PrefixBehavior::Config |
| 162 | ); |
| 163 | define_calculate_path!( |
| 164 | RemapDir, |
| 165 | "XDG_CONFIG_HOME" , |
| 166 | "~/.config" , |
| 167 | PrefixBehavior::Cwd |
| 168 | ); |
| 169 | |