feat: add safe calendar import and export

Add explicit noninteractive CLI transfer modes with full event validation, idempotent duplicate handling, collision refusal, atomic import backups, and no-overwrite export creation.

Cover pure merge semantics and end-to-end rollback paths for unsupported content, invalid identities, conflicts, option combinations, and existing destinations.
This commit is contained in:
2026-07-18 09:32:54 +01:00
parent 8b6cf2e877
commit b524e6e33d
11 changed files with 867 additions and 8 deletions

View File

@@ -82,6 +82,25 @@ does not consume the backup. The TUI mutates a copyable in-memory model and
rolls it back if persistence fails. Its bounded undo/redo history contains only
mutations that crossed the persistence boundary successfully.
Explicit CLI import and export reuse the storage parser, safety classification,
validation, and atomic persistence boundary; these workflows do not depend on
the TUI and perform no network access. Import loads and validates both source
and target before staging a target replacement. UIDs in both files must be
non-empty and unique, every interval must be valid, and every component in both
files must be safe to round-trip. Matching UID plus identical fields is an
idempotent duplicate; matching UID with different fields is a collision that
aborts the whole operation. A committed merge writes the exact old target to
`.bak` before atomic replacement. If every source event is already present
exactly, import performs no write and does not alter the backup.
Export accepts only a valid, safely round-trippable source, serializes a
canonical calendar through private staging, and atomically creates a destination
that must not already exist. Destination refusal is part of the
commit boundary, so export never replaces an existing path. Import, export,
demo, non-interactive frame printing, and backup restoration are distinct
top-level application modes; import and export cannot be selected together or
combined with any of the other modes.
The current writer deliberately refuses to mutate an existing file when the
loader encounters information it cannot round-trip, including recurrence
overrides, `RDATE`, custom `VTIMEZONE` definitions, alarms, attendees, unknown

View File

@@ -81,7 +81,7 @@ The full terminal is treated as a responsive canvas:
The first usable foundation supports day and appointment navigation, a
full-frame reader, a read-only 42-day agenda, validated add/edit/delete forms,
and atomic `.ics` writes.
atomic `.ics` writes, and explicit non-interactive calendar import/export.
Dense days keep every appointment keyboard-reachable even when all lines do
not fit in the cell. Unknown or unsupported iCalendar content makes a source
read-only instead of being discarded. Saves reject external changes, retain a
@@ -101,6 +101,27 @@ agenda. Agenda navigation never persists state, and add/edit/delete remain in
the month workflow. The next local-data work adds advanced recurrence overrides
and rule editing.
## Local file interchange
Import and export are explicit command-line workflows. They never contact the
network and do not enter the interactive TUI.
- `nocal --import SOURCE --calendar TARGET` atomically merges events into the
target. Exact same-UID, same-field events are duplicates and are skipped. A
differing same-UID event, an empty or duplicate UID or invalid event interval
in either file, or content in either file that cannot be safely round-tripped
rejects the complete import before the target is written. A successful
merge keeps the target's exact previous bytes as its adjacent `.bak`; a
duplicate-only import leaves both target and backup untouched.
- `nocal --export DESTINATION --calendar SOURCE` validates the source and
atomically creates a canonical calendar. It never overwrites an existing
destination and refuses any source whose events are invalid or that cannot
be safely round-tripped.
The two operations are mutually exclusive and cannot be combined with demo,
frame printing, or backup restoration. These restrictions keep destructive
ambiguity out of automation and make every file-writing mode deliberate.
## Accessibility
- Information is never encoded by color alone.

View File

@@ -12,13 +12,14 @@
- Occurrence-aware appointment search with exact result-to-grid navigation
- Session calendar toggles shared by month rendering, focus, and search
- Read-only 42-day agenda with bounded recurrence and exact return navigation
- Explicit atomic import/export with validation, collision refusal, and backups
- Meson build, Nix development shell, desktop entry, and Hyprland launcher
- Seeded sample data when explicitly requested, never silent data mutation
## 0.1 — complete local calendar
- Advanced recurrence editing, RDATE/overrides, and embedded VTIMEZONE support
- Import/export and configurable week start
- Configurable week start
- Screen-reader-friendly linear view and full Unicode display-width handling
## 0.2 — durable cache and provider boundary