Have close notifications indicate when notification is not found

This commit is contained in:
Kovid Goyal 2024-07-25 07:58:17 +05:30
parent 095e1917c1
commit 1c9d9e394c
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
4 changed files with 30 additions and 17 deletions

View file

@ -110,18 +110,16 @@ notification when closing succeeds, send the following instead::
Then, the terminal will respond with::
<OSC> i=<notification id> : p=close ; <terminator>
<OSC> i=<notification id> : p=close ; <terminator> # notification was closed
or
<OSC> i=<notification id> : p=close ; ENOENT ; <terminator> # notification did not exist
This escape code is sent by the terminal if the notification is closed
or was already closed when the close request arrives, or a notification
with the specified identifier does not exist. If the notification is activated,
before it can be closed, then the close response is sent only if there is no
activation response. In other words, if you close a response and request
notification, you will get either of the following two responses::
<OSC> i=<notification id> : p=close ; <terminator> # closed
<OSC> i=<notification id> ; <terminator> # activated
This escape code is sent by the terminal if the notification is closed or a
notification with the specified identifier does not exist. If the notification
is activated or closed before the close request is received, then the notification does
not exist as far as the terminal is concerned, and an ``ENOENT`` response is
sent. To detect activation, before close, enable reporting with ``a=report``
when creating the notification.
Querying for support

View file

@ -521,7 +521,7 @@ class NotificationManager:
self.send_closed_response(to_close.channel_id, to_close.identifier)
self.purge_notification(to_close)
else:
self.send_closed_response(channel_id, cmd.identifier)
self.send_closed_response(channel_id, cmd.identifier, not_found=True)
return None
if payload_type is PayloadType.unknown:
@ -531,8 +531,9 @@ class NotificationManager:
cmd.set_payload(payload_type, payload_is_encoded, payload, prev_cmd)
return cmd
def send_closed_response(self, channel_id: int, client_id: str) -> None:
self.channel.send(channel_id, f'99;i={client_id}:p=close;')
def send_closed_response(self, channel_id: int, client_id: str, not_found: bool = False) -> None:
trailer = 'ENOENT;' if not_found else ''
self.channel.send(channel_id, f'99;i={client_id}:p=close;{trailer}')
def purge_notification(self, cmd: NotificationCommand) -> None:
self.in_progress_notification_commands_by_client_id.pop(cmd.identifier, None)

View file

@ -584,7 +584,7 @@ class TestDataTypes(BaseTest):
self.assertNotEqual(SingleKey(key=1, mods=2), SingleKey(key=1))
def test_notify_identifier_sanitization(self):
from kitty.notify import sanitize_identifier_pat
from kitty.notifications import sanitize_identifier_pat
self.ae(sanitize_identifier_pat().sub('', '\x1b\nabc\n[*'), 'abc')
def test_bracketed_paste_sanitizer(self):

View file

@ -93,7 +93,7 @@ def do_test(self: 'TestNotifications') -> None:
n = di.notifications[which]
di.close_notification(n['id'])
def assert_events(focus=True, close=0, report='', close_response=''):
def assert_events(focus=True, close=0, report='', close_response='', enoent=False):
self.ae(ch.focus_events, [''] if focus else [])
if report:
self.assertIn(f'99;i={report};', ch.responses)
@ -102,7 +102,8 @@ def do_test(self: 'TestNotifications') -> None:
m = re.match(r'99;i=[a-z0-9]+;', r)
self.assertIsNone(m, f'Unexpectedly found report response: {r}')
if close_response:
self.assertIn(f'99;i={close_response}:p=close;', ch.responses)
t = 'ENOENT;' if enoent else ''
self.assertIn(f'99;i={close_response}:p=close;{t}', ch.responses)
else:
for r in ch.responses:
m = re.match(r'99;i=[a-z0-9]+:p=close;', r)
@ -172,8 +173,21 @@ def do_test(self: 'TestNotifications') -> None:
reset()
h('i=c;title')
h('i=c:p=close;notify')
self.ae(di.notifications, [n()])
assert_events(focus=False, close=True, close_response='c')
reset()
h('i=c;title')
activate()
h('i=c:p=close;notify')
self.ae(di.notifications, [n()])
assert_events(focus=True, close_response='c', enoent=True)
reset()
h('i=c:a=report;title')
activate()
h('i=c:p=close;notify')
self.ae(di.notifications, [n()])
assert_events(focus=True, report='c', close_response='c', enoent=True)
reset()
h(';title')
self.ae(di.notifications, [n()])