Files
nocal/README.md
Bernardo Magri 8b6cf2e877 feat: add bounded agenda view
Add a read-only 42-day occurrence agenda with keyboard navigation, six-week paging, exact return-to-grid focus, search and calendar overlays, and bounded recurrence expansion.

Keep agenda state outside persistence, document month-only mutations, and cover empty windows, filtering, overlays, navigation, rendering, and terminal restoration.
2026-07-18 09:19:01 +01:00

4.1 KiB

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 with month and agenda views, tests, and Linux launch integration. See the product specification, architecture, and roadmap.

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 g to open a read-only 42-day agenda starting on the selected date. Arrows, j/k, or Tab variants choose an occurrence; Enter returns to the month at that exact occurrence. PageUp/PageDown or p/n shift the agenda by 42 days, while Esc or g returns without changing the month selection. Press c to open the calendar picker; arrows or j/k select a calendar and Enter toggles its in-session visibility. 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 / to search titles, descriptions, locations, and calendar IDs. Search results use arrows or j/k; Enter jumps to the exact occurrence and Esc returns to the month. The calendar picker and search are also available over the agenda with c and /. Add, edit, and delete remain month-view workflows. Press ? for help and q to quit.

Build and run

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 expands and safely round-trips a focused iCalendar recurrence subset: daily, weekly, monthly, and yearly rules with interval, count or until, common weekly/monthly/yearly selectors, EXDATE, floating times, UTC, and system IANA TZID names. Recurring instances are individually navigable; edit and delete clearly operate on the entire series.

Search expands recurring matches within five years on either side of the currently selected date. This finite window keeps unbounded recurrence rules responsive while one-time and recurring results share the same chronological result list. Agenda recurrence expansion is bounded to its visible 42-day window. Hidden calendars are excluded consistently from the month grid, agenda, appointment focus, and search. Visibility and agenda position are session-only presentation state; saves always retain events from hidden calendars.

Calendars containing features this version cannot preserve—such as RDATE, detached recurrence overrides, ordinal BYDAY, embedded VTIMEZONE definitions, alarms, or attendees—remain browsable but read-only. This guard prevents a local edit from silently discarding unknown data.

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.