Files
mangotune/docs/plan/config_resolution.md
2026-03-30 23:06:06 -04:00

6.0 KiB

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<ConfigLayer>:

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

pub struct ConfigLayer {
    pub path: Option<PathBuf>,      // 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<SystemTime>,
    pub config: Option<AnnotatedConfig>,
}

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"}
  1. Add to resolver's layer stack immediately.
  2. 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.