Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion doc/source/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ Several options are common to almost all of :program:`khal`'s commands
alarm-symbol
An alarm symbol (alarm clock) if the event has at least one alarm.

alarms-list
A comma-separated list of alarms for the event (e.g., `alarm1@-15m, getready@-1h`).

location
The event location.

Expand Down Expand Up @@ -222,7 +225,7 @@ Several options are common to almost all of :program:`khal`'s commands
end-date-long, end-time, start-full, start-long-full,
start-date-full, start-date-long-full, start-time-full,
end-full, end-long-full, end-date-full, end-date-long-full,
end-time-full, repeat-symbol, location, calendar,
end-time-full, repeat-symbol, alarms-list, location, calendar,
calendar-color, start-style, to-style, end-style,
start-end-time-style, end-necessary, end-necessary-long,
status, cancelled, organizer, url, duration, duration-full,
Expand Down
11 changes: 10 additions & 1 deletion khal/khalendar/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import logging
import os
from collections.abc import Callable
from typing import Any

import icalendar
import icalendar.cal
Expand Down Expand Up @@ -612,7 +613,7 @@ def attributes(
"""
env = env or {}

attributes = {}
attributes: dict[str, Any] = {}
if isinstance(relative_to, tuple):
relative_to_start, relative_to_end = relative_to
else:
Expand Down Expand Up @@ -734,6 +735,14 @@ def attributes(
attributes["repeat-symbol"] = self._recur_str
attributes["repeat-pattern"] = self.recurpattern
attributes["alarm-symbol"] = self._alarm_str
attributes["alarms-list"] = [
{
"delta": alarm[0].total_seconds(),
"description": str(alarm[1]),
"delta-formatted": timedelta2str(alarm[0]),
}
for alarm in self.alarms
]
attributes["status-symbol"] = self._status_str
attributes["partstat-symbol"] = self._partstat_str
attributes["title"] = self.summary
Expand Down
7 changes: 7 additions & 0 deletions khal/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,12 @@ def fmt(rows):
if "calendar-color" in row:
row["calendar-color"] = get_color(row["calendar-color"])

if "alarms-list" in row and isinstance(row["alarms-list"], list):
row["alarms-list"] = ", ".join(
alarm["description"] + "@" + alarm["delta-formatted"]
for alarm in row["alarms-list"]
)

s = format_string.format(**row)

if colors:
Expand Down Expand Up @@ -245,6 +251,7 @@ def fmt(rows):
"end-necessary-long",
"repeat-symbol",
"repeat-pattern",
"alarms-list",
"title",
"organizer",
"description",
Expand Down
26 changes: 26 additions & 0 deletions tests/cli_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,32 @@ def test_list_json(runner):
assert result.output.startswith(expected)


def test_list_alarms(runner):
runner = runner(days=2)
now = dt.datetime.now().strftime("%d.%m.%Y")
runner.invoke(main_khal, f"new {now} 18:00 myevent --alarms -15m,1h".split())
args = ["list", "--format", "{alarms-list}", "--day-format", ""]
result = runner.invoke(main_khal, args)
assert not result.exception
assert result.output.strip() == "@15m, @-1h"


def test_list_alarms_json(runner):
runner = runner()
now = dt.datetime.now().strftime("%d.%m.%Y")
runner.invoke(main_khal, f"new {now} 18:00 myevent --alarms 15m,1h".split())
args = ["list", "--json", "alarms-list"]
result = runner.invoke(main_khal, args)
expected = '[{"alarms-list": [\
{"delta": -900.0, "description": "", "delta-formatted": "-15m"}, \
{"delta": -3600.0, "description": "", "delta-formatted": "-1h"}\
]}]'
print(result.output)
print(expected)
assert not result.exception
assert result.output.startswith(expected)


def test_search(runner):
runner = runner(days=2)
now = dt.datetime.now().strftime("%d.%m.%Y")
Expand Down
22 changes: 22 additions & 0 deletions tests/event_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,28 @@ def test_event_alarm():
assert event.alarms == [(dt.timedelta(-1, 82800), vText("new event"))]


def test_event_alarm_list():
"""test the content of `alarms-list` attribute"""
event = Event.fromString(_get_text("event_dt_simple"), **EVENT_KWARGS)
assert event.alarms == []
event.update_alarms(
[(dt.timedelta(minutes=30), "alarm 1"), (-dt.timedelta(hours=1, minutes=30), "alarm 2")]
)
attributes = event.attributes(dt.date.today())
assert attributes["alarms-list"] == [
{"delta": 1800.0, "description": "alarm 1", "delta-formatted": "30m"},
{"delta": -5400.0, "description": "alarm 2", "delta-formatted": "-1h -30m"},
]


def test_event_no_alarms_list():
"""test that `alarms-list` is empty for an event with no alarms"""
event = Event.fromString(_get_text("event_dt_simple"), **EVENT_KWARGS)
assert event.alarms == []
attributes = event.attributes(dt.date.today())
assert attributes["alarms-list"] == []


def test_event_attendees():
event = Event.fromString(_get_text("event_dt_simple"), **EVENT_KWARGS)
assert event.attendees == ""
Expand Down
Loading