Orphaned .backgrounds/ files get tidied — a repoint trims the one it leaves behind, and every open sweeps what got away
Follow-up to d0c5461's .backgrounds/ folder: generating, pasting, or choosing solid now trims the app's own prior file in .backgrounds/ as part of the same write when it repoints or unsets background.image away from it — silent, best-effort, never blocking the gesture that triggered it. A scheduled heal at every board open sweeps whatever that trim declined or missed: any .backgrounds/ file the board's current background.image no longer names, announced with a loss-row notice in the loose-file relocation's own voice. Legacy root-level references are untouched by both paths — the tidy scopes to .backgrounds/ only, since that is the one folder the app can prove it wrote into. Removal is via FileManager.trashItem, matching the attachment-removal precedent (recoverable, never a hard delete). Supersedes applySolidBackground's earlier "facets.png survives on disk" contract for the settled case: the ruling reads "unsets" as one more shape of "repoints away from a .backgrounds/ file", so a settled solid choice now trims the generated picture it displaces, same as switching producers does. The superseded test and doc comment are updated to the new behavior; the echo-window (no-reload-yet) case is unaffected and still leaves the file in place. Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
@@ -96,6 +96,26 @@ enum BoardBackdrop {
|
||||
/// leftover an overwritten `facets.png` already could.
|
||||
static let backgroundsFolderName = ".backgrounds"
|
||||
|
||||
/// **The bare filename `reference` names, when it is a direct child of `.backgrounds/`** — the
|
||||
/// read the orphan tidy needs (01-storage-format.md § Validation and healing, ruled 2026-08-09:
|
||||
/// "Tidy scopes to `.backgrounds/` ONLY … app-written by construction") to tell "one of ours,
|
||||
/// still in service" from everything else a `background.image` could name.
|
||||
///
|
||||
/// `nil` for every reading that is not that one shape, folded together on purpose — a missing
|
||||
/// reference, a legacy bare name at board root, a hand-placed image in a subfolder of its own, a
|
||||
/// reference naming a grandchild of `.backgrounds/` (`.backgrounds/art/x.png`) — because every one
|
||||
/// of those means the same thing to a caller asking "which file in `.backgrounds/` is spoken for
|
||||
/// right now": none of them are, so every file the folder holds is a candidate. The shared
|
||||
/// prefix-and-single-component test is exactly `boardImageName`'s own "only the qualified form
|
||||
/// reads as ours" rule, restated as a pure function so both tidy mechanisms — the in-flow trim and
|
||||
/// the open-time sweep — read it the same way without either owning the other's copy.
|
||||
static func qualifiedBareName(of reference: String?) -> String? {
|
||||
guard let reference, reference.hasPrefix("\(backgroundsFolderName)/") else { return nil }
|
||||
let rest = reference.dropFirst(backgroundsFolderName.count + 1)
|
||||
guard !rest.isEmpty, !rest.contains("/") else { return nil }
|
||||
return String(rest)
|
||||
}
|
||||
|
||||
/// Whether this board paints a background of its own — **the window-chrome predicate**
|
||||
/// (`BoardWindowHost`, `HostedWindowController.setExtendsContentUnderTitlebar`): a board with one
|
||||
/// runs its content under a transparent title bar, and a board without one keeps the standard
|
||||
|
||||
Reference in New Issue
Block a user