xdge 0.1.0

A complete, zero-dependency implementation of the XDG Base Directory Specification (v0.8) for Linux and Unix systems.
Documentation
# xdge

[![Crates.io](https://img.shields.io/crates/v/xdge.svg)](https://crates.io/crates/xdge)
[![docs.rs](https://docs.rs/xdge/badge.svg)](https://docs.rs/xdge)
[![License](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)](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

| Variable            | Default                       | Method                    |
|---------------------|-------------------------------|---------------------------|
| `$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
| Method                    | Returns                                  |
|---------------------------|------------------------------------------|
| `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
| Method                                  | Returns              |
|-----------------------------------------|----------------------|
| `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
| Method                              | Returns                        |
|-------------------------------------|--------------------------------|
| `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
| Method                              | Returns                        |
|-------------------------------------|--------------------------------|
| `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