fix: luminance-aware chrome theming for light themes; serialized settings writes; buffered log flush
- Derive tab-bar/chrome palette by background luminance: light themes keep a near-background bar with black-tinted tab overlays instead of a muddy gray strip; dark themes unchanged - Theme dockview tabs via the group-scoped --dv-*-tab-* vars its own rules consume (they outspecify our .dv-tab rules and leaked abyss navy onto light tabs); bump inactive-tab hover specificity to match - Convert settings dialog + highlight editor hardcoded white text/border tints to color-mix over --chrome-fg so panes stay readable on light themes - commands.ts: per-file log write buffer with a single drain loop per file (burst output coalesces into one appendFile per IO tick, chain no longer grows per logWrite); stop-tail rides the same buffer - settingsStore: serialize all writers through mutateSettings() queue that re-reads latest state per mutation (tray close-action vs settings UI full saves no longer clobber each other) - tests: burst ordering + stop-tail case for the log buffer
This commit is contained in:
1 parent
9e453e272c
commit
b3744b4705
9 files changed
+218
-99
No files matched your search
+32
-17
@@ -159,25 +159,40 @@ export function loadSettings(): AppSettings {
|
||||
}
|
||||
}
|
||||
|
||||
export function saveSettings(next: AppSettings): AppSettings {
|
||||
const merged = deepMerge({
|
||||
terminal: next.terminal,
|
||||
customThemes: next.customThemes,
|
||||
highlightRules: next.highlightRules,
|
||||
system: next.system ?? DEFAULT_SYSTEM
|
||||
}).settings
|
||||
applySystemSettings(merged.system)
|
||||
applyWindowChrome(merged)
|
||||
const pretty = JSON.stringify(merged, null, 2)
|
||||
let settingsQueue: Promise<unknown> = Promise.resolve()
|
||||
|
||||
mkdirSync(app.getPath('userData'), { recursive: true })
|
||||
const path = settingsPath()
|
||||
const tmp = `${path}.tmp`
|
||||
writeFileSync(tmp, pretty, 'utf8')
|
||||
renameSync(tmp, path)
|
||||
/**
|
||||
* Serialize a settings mutation against every other writer. Each queued step
|
||||
* re-reads the file so the mutation applies on top of the latest state — a
|
||||
* full-snapshot save can no longer silently revert a change written between
|
||||
* its read and its write (e.g. tray close-action vs settings UI save).
|
||||
*/
|
||||
export function mutateSettings(mutate: (settings: AppSettings) => AppSettings): Promise<AppSettings> {
|
||||
const run = settingsQueue.then((): AppSettings => {
|
||||
const merged = deepMerge(mutate(loadSettings())).settings
|
||||
applySystemSettings(merged.system)
|
||||
applyWindowChrome(merged)
|
||||
|
||||
broadcast(Ipc.SETTINGS_CHANGED, merged)
|
||||
return merged
|
||||
mkdirSync(app.getPath('userData'), { recursive: true })
|
||||
const path = settingsPath()
|
||||
const tmp = `${path}.tmp`
|
||||
writeFileSync(tmp, JSON.stringify(merged, null, 2), 'utf8')
|
||||
renameSync(tmp, path)
|
||||
|
||||
broadcast(Ipc.SETTINGS_CHANGED, merged)
|
||||
return merged
|
||||
})
|
||||
// Keep the queue alive when a mutation throws; the caller still sees it.
|
||||
settingsQueue = run.then(
|
||||
() => undefined,
|
||||
() => undefined
|
||||
)
|
||||
return run
|
||||
}
|
||||
|
||||
/** Replace the persisted settings with `next` (serialized). */
|
||||
export function saveSettings(next: AppSettings): Promise<AppSettings> {
|
||||
return mutateSettings((current) => ({ ...current, ...next }))
|
||||
}
|
||||
|
||||
export function registerSettingsIpc(): void {
|
||||
|
||||
Reference in new issue
Block a user