mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-04 22:03:48 +02:00
notify kitten: Wait for close now implemented
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user