# Nocal Nocal is a fast, local-first C++20 month calendar designed for the Linux terminal and Hyprland. It presents appointments inside a six-week month grid and inherits its colors from your terminal theme. This repository currently contains the first local-calendar vertical slice: date/domain logic, guarded atomic iCalendar persistence, add/edit/delete forms, a responsive ANSI terminal UI, tests, and Linux launch integration. See [the product specification](docs/PRODUCT.md), [architecture](docs/ARCHITECTURE.md), and [roadmap](docs/ROADMAP.md). ## Controls Use arrow keys or `h j k l` to move, `PageUp`/`PageDown` or `p`/`n` to change month, and `t` for today. On a day with appointments, `Tab` and `Shift-Tab` move focus through them and `Enter` opens the appointment reader. In the reader, arrows/Vim keys or Tab variants browse the day's appointments and `Esc` returns to the month. Press `a` to add an appointment. Focus an appointment and press `e` to edit it or `d` to delete it. Forms use `Tab` and `Shift-Tab` (or arrows) between fields, `Space` for the all-day toggle, `Ctrl-S` to save, and `Esc` to cancel. Back in the calendar, `u` undoes the last successful mutation and `Ctrl-R` redoes it. Press `?` for help and `q` to quit. ## Build and run ```sh nix-shell --run 'meson setup build && meson compile -C build' ./build/nocal --demo ``` Run the tests with `meson test -C build --print-errorlogs`. Nocal reads `$XDG_DATA_HOME/nocal/calendar.ics` by default (falling back to `~/.local/share/nocal/calendar.ics`), or accepts another `.ics` path as its positional argument. `--demo` adds a few unsaved sample appointments and `--print` emits a non-interactive frame. Nocal will not rewrite a calendar containing iCalendar data this version cannot preserve, such as recurrence rules, alarms, attendees, or `TZID` parameters. The calendar remains browsable, while mutation attempts explain that it is read-only. This guard prevents a local edit from silently discarding unknown data until those features are represented by the domain model. Every replacement checks that the source has not changed since it was loaded. If another Nocal instance or an external editor changes the file, the mutation is rejected and the in-memory change is rolled back. Successful replacements retain the immediately previous bytes as `calendar.ics.bak`. Run `nocal --restore-backup [CALENDAR.ics]` for an explicit, atomic recovery; the backup itself is kept so recovery can be repeated. For a popup calendar binding and version-specific Hyprland rules, see [Hyprland integration](docs/HYPRLAND.md).