# Config Resolution & Priority System ## MangoHud's Config Priority Order (highest to lowest) When MangoHud loads, it resolves configuration from multiple sources. Later sources override earlier ones. **Highest priority wins for any given option.** ``` Priority 5 (HIGHEST) — Environment variable override $MANGOHUD_CONFIG="key=value,key2=value2" Also: $MANGOHUD_CONFIGFILE="/path/to/custom.conf" Priority 4 — App-local config (same directory as the game executable) {game_directory}/MangoHud.conf Priority 3 — Per-app XDG config (named after the process) $XDG_CONFIG_HOME/MangoHud/{appname}.conf (default: ~/.config/MangoHud/{appname}.conf) Priority 2 — Global XDG user config $XDG_CONFIG_HOME/MangoHud/MangoHud.conf (default: ~/.config/MangoHud/MangoHud.conf) Priority 1 (LOWEST) — MangoHud compiled defaults (no file, built into the library) ``` ## Discovery Algorithm for `config::resolver` ``` fn discover() -> Vec: 1. Check environment: a. Read $MANGOHUD_CONFIGFILE — if set and path exists, record as Priority 5b b. Read $MANGOHUD_CONFIG — if set, parse inline key=value pairs as Priority 5a Note: 5a overrides 5b which overrides all file-based configs 2. Determine XDG config home: a. Use $XDG_CONFIG_HOME if set and non-empty b. Otherwise use $HOME/.config c. If neither available: warn and skip file-based discovery 3. Enumerate known config files in priority order: a. {XDG_CONFIG_HOME}/MangoHud/MangoHud.conf (global) b. {XDG_CONFIG_HOME}/MangoHud/*.conf (all per-app configs found) c. Scan common game directories for MangoHud.conf: - $HOME/.steam/steam/steamapps/common/*/ - $HOME/.local/share/Steam/steamapps/common/*/ - $HOME/Games/*/ - $HOME/.var/app/com.valvesoftware.Steam/data/Steam/steamapps/common/*/ (Flatpak Steam) 4. For each discovered config file: - Record: path, source_type, priority_rank, file_exists, last_modified - Parse if exists 5. Build conflict map: For each option key found in more than one layer: - Record which layer provides the winning value - Record which layers are shadowed - Mark as "conflict" in the UI ``` ## ConfigLayer Struct ```rust pub struct ConfigLayer { pub path: Option, // None for env-var inline configs pub source_type: LayerSource, pub priority: u8, // 1=lowest (compiled default) to 5=highest (env) pub exists: bool, pub is_editable: bool, // false for env-var layers pub last_modified: Option, pub config: Option, } pub enum LayerSource { CompiledDefault, GlobalXdg, // ~/.config/MangoHud/MangoHud.conf PerAppXdg(String), // ~/.config/MangoHud/{appname}.conf — stores appname AppLocal(PathBuf), // {game_dir}/MangoHud.conf EnvFile(PathBuf), // $MANGOHUD_CONFIGFILE EnvInline(String), // $MANGOHUD_CONFIG inline value } ``` ## Conflict Detection Rules A **conflict** exists when: - An option is explicitly set in two or more layers with different values. - OR an env var (`$MANGOHUD_CONFIG` or `$MANGOHUD_CONFIGFILE`) is set AND any file-based config also sets the same option — the env always wins but the user may not realize it. A **shadow** occurs when: - A lower-priority layer sets an option that a higher-priority layer also sets. The lower-priority setting is "shadowed" (has no effect at runtime). ## UI: Visual Cascade (CSS Specificity Style) The Conflicts page (`ui/pages/conflicts.rs`) renders a vertical stack of layers, highest priority at top. For each layer: ``` ┌─────────────────────────────────────────────────────────┐ │ 🔴 ENV: $MANGOHUD_CONFIG [not editable]│ │ gpu_stats=0 fps_limit=120 text_color=FF0000 │ ├─────────────────────────────────────────────────────────┤ │ 🟡 Per-App: ~/.config/MangoHud/cs2.conf [Edit] │ │ fps_limit=60 ← SHADOWED by ENV above │ │ gpu_temp=1 cpu_temp=1 ram=1 │ ├─────────────────────────────────────────────────────────┤ │ 🟢 Global: ~/.config/MangoHud/MangoHud.conf [Edit] │ │ fps_limit=0 ← SHADOWED by cs2.conf and ENV │ │ font_size=24 position=top-left background_alpha=0.5 │ └─────────────────────────────────────────────────────────┘ ``` Color coding: - 🔴 Red badge = env var override (cannot edit in app, show value only) - 🟡 Yellow badge = per-app or app-local config - 🟢 Green badge = global config - Grey strikethrough text = shadowed (ineffective) option Clicking an option in any layer: - If editable layer: jumps to that option in the config editor with that layer selected - If env-var layer: shows tooltip explaining how to unset the env var ## Creating New Config Files When user clicks "+ New Config": 1. Ask: Global, Per-App (enter app name), or App-Local (browse for directory)? 2. If Per-App: validate app name (alphanumeric + hyphens/underscores only) 3. Create file with header comment block: ``` ### MangoHud configuration - managed by MangoTune ### Created: {date} ### App: {appname or "global"} ``` 4. Add to resolver's layer stack immediately. 5. Set as the active editing target. ## Config File Write Safety Before writing any config to disk: 1. Run full validation pass — abort if any errors. 2. Create a backup: `{original_path}.mangotune.bak` (overwrite if exists). 3. Write to `{original_path}.mangotune.tmp`. 4. On success: atomically rename tmp → original. 5. On failure: restore from backup, show error toast. 6. Never write a partial/corrupt file.