Skip to content

calternal_notes_core::nlp::tasks_recurrence_md

Canonical serializer and deserializer for TaskRecurrence. Issue #430 requires readable repeat: values; RFC 5545 RRULE input and output use the same structured recurrence so imports remain lossless.

Canonical form (ported from iOS ListItemTaskRecurrenceMarkdown.swift:260-321)

Section titled “Canonical form (ported from iOS ListItemTaskRecurrenceMarkdown.swift:260-321)”
freq interval weekdays month_day month output
Daily 1 — — — every day
Daily N — — — every N days
Weekly 1 nil/empty — — every week
Weekly N nil/empty — — every N weeks
Weekly 1 Mon-Fri — — every weekday
Weekly 1 Sat+Sun — — every weekend
Weekly 1 {Mon} — — every Monday
Weekly 1 {Mon,Wed,Fri} — — every Monday Wednesday Friday
Weekly N {Mon} — — every N weeks on Monday
Monthly 1 — 15 — every month on the 15th
Monthly N — 15 — every N months on the 15th
Monthly 1 — nil — every month
Yearly 1 — 15 1 every Jan 15
Yearly N — 15 1 every N years on Jan 15
Yearly 1 — nil/— — every year

recurrence_from_string(&recurrence_to_string(r)) == Some(r.clone()) for every TaskRecurrence that detect_recurrence can produce. The serializer is designed so every output form is parseable by the T4 parser (detect_recurrence reused via recurrence_from_string).

Source: crates/calternal-notes-core/src/nlp/tasks_recurrence_md.rs

pub fn recurrence_from_rrule(value: &str) -> Option<TaskRecurrence>

Parse the supported, canonical RRULE subset into the shared Task value. The caller still validates RFC syntax at the CalDAV boundary (#430, #393).

Source: crates/calternal-notes-core/src/nlp/tasks_recurrence_md.rs:253

pub fn recurrence_from_string(s: &str) -> Option<TaskRecurrence>

Parse a canonical recurrence phrase, including an ISO until date, back to a TaskRecurrence (#430).

Reuses the T4 detect_recurrence parser over a fresh tokenization of the string — no duplicate grammar. Returns None when the string is not recognisable as a recurrence.

Source: crates/calternal-notes-core/src/nlp/tasks_recurrence_md.rs:238

pub fn recurrence_from_string_with_when_done(s: &str) -> Option<(TaskRecurrence, bool)>

recurrence_from_string, but ALSO accepting a trailing task when done suffix (#27 T9, spec A §D.6: every day when done, every 3 days when done, …). v1 only parses/stores/round-trips this modifier VERBATIM (tasks spec §8 D2) — the completion-anchored ROLLING behavior it requests is v1.1 roll-forward engine work (untouched here; nothing acts on the modifier yet). Returns the parsed core recurrence plus whether the suffix was present, so a caller that round-trips the FULL frontmatter string (extract_task_index’s parse_fm_recurrence) can re-attach it verbatim via recurrence_to_string_with_when_done — the suffix is never rejected and never silently stripped.

Source: crates/calternal-notes-core/src/nlp/tasks_recurrence_md.rs:430

pub fn recurrence_to_string(r: &TaskRecurrence) -> String

Serialize a TaskRecurrence to its canonical English phrase and optional ISO end date (#430).

The output is always parseable by recurrence_from_string, giving the round-trip invariant:

recurrence_from_string(&recurrence_to_string(r)) == Some(r.clone())

(within the value shapes that detect_recurrence can produce).

Ported from ListItemTaskRecurrenceMarkdown.recurrencePhrase (Swift ListItemTaskRecurrenceMarkdown.swift:260-321).

Source: crates/calternal-notes-core/src/nlp/tasks_recurrence_md.rs:138

pub fn recurrence_to_string_with_when_done(r: &TaskRecurrence, when_done: bool) -> String

Companion to [recurrence_from_string_with_when_done]: canonicalize the core recurrence via recurrence_to_string, then re-append when done verbatim when when_done is set.

Source: crates/calternal-notes-core/src/nlp/tasks_recurrence_md.rs:438