From 7741799f78d125641054df53d42bf6641137feda Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 23 Jul 2024 21:43:29 +0530 Subject: [PATCH] Start work on implementing closing of notifications --- docs/desktop-notifications.rst | 2 +- kitty/notify.py | 28 ++++++++++++++++++++-------- kitty_tests/parser.py | 4 ++-- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/docs/desktop-notifications.rst b/docs/desktop-notifications.rst index 56186978e..772872bc3 100644 --- a/docs/desktop-notifications.rst +++ b/docs/desktop-notifications.rst @@ -179,7 +179,7 @@ Key Value Default Description ``p`` One of ``title``, ``title`` Whether the payload is the notification title or body or query. If a ``body``, ``close`` notification has no title, the body will be used as title. Terminal - , ``?`` emulators should ignore payloads of unknown type to allow for future + , ``?`` emulators should ignore payloads of unknown type to allow for future expansion of this protocol. ``o`` One of ``always``, ``always`` When to honor the notification request. ``unfocused`` means when the window diff --git a/kitty/notify.py b/kitty/notify.py index 40e1fffe4..8270a7f04 100644 --- a/kitty/notify.py +++ b/kitty/notify.py @@ -78,6 +78,14 @@ class NotifyImplementation: notify_implementation = NotifyImplementation() +class PayloadType(Enum): + unknown = '' + title = 'title' + body = 'body' + query = '?' + close = 'close' + + class OnlyWhen(Enum): unset = '' always = 'always' @@ -141,7 +149,7 @@ def parse_osc_99(raw: str, log_warnings: bool = True) -> NotificationCommand: cmd = NotificationCommand() metadata, payload = raw.partition(';')[::2] payload_is_encoded = False - payload_type = 'title' + payload_type = PayloadType.title if metadata: for part in metadata.split(':'): try: @@ -151,7 +159,10 @@ def parse_osc_99(raw: str, log_warnings: bool = True) -> NotificationCommand: log_error('Malformed OSC 99: metadata is not key=value pairs') return cmd if k == 'p': - payload_type = v + try: + payload_type = PayloadType(v) + except ValueError: + payload_type = PayloadType.unknown elif k == 'i': cmd.identifier = sanitize_id(v) elif k == 'e': @@ -177,14 +188,15 @@ def parse_osc_99(raw: str, log_warnings: bool = True) -> NotificationCommand: elif k == 'u': with suppress(Exception): cmd.urgency = Urgency(int(v)) - if payload_type == '?': - actions = ','.join(x.name for x in Action) - when = ','.join(x.name for x in OnlyWhen if x.value) + if payload_type is PayloadType.query: + actions = ','.join(x.value for x in Action) + when = ','.join(x.value for x in OnlyWhen if x.value) urgency = ','.join(str(x.value) for x in Urgency) i = f'i={sanitize_id(cmd.identifier or "0")}:' - raise QueryResponse(f'99;{i}p=?;a={actions}:o={when}:u={urgency}') + p = ','.join(x.value for x in PayloadType if x.value) + raise QueryResponse(f'99;{i}p=?;a={actions}:o={when}:u={urgency}:p={p}') - if payload_type in ('body', 'title'): + if payload_type in (PayloadType.title, PayloadType.body): if payload_is_encoded: try: payload = standard_b64decode(payload).decode('utf-8') @@ -192,7 +204,7 @@ def parse_osc_99(raw: str, log_warnings: bool = True) -> NotificationCommand: if log_warnings: log_error('Malformed OSC 99: payload is not base64 encoded UTF-8 text') return NotificationCommand() - if payload_type == 'title': + if payload_type is PayloadType.title: cmd.title = payload else: cmd.body = payload diff --git a/kitty_tests/parser.py b/kitty_tests/parser.py index a6c16a853..c0a15dd11 100644 --- a/kitty_tests/parser.py +++ b/kitty_tests/parser.py @@ -601,11 +601,11 @@ class TestParser(BaseTest): reset() h('i=xyz:p=?') self.assertFalse(notifications) - self.ae(query_responses, ['99;i=xyz:p=?;a=focus,report:o=always,unfocused,invisible:u=0,1,2']) + self.ae(query_responses, ['99;i=xyz:p=?;a=focus,report:o=always,unfocused,invisible:u=0,1,2:p=title,body,?,close']) reset() h('p=?') self.assertFalse(notifications) - self.ae(query_responses, ['99;i=0:p=?;a=focus,report:o=always,unfocused,invisible:u=0,1,2']) + self.ae(query_responses, ['99;i=0:p=?;a=focus,report:o=always,unfocused,invisible:u=0,1,2:p=title,body,?,close']) def test_dcs_codes(self): s = self.create_screen()