feat: support safe recurrence additions

Parse, persist, expand, and round-trip compatible RDATE values while preserving whole-series TUI behavior and conservative rewrite guards.

Verified: normal, warning-as-error, and ASan/UBSan builds pass all 9 suites; storage failure paths preserve calendar and backup bytes; live PTY restores terminal state.
This commit is contained in:
2026-07-18 10:14:53 +01:00
parent 989332ef9a
commit cfca6ab6d0
16 changed files with 498 additions and 69 deletions

View File

@@ -374,7 +374,7 @@ bool EventEditor::validate()
Event candidate = original_;
if (candidate.uid.empty()) candidate.uid = make_uid();
if (candidate.recurrence && all_day_ != candidate.all_day) {
if (is_recurring(candidate) && all_day_ != candidate.all_day) {
return fail(EditorField::all_day,
"Timed/all-day conversion is unavailable for recurring series.");
}
@@ -435,7 +435,7 @@ std::string EventEditor::render(const int requested_width, const int requested_h
std::vector<std::string> lines;
lines.reserve(16);
lines.push_back(top);
const auto heading = editing_ && original_.recurrence
const auto heading = editing_ && is_recurring(original_)
? " NOCAL · EDIT ENTIRE RECURRING SERIES"
: editing_ ? " NOCAL · EDIT APPOINTMENT"
: " NOCAL · NEW APPOINTMENT";