teksilo-settings — persistent, reactive user preferences for Teksilo.
Two persistence shapes share one storage backbone:
- [
SettingsStore] — dynamic, dotted-key K/V for scalar values (numbers, strings, bools, arrays of those), surfaced asSignal<T>. The QSettings analogue. Struct values aren't supported here because TOML serializes them as tables, indistinguishable from nested key paths; use [SettingsFile<T>] for those instead. - [
SettingsFile<T>] — typed single-struct persistence with migrations. - [
PersistedListModel<T>] — a reactive, [Keyed]-item ordered collection persisted to a single file, merging by op (upsert / remove / clear) rather than by whole-document snapshot — so a peer process's concurrent addition survives. - [
MruList<T>] — generic dedupe + pin + cap list over an app-defined item type implementing [MruEntry]. Apps register their own viaTeksiloAppBuilder::app_state(handle). - [
WindowStateService] — per-window geometry persistence. When registered viaTeksiloAppBuilder::settings(...), everyWindowConfigcarrying anid(...)is automatically restored on creation (sanitized against the current monitor) and recorded on every change byteksilo-app's window manager. No widget-side wiring required.
All disk writes are atomic (write-temp + rename). Every write merges
against the document read fresh off disk under an exclusive lock —
never a blind whole-document overwrite — so two processes sharing a
file (Skribisto's one-process-per-project model shares general.toml,
recents.toml, window_state.toml across every open project) cannot
silently clobber each other. [Reloadable] is the matching read-side
contract: a hook a file-system watcher calls to push a peer's write into
this process's live signals/models — and [SettingsWatcher] +
[SettingsRegistry] are the actual watcher: a notify-based directory
watch (parent-directory, not file, so an atomic rename-over doesn't
invalidate it) plus the path → [Reloadable] lookup a changed-file
event dispatches through. TeksiloAppBuilder::settings(...) wires one
up automatically (opt out via .settings_watch(false)); every service
[SettingsBundle::open] opens is pre-registered into
[OpenedSettings::registry], and application code can register its
own ad hoc SettingsFile / PersistedListModel / MruList handles
into that same registry.
use ;
const FONT_SIZE: =
new;
// Tests / docs use `for_testing(...)` against a tempdir so they
// never touch the user's real config tree. Production apps use
// `AppPaths::new(qualifier, organization, application)`.
let tmp = tempdir.unwrap;
let paths = for_testing;
let store = open.unwrap;
let font_size = store.signal_for;
font_size.set; // persisted on the next debounce tick