G
YouTube TikTok Games
Skip to content
pimalayaPublic

About

Edit and merge iCalendars as ergonomic TOML

Topics

Resources

Contributing

Security policy

Stars

3 stars

Watchers

1 watching

Forks

Repository files navigation

tCal Documentation Matrix Mastodon Sponsor

Edit and merge iCalendars as ergonomic TOML

tcal edit --event
summary = "Check for tcal issues"
categories = ["pimalaya", "cli"]
url = "https://github.com/pimalaya/tcal/issues"
organizer = "pimalaya.org@posteo.net"
class = "public"
priority = 5
status = "confirmed"
recurrence.frequency = "daily"
recurrence.interval = 1

[[attendee]]
display-name = "Pimalaya"

[[alarm]]
summary = "Go check daily tcal issues"
action = "display"
trigger.min = 5

Output:

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Pimalaya//tcal//EN
BEGIN:VEVENT
UID:1f34e439-ca07-446f-af28-f5b7d3afcfc8
DTSTAMP:20260613T211938Z
SUMMARY:Check for tcal issues
CATEGORIES:pimalaya,cli
URL:https://github.com/pimalaya/tcal/issues
ORGANIZER:mailto:pimalaya.org@posteo.net
CLASS:PUBLIC
PRIORITY:5
STATUS:CONFIRMED
RRULE:FREQ=DAILY;INTERVAL=1
BEGIN:VALARM
SUMMARY:Go check daily tcal issues
ACTION:DISPLAY
TRIGGER:-PT5M
END:VALARM
END:VEVENT
END:VCALENDAR

This repository ships two interfaces: a Rust library projecting an iCalendar to TOML and back, and a CLI editing that projection in $EDITOR, or folding an already edited one back with apply.

Table of contents

Features

  • Projection of a calendar into ergonomic TOML and back, backed by ical-rs.
  • Friendly keys and values: cryptic property names become readable TOML keys, and a closed vocabulary lists what it accepts.
  • Structured recurrence and duration: a rule or a length expands into named parts, with a raw escape hatch for the rest.
  • Discoverable properties: every editable property is printed with an empty value, so the form is its own documentation.
  • Every component type: events, to-dos, journals, free/busy reports and time zones, narrowed to the ones you ask for.
  • Minimal, lossless diffs: only the lines you changed are re-rendered, and what tCal does not model is carried through verbatim.
  • Three-way merge: what two sides both changed comes back as duplicate TOML keys, which do not parse until you decide them.
  • Slim library core: the projection and the merge build without the standard library, the CLI living behind the cli feature, on by default.

RFC coverage

RFC What is covered
5545 iCalendar: events, to-dos, journals, free/busy reports, time zones and alarms, their recurrence rules, durations and attendees

Installation

Pre-built binary

As root:

curl -sSL https://raw.githubusercontent.com/pimalaya/tcal/master/install.sh | sudo sh

As a regular user:

curl -sSL https://raw.githubusercontent.com/pimalaya/tcal/master/install.sh | PREFIX=~/.local sh

These commands install the latest binary from the GitHub releases section.

For a more up-to-date version, check the releases workflow and look for the Artifacts section: those are built from master, with the default cargo features.

Note

Pre-built binaries carry the cli feature and nothing else. If you need a different feature set, use another installation method.

Cargo

The binary lives behind the cli feature, on by default; a library consumer turns it off with default-features = false and pays for none of it:

cargo install --locked tcal

The library alone is a tcal dependency, which pulls in none of that:

cargo add tcal

Nix

If you have the Flakes feature enabled:

nix profile install github:pimalaya/tcal

Or run without installing:

nix run github:pimalaya/tcal -- template < event.ics

Sources

git clone https://github.com/pimalaya/tcal
cd tcal
nix run

Usage

Library

See documentation at docs.rs.

CLI

Run tcal --help for the command tree, and tcal <command> --help for a command's arguments.

A few real command lines:

tcal template                              # a blank, fully documented form
tcal template event.ics                    # an existing calendar as TOML
tcal template - < event.ics                # the same, read from stdin
tcal template --event event.ics            # the event alone, flat at the root
tcal template --event --todo event.ics     # only events and to-dos, as blocks
tcal edit event.ics                        # edit in $EDITOR, written back in place
tcal edit - < event.ics > updated.ics      # edit a stream
tcal edit --output meeting.ics             # start a new event from scratch
tcal edit --editor "code --wait" event.ics # name the editor for one run
tcal apply form.toml event.ics             # fold an edited form back, no editor
tcal template event.ics | edit-somehow | tcal apply - event.ics
tcal merge base.ics local.ics remote.ics --output merged.ics

A type flag narrows the form and nothing else: a type it does not show is left exactly as it was when the result is written back.

The editor is the one --editor names, then $VISUAL, then $EDITOR, and nothing after those: tCal picks none of its own, and says so when neither variable is set. It reads no configuration file, so set them in your shell rc file. The command is spawned on the path of a temporary TOML file it edits in place, so it must block until the edit is done: use code --wait, not code.

A property tcal merge could not settle comes back written once per side, under the same TOML key:

# conflict, keep one line
# summary = "Standup" # base
summary = "Daily standup" # local
summary = "Team standup" # remote

TOML forbids duplicate keys, so an undecided document does not parse and nothing is written. Delete the line you do not want, or replace them all with a value of your own.

What the merge settled on its own is said in a comment at the head of the document instead, since offering a decided thing as a choice asks you to undo what you cannot see the reasons for.

In text, a document goes to stdout as itself, and one written to a file prints nothing. With --json, a command prints one object: {"contents": ...} for a document printed whole, {"path": ..., "size": ...} for one written to a file, or the failure object, whose code names what failed (calendar-unreadable, template-unreadable, collision-undecided, date-unreadable, component-unknown, editor-missing, editor-failed, usage-invalid). tcal json-schema -d <DIR> writes their JSON Schemas. A failure exits 1, a command line the parser refuses exits 2.

Logs go to stderr, so they can be redirected to a file while the command output stays on stdout:

tcal template event.ics --log-level debug 2>/tmp/tcal.log

Use --log-file <PATH> to append them to a file directly. When --log-level is omitted the RUST_LOG environment variable is consulted, and RUST_BACKTRACE=1 adds the full error backtrace.

License

This project is licensed under either of:

Social

Sponsoring

nlnet

Special thanks to the NLnet foundation and the European Commission that have been financially supporting the project for years:

This program is part of Pimalaya, free software funded entirely by grants and donations. If you find it useful, consider sponsoring its development:

GitHub Ko-fi Buy Me a Coffee Liberapay thanks.dev PayPal

About

Edit and merge iCalendars as ergonomic TOML

Topics

Resources

Contributing

Security policy

Stars

3 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Contributors

Languages