Browse documentation

Calendar in search

v0.9.7

Narrow which calendars search reads, add Directions and Join buttons to event rows, and see a shared event once instead of twice.

Where
  • Settings → Drawer → Calendar → Calendars to search
  • Settings → Drawer → Calendar → Event actions

Drawer search reads every calendar your calendar app has marked visible. Settings → Drawer → Calendar → “Calendars to search” narrows that — useful when a calendar should stay visible in the calendar app but not surface when you’re typing in the drawer. The summary line reads “All calendars,” “No calendars,” or a count like “5 of 8 calendars.”

The picker only lists calendars currently marked visible, and starts with everything ticked — unticking a calendar excludes it from search while leaving it alone everywhere else. A calendar you hide in the calendar app itself stays hidden from search either way, regardless of what’s ticked here. Above five calendars, a “Select all”/“Select none” button appears.

Under the hood

The setting stores which calendars to exclude, not which to include — an empty exclusion set means search everything, so a calendar added to an account later is searched immediately without needing its own entry. The picker inverts this for display, since a ticked box meaning “search this” is what a checkbox is expected to mean. Renaming a calendar loses its exclusion, so a renamed calendar starts being searched again.

Directions and Join on event rows

A calendar row in search or on the drawer’s home surface can carry up to two action buttons: “Directions,” when the event’s location looks like a place, and “Join,” when it carries a known video-meeting link. Settings → Drawer → Calendar → “Event actions” is a multi-choice dialog for the two; Directions is ticked by default, Join is not.

A location that’s nothing but a meeting-service placeholder — the generic text some calendar apps write into the location field for a Teams meeting, for instance — is never treated as a place, so Directions doesn’t open a map on it. Join checks both the location and the description for a recognized meeting link, location first, and only counts a link as a match against a known list of meeting services rather than any web address.

Under the hood

Matching a meeting link checks the host itself — matching it exactly or as a subdomain — rather than searching for the service’s name anywhere in the URL, which is what stops a link like zoom.us.attacker.example or a query string mentioning zoom.us from being treated as a real Zoom link.

One row per event across calendars

An invitation that lands on two calendars in the same account — your own and a shared family calendar, say — is one event, but showed up as two rows before. It now shows once, keeping the copy on your main calendar when there is one, or otherwise the copy on a calendar you own over one only shared with you.

Under the hood
key(event) = (invite_id, start_time)    # start_time keeps recurring instances distinct
sort events by:
    start_time ascending
    is_main_calendar descending         # a copy on your main calendar wins
    calendar_access_level descending    # else, owned beats read-only
    calendar_id ascending               # tiebreak only, for stability
seen = {}
for event in sorted events:
    if event.invite_id is empty:
        keep event                      # no invite id, never merged with anything
    elif key(event) in seen:
        drop event                      # duplicate: another calendar's copy
    else:
        seen.add(key(event))
        keep event

An event with no invite id — a local, unsynced event — is never merged with anything else, even another local event, since treating two blank ids as equal would risk hiding two genuinely different events. A dropped duplicate doesn’t cost a result slot, so a search capped at a fixed number of rows still returns that many distinct events.

Limits

A duplicate that reaches two calendars through some route other than a shared invite — without a shared invite id — still shows twice. Closing that gap would mean matching by title and start time instead, which was tried and rejected: it also catches distinct events that happen to share both, like a recurring meeting name repeated across two projects, and hiding a real event is worse than showing one twice.