Never let a stale settings copy erase a saved choice
The preferences store was loaded once at shell startup, and every save wrote the whole in-memory copy back. Anything that reached the file after startup -- a hand edit, a script, another shell instance flushing during a session handoff -- was erased by the next unrelated save. That is how a display scale set to 1.5 kept coming back as 2: the entry was written, then silently clobbered, and the catch-all auto rule filled the gap. Two halves, either alone insufficient. The store now watches its file and adopts outside writes instead of holding a stale copy over them; and a save merges with what is on disk rather than overwriting it -- keys this shell has set win, keys it has never seen survive. A setting changed anywhere now persists until it is changed again, which is the only behavior a settings file is entitled to have. Claude-Session: https://claude.ai/code/session_01Epx9ZC1gwm81K3jm9x9CKh
This commit is contained in:
@@ -130,6 +130,14 @@ Singleton {
|
||||
printErrors: false
|
||||
atomicWrites: true
|
||||
|
||||
// Adopt writes made from outside the shell -- a hand edit, a script,
|
||||
// a restored snapshot -- instead of holding a stale copy in memory
|
||||
// and silently erasing them at the next save. A change made anywhere
|
||||
// must survive everywhere; the shell is the editor, not the owner.
|
||||
// The shell's own atomic writes land here too and reload as a no-op.
|
||||
watchChanges: true
|
||||
onFileChanged: this.reload()
|
||||
|
||||
onLoaded: root.load()
|
||||
// No file yet is the normal first-run case, not an error.
|
||||
onLoadFailed: root.load()
|
||||
@@ -145,7 +153,27 @@ Singleton {
|
||||
Timer {
|
||||
id: persistTimer
|
||||
interval: 0
|
||||
onTriggered: preferencesFile.setText(JSON.stringify(root.values, null, 2) + "\n")
|
||||
// Merge with what is on disk rather than overwriting it. This model
|
||||
// was loaded at startup; a key written to the file since then -- a
|
||||
// hand edit, a script, another shell instance during a session
|
||||
// handoff -- would otherwise be erased by the next unrelated save,
|
||||
// which is how a setting "changed itself back". Keys this shell has
|
||||
// set win; keys it has never seen survive.
|
||||
onTriggered: {
|
||||
let disk = {};
|
||||
try {
|
||||
const text = preferencesFile.text();
|
||||
if (text && text.trim().length > 0)
|
||||
disk = JSON.parse(text);
|
||||
} catch (error) {
|
||||
// An unreadable file loses the merge, never the write.
|
||||
}
|
||||
if (!disk || typeof disk !== "object")
|
||||
disk = {};
|
||||
const merged = Object.assign({}, disk, root.values);
|
||||
root.values = merged;
|
||||
preferencesFile.setText(JSON.stringify(merged, null, 2) + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
// One-time move from the pre-Stage-1 location inside Quickshell's state
|
||||
|
||||
Reference in New Issue
Block a user