bos-settings 0.4.1: fix broken panels, add breadsearch view

- breadbox panel edited [[contexts]] but breadbox reads [[context]]
  (serde rename mismatch) — panel was always empty and Save appended
  a dead array.
- Packages panel parsed installed.json as a flat map instead of
  unwrapping {"packages": {...}} — always showed one bogus row.
- load_doc silently produced an empty document on any parse error,
  so the next Save could clobber a config file with a syntax typo;
  now backs it up first.
- Hyprland panel opened hyprland.conf/keybinds.conf (BOS ships
  hyprland.lua) via $EDITOR with no terminal (dead click for any TUI
  editor) and defaulted to foot (BOS ships kitty). Now opens
  hyprland.lua and a keybinds cheat sheet via kitty -e $EDITOR.
- New breadsearch view: power (enabled/run-on-battery), compute
  backend (cpu/npu/rocm), index/search settings.
This commit is contained in:
Breadway 2026-07-03 13:31:05 +08:00
parent 4edd356151
commit 81f2f3545a
10 changed files with 176 additions and 31 deletions

View file

@ -12,13 +12,31 @@ use std::path::{Path, PathBuf};
use toml_edit::{value, Array, DocumentMut, Item, Table, Value};
/// Load a TOML file into an editable document. A missing or unparseable file
/// yields an empty document so the UI still renders (with defaults).
/// Load a TOML file into an editable document. A missing file yields an
/// empty document so the UI still renders with defaults — normal for a fresh
/// install. A file that *exists* but fails to parse is far more dangerous:
/// falling back to an empty document there means the next Save (see
/// `save_doc`) overwrites it with only the UI-modelled keys, silently
/// destroying anything else in the file (breadpad's calendar credentials,
/// breadcrumbs' saved network passwords, ...). Back up the unparseable file
/// once before falling back, so a bad edit is always recoverable.
pub fn load_doc(path: &Path) -> DocumentMut {
std::fs::read_to_string(path)
.ok()
.and_then(|s| s.parse::<DocumentMut>().ok())
.unwrap_or_default()
let Ok(text) = std::fs::read_to_string(path) else {
return DocumentMut::default();
};
match text.parse::<DocumentMut>() {
Ok(doc) => doc,
Err(e) => {
let backup = PathBuf::from(format!("{}.bak", path.display()));
eprintln!(
"bos-settings: {} failed to parse ({e}); backed up to {} before falling back to defaults",
path.display(),
backup.display()
);
let _ = std::fs::write(&backup, &text);
DocumentMut::default()
}
}
}
/// Write the document back to disk, creating parent dirs as needed.