From 264f48ae11052d2d6accb8dc356a9e650c607244 Mon Sep 17 00:00:00 2001 From: Kristian Wind Date: Thu, 20 Aug 2026 22:11:01 +0200 Subject: [PATCH] fix(quickadd): "hver anden tirsdag" blev til en dato og to ord i titlen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vendingen er den, folk bruger, og recurrence-pakken har kunnet den siden den blev skrevet — den oversætter "hver anden" til "hver 2." netop for at slippe for at skrive hvert eneste mønster i to udgaver. Sætningen nåede bare aldrig frem til den. Mønsteret i hurtig tilføjelse tog et tal efter "hver", men ikke et ord, så det, der blev givet videre, var "hver anden". Det er ikke en regel. Så blev de to ord stående i titlen, "tirsdag" blev læst som en forfaldsdato, og opgaven gentog sig ikke — uden at noget sagde det. Sløjfen, der prøver sig frem, kunne ikke redde den: den fjerner ord fra enden, én ad gangen, og kan ikke hente et ord, mønsteret aldrig tog med. Fundet af en prøve, jeg skrev til noget andet, hvor jeg brugte vendingen som en selvfølge og opdagede, at den ikke var det. Co-Authored-By: Claude Opus 5 --- internal/quickadd/quickadd.go | 12 ++++++++++- internal/quickadd/quickadd_test.go | 33 ++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/internal/quickadd/quickadd.go b/internal/quickadd/quickadd.go index 6c18b2d..3d8a3eb 100644 --- a/internal/quickadd/quickadd.go +++ b/internal/quickadd/quickadd.go @@ -650,8 +650,18 @@ func pad2(n int) string { // The trailing group is bounded rather than greedy: without a limit, "hver mandag // kl 10 p1" would hand the whole tail to the recurrence parser, which would refuse // all of it and leave the task not repeating at all. +// +// Mellemleddet må være et ord og ikke kun et tal. "hver anden tirsdag" er den måde, +// folk siger det på — recurrence-pakken har oversat "hver anden" til "hver 2." +// siden den blev skrevet — men her stoppede mønsteret efter "anden" og gav den +// sætning videre. Den er ikke en regel, så "hver anden" blev stående i titlen og +// "tirsdag" blev en forfaldsdato. Sløjfen nedenfor kan kun *fjerne* ord fra +// enden; den kan ikke hente et, mønsteret aldrig tog med. +// +// Fundet af en prøve, der brugte vendingen som selvfølgelig og opdagede, at den +// ikke var det. var reRepeat = regexp.MustCompile( - `(?i)(?:^|\s)((?:hver|hvert|every|each)\s+(?:\d+\.?\s+)?[\p{L}]+(?:\s*(?:,|\bog\b|\band\b)\s*[\p{L}]+)*` + + `(?i)(?:^|\s)((?:hver|hvert|every|each)\s+(?:\d+\.?\s+|(?:anden|andet|tredje|fjerde|femte|sjette|other)\s+)?[\p{L}]+(?:\s*(?:,|\bog\b|\band\b)\s*[\p{L}]+)*` + `|hverdage|ugedage|weekdays?|dagligt|daily|ugentligt|weekly|månedligt|maanedligt|monthly|årligt|aarligt|yearly|annually` + `|den\s+\d{1,2}\.?\s+i\s+måneden|den\s+\d{1,2}\.?\s+i\s+maaneden)(?:\s|$)`) diff --git a/internal/quickadd/quickadd_test.go b/internal/quickadd/quickadd_test.go index c6dedde..aacc761 100644 --- a/internal/quickadd/quickadd_test.go +++ b/internal/quickadd/quickadd_test.go @@ -603,3 +603,36 @@ func TestASectionIsWrittenWithASlash(t *testing.T) { } } } + +// "hver anden tirsdag" er den måde, folk siger det på. +// +// recurrence-pakken har oversat "hver anden" til "hver 2." siden den blev skrevet, +// men sætningen nåede aldrig frem til den: mønsteret her tog kun ét ord efter +// "hver", så det, der blev givet videre, var "hver anden" — ikke en regel. Så blev +// de to ord stående i titlen, og "tirsdag" blev til en forfaldsdato. Opgaven +// gentog sig ikke, og der stod ikke noget om det. +// +// Fundet af en prøve, der brugte vendingen som selvfølgelig og opdagede, at den +// ikke var det. +func TestEveryOtherWeekdayIsARepetition(t *testing.T) { + for _, tc := range []struct { + text string + rule string + left string + }{ + {"vande planterne hver anden tirsdag", "FREQ=WEEKLY;BYDAY=TU;INTERVAL=2", "vande planterne"}, + {"vande planterne hver 2. tirsdag", "FREQ=WEEKLY;BYDAY=TU;INTERVAL=2", "vande planterne"}, + {"water the plants every other tuesday", "FREQ=WEEKLY;BYDAY=TU;INTERVAL=2", "water the plants"}, + {"gå tur hver tredje søndag", "FREQ=WEEKLY;BYDAY=SU;INTERVAL=3", "gå tur"}, + // Den, der virkede i forvejen, skal blive ved med at gøre det. + {"tømme opvasker hver mandag", "FREQ=WEEKLY;BYDAY=MO", "tømme opvasker"}, + } { + got := Parse(tc.text, time.Date(2026, 8, 20, 9, 0, 0, 0, time.UTC), "da") + if got.Recurrence != tc.rule { + t.Errorf("%q gav reglen %q, want %q", tc.text, got.Recurrence, tc.rule) + } + if got.Content != tc.left { + t.Errorf("%q efterlod titlen %q, want %q", tc.text, got.Content, tc.left) + } + } +}