# xdge
[](https://crates.io/crates/xdge)
[](https://docs.rs/xdge)
[](LICENSE-MIT)
A complete, **zero-dependency** implementation of the
[XDG Base Directory Specification v0.8](https://specifications.freedesktop.org/basedir/latest/)
for Linux and Unix systems.
---
## Why xdge?
The XDG Base Directory Specification tells applications *where* to put user
data, config, cache, state, and runtime files — so they don't litter `$HOME`
with hidden dot-directories.
`xdge` implements the full spec, including:
- Correct fallback defaults for every variable
- Silent rejection of **relative paths** (required by the spec)
- `$XDG_RUNTIME_DIR` handling with automatic fallback + stderr warning
- `find_*` helpers to search all directories in precedence order
- `place_*` helpers that auto-create parent dirs with mode `0700`
- `create_*` helpers for all base directories and arbitrary sub-paths
---
## Quick Start
Add to `Cargo.toml`:
```toml
[dependencies]
xdge = "0.1"
```
```rust
use xdge::XdgDirs;
fn main() {
let xdg = XdgDirs::new();
// ── Reading paths ──────────────────────────────────────────────────────
println!("Data home: {}", xdg.data_home().display());
// e.g. ~/.local/share
println!("Config home: {}", xdg.config_home().display());
// e.g. ~/.config
println!("State home: {}", xdg.state_home().display());
// e.g. ~/.local/state
println!("Cache home: {}", xdg.cache_home().display());
// e.g. ~/.cache
println!("User bin: {}", xdg.user_bin_dir().display());
// e.g. ~/.local/bin
println!("Runtime dir: {:?}", xdg.runtime_dir().unwrap());
// e.g. Some("/run/user/1000") or None
// ── Searching ─────────────────────────────────────────────────────────
// Find first matching file across all data directories (user → system):
if let Some(path) = xdg.find_data_file("myapp/icons/logo.png") {
println!("Found data file: {}", path.display());
}
// Find first matching config (user → system):
if let Some(path) = xdg.find_config_file("myapp/settings.toml") {
println!("Found config: {}", path.display());
}
// ── Writing ───────────────────────────────────────────────────────────
// Get path to write a config file (parent dirs created automatically):
let cfg_path = xdg.place_config_file("myapp/settings.toml").unwrap();
std::fs::write(&cfg_path, b"key = \"value\"\n").unwrap();
// Get path to write a data file:
let db_path = xdg.place_data_file("myapp/db.sqlite").unwrap();
println!("Will write DB to {}", db_path.display());
// ── Creating directories ───────────────────────────────────────────────
xdg.create_cache_subdir("myapp/thumbnails").unwrap();
xdg.create_state_subdir("myapp/logs").unwrap();
}
```
---
## XDG Variables Reference
| `$XDG_DATA_HOME` | `$HOME/.local/share` | `data_home()` |
| `$XDG_CONFIG_HOME` | `$HOME/.config` | `config_home()` |
| `$XDG_STATE_HOME` | `$HOME/.local/state` | `state_home()` |
| `$XDG_CACHE_HOME` | `$HOME/.cache` | `cache_home()` |
| `$XDG_RUNTIME_DIR` | *(none — warns if unset)* | `runtime_dir()` |
| `$XDG_DATA_DIRS` | `/usr/local/share:/usr/share` | `data_dirs()` |
| `$XDG_CONFIG_DIRS` | `/etc/xdg` | `config_dirs()` |
| *(user bin)* | `$HOME/.local/bin` | `user_bin_dir()` |
---
## API Summary
### Path accessors
| `data_home()` | `PathBuf` |
| `config_home()` | `PathBuf` |
| `state_home()` | `PathBuf` |
| `cache_home()` | `PathBuf` |
| `user_bin_dir()` | `PathBuf` |
| `runtime_dir()` | `Result<Option<PathBuf>, XdgError>` |
| `runtime_dir_or_fallback()` | `PathBuf` (warns on stderr if unset) |
| `data_dirs()` | `Vec<PathBuf>` |
| `config_dirs()` | `Vec<PathBuf>` |
| `data_search_dirs()` | `Vec<PathBuf>` (home + system) |
| `config_search_dirs()` | `Vec<PathBuf>` (home + system) |
### File-finding helpers
| `find_data_file(relative)` | `Option<PathBuf>` |
| `find_config_file(relative)` | `Option<PathBuf>` |
| `find_all_data_files(relative)` | `Vec<PathBuf>` |
| `find_all_config_files(relative)` | `Vec<PathBuf>` |
### Directory-creation helpers
| `create_data_home()` | `Result<PathBuf, XdgError>` |
| `create_config_home()` | `Result<PathBuf, XdgError>` |
| `create_state_home()` | `Result<PathBuf, XdgError>` |
| `create_cache_home()` | `Result<PathBuf, XdgError>` |
| `create_runtime_dir()` | `Result<PathBuf, XdgError>` |
| `create_data_subdir(sub)` | `Result<PathBuf, XdgError>` |
| `create_config_subdir(sub)` | `Result<PathBuf, XdgError>` |
| `create_state_subdir(sub)` | `Result<PathBuf, XdgError>` |
| `create_cache_subdir(sub)` | `Result<PathBuf, XdgError>` |
| `create_runtime_subdir(sub)` | `Result<PathBuf, XdgError>` |
### File-placement helpers
| `place_data_file(relative)` | `Result<PathBuf, XdgError>` |
| `place_config_file(relative)` | `Result<PathBuf, XdgError>` |
| `place_state_file(relative)` | `Result<PathBuf, XdgError>` |
| `place_cache_file(relative)` | `Result<PathBuf, XdgError>` |
| `place_runtime_file(relative)` | `Result<PathBuf, XdgError>` |
---
## Spec Compliance Notes
- All environment variable values that are **relative paths** are silently
ignored and the spec default is used instead (§3).
- In `$XDG_DATA_DIRS` / `$XDG_CONFIG_DIRS`, individual relative entries are
filtered out; if all entries are relative the full default list is used.
- `$XDG_DATA_HOME` and `$XDG_CONFIG_HOME` take precedence over their
respective `*_DIRS` variables (§3).
- When creating directories, mode `0700` is applied; existing directories are
**not** chmod'd (§4).
- `$XDG_RUNTIME_DIR` is optional; when unset `runtime_dir_or_fallback()`
emits a warning to stderr as required by the spec (§3).
---
## License
- [MIT license](LICENSE-MIT)