Edit a rule from the rules screen
A rule could be written and deleted but never changed, so fixing a glob meant deleting the rule and typing it again -- losing its note, the comments around it, and its position, which still breaks ties between equally specific rules. e now opens the selected rule in the builder and enter rewrites it where it sits. config.ReplaceRule edits rules.toml textually, as deleting does, and keeps the comments above the rule: they say why it is there, which editing its glob rarely changes. The round trip must not lose what the form does not show. The builder has four fields and a Rule has five, so an edit carries the type pattern through untouched and says so under the glob; a type-only rule saves without one. The preview needed the same care in reverse: a working rule's transactions are tagged, so an untagged-only preview would be empty for it. Its own rows are added back, and the ones a narrowed glob stops catching stay on screen marked -- giving one up is the decision being made, and it must not happen silently. The builder and its list shared one return view, so opening the builder from the list left esc pointing back into the form. Each screen now remembers its own way out; transfers had the same trap and the same fix. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -167,12 +167,31 @@ than a `#` comment so `LoadRules` can return it, the builder can write it and
|
||||
the rules screen can show it. It never takes part in matching — `rules.Engine`
|
||||
does not look at it — and it must stay that way.
|
||||
|
||||
**`config.DeleteRules` edits rules.toml textually, never by re-serialising the
|
||||
parsed rules**, because comments and formatting are not recoverable from
|
||||
`[]Rule`. A rule owns the comment lines directly above it; a comment separated
|
||||
by a blank line is a heading for what follows and stays. Both writers go
|
||||
through `writeFileAtomic`, and deletion re-parses the result before replacing
|
||||
the file.
|
||||
**`config.DeleteRules` and `config.ReplaceRule` edit rules.toml textually, never
|
||||
by re-serialising the parsed rules**, because comments and formatting are not
|
||||
recoverable from `[]Rule`. A rule owns the comment lines directly above it, so
|
||||
deleting takes them with it; a comment separated by a blank line is a heading
|
||||
for what follows and stays. Replacing keeps them — they say why the rule is
|
||||
there, which editing its glob rarely changes — and rewrites only the rule's own
|
||||
lines, leaving its *position* alone: position still breaks ties, so a rule that
|
||||
moved could start beating an equally specific one it never used to. Every
|
||||
writer goes through `writeFileAtomic`, and both editors re-parse the result
|
||||
before replacing the file.
|
||||
|
||||
**An edit must not lose what the builder does not show.** The form has four
|
||||
fields and a `Rule` has five, so `saveRule` carries `Type` through from the rule
|
||||
being edited and the form says it is doing so. Nothing may round-trip a rule
|
||||
through those four fields alone — a pattern the user was never shown is not a
|
||||
pattern they chose to remove. A new field on `Rule` needs the same treatment or
|
||||
a field of its own. Covered by `TestRuleEditKeepsTypePattern`.
|
||||
|
||||
**The rule builder's preview is what the rule is judged against, which is not
|
||||
always "what is untagged".** For a new rule those are the same thing. For an
|
||||
edit they are not: the rule's own transactions are tagged, so an untagged-only
|
||||
preview would be empty for a rule that works. `reloadPreviewGroups` adds them
|
||||
back, and `refreshRulePreview` keeps the ones the new glob stops catching on
|
||||
screen marked `−` instead of dropping them silently, because giving one up is
|
||||
the decision being made.
|
||||
|
||||
## Adding a bank parser
|
||||
|
||||
|
||||
Reference in New Issue
Block a user