Skip to content

feat(calendar): add option to merge duplicate events - #4249

Open
jechton wants to merge 2 commits into
noctalia-dev:mainfrom
jechton:feat/dedupe-calendar-events
Open

feat(calendar): add option to merge duplicate events#4249
jechton wants to merge 2 commits into
noctalia-dev:mainfrom
jechton:feat/dedupe-calendar-events

Conversation

@jechton

@jechton jechton commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a [calendar] option dedupe_events (off by default), that collapses an
event appearing in more than one of your calendars into a single entry. This
covers two calendars in one account that both hold the event as well as the same
calendar reached through two accounts (for example a Google account and a CalDAV
account).

Two events are treated as the same occurrence when their start, end, all-day
flag, and title match. Provider event ids differ between backends and between
calendars, so the visible shape of the occurrence is the identity. Among
duplicates the entry kept is the one that shows the most: more filled-in fields
(color, link, location), then the longer title.

A second commit adds dedupe_ignore_patterns, a list of ECMAScript regexes
(matched case-insensitively). Every match is stripped from a title before the
titles are compared, so two calendars that word the same event slightly
differently (one appending a note in parentheses, say) still merge, and the more
detailed title is the one displayed. Invalid patterns are skipped, the same way
notification_filter.cpp handles a bad content-filter regex.

The merge runs in a new mergeCalendarEvents() helper called from
CalendarService::rebuildSnapshot(), so every calendar surface (control center
tab, desktop widget, calendar view) sees the deduplicated snapshot.

New settings: Settings > Services > Calendar > Merge Duplicate Events, and
Ignore in Title When Merging (shown only while merging is on).

Motivation

When the same calendar is connected through two accounts, or shared into a second
calendar, every event shows up twice in the control center calendar and the
desktop widget. I personally have many duplicate events among my calendars depending on who they're shared with, some with extra data and some without.

Type of Change

  • New feature

Testing

  • just format
  • python3 tools/i18n-check.py - passes
  • ninja -C build-debug event_merge_test config_schema_roundtrip_test - build clean
  • ./build-debug/event_merge_test - passes (8 cases: disabled pass-through, cross-calendar collapse, richest-copy selection, distinct start times, all-day vs timed, ignore-pattern merge to the detailed title, no-pattern separation, invalid-pattern skip)
  • ./build-debug/config_schema_roundtrip_test - passes (fixture updated for the new fields)
  • Ran build and tested settings myself

Manual Coverage

  • Tested on Niri
  • Tested on Hyprland
  • Tested on Sway
  • Tested on another compositor:
  • Tested with different bar positions and density settings
  • Tested at different interface scaling values
  • Tested with multiple monitors

Checklist

  • This PR is ready for review, or it is marked as Draft.
  • I read and followed the relevant guidance in CONTRIBUTING.md.
  • I ran just format with clang-format v22+ installed, or this PR has no code changes.
  • I ran the relevant build or test commands, or explained why they were not run.
  • I self-reviewed the changes.
  • I checked for new warnings or errors.
  • I updated user-facing documentation in docs/user/ when this PR changes documented behavior or configuration, or this PR does not require documentation changes.
  • I added or updated assets/translations/en.json, or this PR adds no new user-facing strings.
  • I did not edit non-English translation files unless this PR is explicitly for translation tooling, an import/export sync, or a maintainer-requested locale change.
  • I used the existing canonical names for config keys, IPC names, paths, and identifiers.

An event that lives in more than one of your calendars (two calendars in
one account, or the same calendar reached through both a Google and a
CalDAV account) is currently shown once per calendar. The new [calendar]
dedupe_events option, off by default, collapses occurrences that share a
title, start, end, and all-day flag into a single entry, keeping the copy
with the most presentation metadata (color, link, location).

Merging happens in a new mergeCalendarEvents() helper called from
CalendarService::rebuildSnapshot(), so every calendar surface (control
center tab, desktop widget, calendar view) sees the deduplicated
snapshot.
The exact-title match misses events that two calendars word differently,
for example when one appends a note in parentheses. dedupe_ignore_patterns
is a list of ECMAScript regexes (case-insensitive); every match is
stripped from a title before events are compared, so those still merge.

The kept copy now also prefers the longer title, so the more detailed
wording is the one displayed. Invalid patterns are skipped, matching how
notification content filters treat a bad regex.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant