Try the most specific rule first, not the topmost
File order decided precedence, so a narrow rule had to be written above the broad one it carves an exception out of -- an ordering constraint the file cannot show and the user has to remember. *NIKOLA* below *NIK* silently matched nothing, and a catch-all * could only ever be the last line. Engine.New now sorts once and MatchIndex walks that order: most literal characters first, then fewest *, then account-scoped over unscoped. Literals are what a rule commits to and a * is what it gives up, so a bare * is tried last wherever it sits. The sort is stable, so equally specific rules keep file order and the earlier one wins -- which is all position decides now, and why AppendRule can keep appending without displacing a rule written by hand. The two orders must not be confused: Rules(), Usage and MatchIndex still speak in file positions, because that is what the rules screen numbers and what DeleteRules deletes by. A shadowed rule still reports zero usage, but a zero no longer says anything about where the rule sits. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -23,8 +23,9 @@ const (
|
||||
IndexFile = "index.db"
|
||||
)
|
||||
|
||||
// Rule is one entry in rules.toml. Rules are evaluated in file order and the
|
||||
// first one whose Match (and optional Account) matches wins.
|
||||
// Rule is one entry in rules.toml. The most specific rule that matches wins,
|
||||
// with file order breaking ties between equally specific ones; rules.Engine
|
||||
// owns that ordering.
|
||||
type Rule struct {
|
||||
Match string `toml:"match"`
|
||||
Tag string `toml:"tag"`
|
||||
@@ -126,8 +127,10 @@ func checkTransfer(t Transfer) error {
|
||||
}
|
||||
|
||||
// AppendRule adds a rule to the end of rules.toml, creating the file if it is
|
||||
// not there yet. Appending rather than inserting means an existing rule always
|
||||
// keeps precedence, since the first match wins.
|
||||
// not there yet. Position no longer decides precedence — the most specific rule
|
||||
// wins, see rules.Engine — but it still breaks ties, so appending rather than
|
||||
// inserting keeps a saved rule from displacing an equally specific one the user
|
||||
// wrote by hand.
|
||||
//
|
||||
// The file is rewritten through a temporary file so a failure part-way cannot
|
||||
// leave the user with a truncated config.
|
||||
|
||||
Reference in New Issue
Block a user