notify kitten: Wait for close now implemented

This commit is contained in:
Kovid Goyal
2024-07-29 10:08:37 +05:30
parent 9bd155ae50
commit 896833a4f7
3 changed files with 80 additions and 14 deletions

View File

@@ -100,14 +100,6 @@ code. Similarly if values for known keys are unknown, the terminal emulator
*should* either ignore the entire escape code or perform a best guess effort
to display it based on what it does understand.
.. note::
It is possible to extend this escape code to allow specifying an icon for
the notification, however, given that some platforms, such as legacy versions
of macOS, don't allow displaying custom images on a notification, it was
decided to leave it out of the spec for the time being.
Similarly, features such as scheduled notifications could be added in future
revisions.
Being informed when a notification is closed
------------------------------------------------
@@ -143,9 +135,10 @@ notifications are still alive (not closed), with::
<OSC> 99 ; i=myid : p=alive ; <terminator>
The terminal will reply with::
<OSC> 99 ; i=myid : p=alive ; id1,id2,id3 <terminator>
Here, ``myid`` is present for multiplxer support. The reponse from the terminal
Here, ``myid`` is present for multiplexer support. The response from the terminal
contains a comma separated list of ids that are still alive.
@@ -218,7 +211,7 @@ Key Value
query response.
``o`` Comma separated list of occassions from the ``o`` key that the
terminal implements. If no occassions are supported, the value
terminal implements. If no occasions are supported, the value
``o=always`` must be sent in the query response.
``u`` Comma separated list of urgency values that the terminal implements.
@@ -236,7 +229,7 @@ Key Value
======= ================================================================================
In the future, if this protocol expands, more keys might be added. Clients must
ignore keys they dont understand in the query response.
ignore keys they do not understand in the query response.
To check if a terminal emulator supports this notifications protocol the best way is to
send the above *query action* followed by a request for the `primary device
@@ -264,7 +257,7 @@ Key Value Default Description
otherwise it is plain UTF-8 text with no C0 control codes in it
``i`` ``[a-zA-Z0-9-_+.]`` ``0`` Identifier for the notification. Make these globally unqiue,
like an UUID, so that termial multiplxers can
like an UUID, so that terminal multiplexers can
direct responses to the correct window.
``p`` One of ``title``, ``title`` Whether the payload is the notification title or body or query. If a

View File

@@ -1,9 +1,11 @@
package notify
import (
"bytes"
"encoding/base64"
"fmt"
"os"
"slices"
"strconv"
"strings"
"time"
@@ -42,7 +44,7 @@ func create_metadata(opts *Options, wait_till_closed bool, expire_time time.Dura
ans = append(ans, "t="+b64encode(opts.Type))
}
if wait_till_closed {
ans = append(ans, "c=1")
ans = append(ans, "c=1:a=report")
}
m := strings.Join(ans, ":")
if m != "" {
@@ -82,11 +84,78 @@ func run_loop(title, body, identifier string, opts *Options, wait_till_closed bo
if err != nil {
return err
}
activated := ""
prefix := ESC_CODE_PREFIX + "i=" + identifier
poll_for_close := func() {
lp.AddTimer(time.Millisecond*50, false, func(_ loop.IdType) error {
lp.QueueWriteString(prefix + ":p=alive;" + ESC_CODE_SUFFIX)
return nil
})
}
lp.OnInitialize = func() (string, error) {
generate_chunks(title, body, identifier, opts, wait_till_closed, expire_time, func(x string) { lp.QueueWriteString(x) })
return "", nil
}
lp.OnEscapeCode = func(ect loop.EscapeCodeType, data []byte) error {
if ect == loop.OSC && bytes.HasPrefix(data, []byte(ESC_CODE_PREFIX[2:])) {
raw := utils.UnsafeBytesToString(data[len(ESC_CODE_PREFIX[2:]):])
metadata, payload, _ := strings.Cut(raw, ";")
sent_identifier, payload_type := "", ""
for _, x := range strings.Split(metadata, ":") {
key, val, _ := strings.Cut(x, "=")
switch key {
case "i":
sent_identifier = val
case "p":
payload_type = val
}
}
if sent_identifier == identifier {
switch payload_type {
case "close":
if payload == "untracked" {
poll_for_close()
} else {
lp.Quit(0)
}
case "alive":
live_ids := strings.Split(payload, ",")
if slices.Contains(live_ids, identifier) {
poll_for_close()
} else {
lp.Quit(0)
}
case "":
activated = utils.IfElse(payload == "", "activated", payload)
}
}
}
return nil
}
close_requested := 0
lp.OnKeyEvent = func(event *loop.KeyEvent) error {
if event.MatchesPressOrRepeat("ctrl+c") || event.MatchesPressOrRepeat("esc") {
event.Handled = true
switch close_requested {
case 0:
lp.QueueWriteString(prefix + ":p=close;" + ESC_CODE_SUFFIX)
lp.Println("Closing notification, please wait...")
close_requested++
case 1:
key := "Esc"
if event.MatchesPressOrRepeat("ctrl+c") {
key = "Ctrl+C"
}
lp.Println(fmt.Sprintf("Waiting for response from terminal, press the %s key again to abort. Note that this might result in garbage being printed to the terminal.", key))
close_requested++
default:
return fmt.Errorf("Aborted by user!")
}
}
return nil
}
err = lp.Run()
ds := lp.DeathSignalName()
if ds != "" {
@@ -94,6 +163,9 @@ func run_loop(title, body, identifier string, opts *Options, wait_till_closed bo
lp.KillIfSignalled()
return
}
if activated != "" && err == nil {
fmt.Println(activated)
}
return
}

View File

@@ -45,7 +45,8 @@ your own identifier via the --identifier option.
--wait-till-closed -w
type=bool-set
Wait until the notification is closed. If the user activates the notification,
"activated" is printed to STDOUT before quitting.
"activated" is printed to STDOUT before quitting. Press the Esc or Ctrl+C keys
to close the notification manually.
--only-print-escape-code