mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-19 15:04:50 +02:00
More work on notify kitten
This commit is contained in:
@@ -6,8 +6,10 @@ import (
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"kitty/tools/cli"
|
||||
"kitty/tools/tty"
|
||||
"kitty/tools/tui/loop"
|
||||
"kitty/tools/utils"
|
||||
)
|
||||
@@ -22,7 +24,7 @@ func b64encode(x string) string {
|
||||
return base64.RawStdEncoding.EncodeToString(utils.UnsafeStringToBytes(x))
|
||||
}
|
||||
|
||||
func create_metadata(opts *Options) string {
|
||||
func create_metadata(opts *Options, wait_till_closed bool, expire_time time.Duration) string {
|
||||
ans := []string{}
|
||||
if opts.AppName != "" {
|
||||
ans = append(ans, "f="+b64encode(opts.AppName))
|
||||
@@ -33,13 +35,13 @@ func create_metadata(opts *Options) string {
|
||||
case "critical":
|
||||
ans = append(ans, "u=2")
|
||||
}
|
||||
if opts.ExpireTime >= 0 {
|
||||
ans = append(ans, "w="+strconv.Itoa(opts.ExpireTime))
|
||||
if expire_time >= 0 {
|
||||
ans = append(ans, "w="+strconv.FormatInt(expire_time.Milliseconds(), 10))
|
||||
}
|
||||
if opts.Type != "" {
|
||||
ans = append(ans, "t="+b64encode(opts.Type))
|
||||
}
|
||||
if opts.WaitTillClosed {
|
||||
if wait_till_closed {
|
||||
ans = append(ans, "c=1")
|
||||
}
|
||||
m := strings.Join(ans, ":")
|
||||
@@ -49,7 +51,9 @@ func create_metadata(opts *Options) string {
|
||||
return m
|
||||
}
|
||||
|
||||
func generate_chunks(title, body, identifier string, opts *Options, wait_till_closed bool, callback func(string)) {
|
||||
var debugprintln = tty.DebugPrintln
|
||||
|
||||
func generate_chunks(title, body, identifier string, opts *Options, wait_till_closed bool, expire_time time.Duration, callback func(string)) {
|
||||
prefix := ESC_CODE_PREFIX + "i=" + identifier
|
||||
write_chunk := func(middle string) {
|
||||
callback(prefix + middle + ESC_CODE_SUFFIX)
|
||||
@@ -61,10 +65,10 @@ func generate_chunks(title, body, identifier string, opts *Options, wait_till_cl
|
||||
chunk := payload[:min(CHUNK_SIZE, len(payload))]
|
||||
payload = utils.IfElse(len(payload) > len(chunk), payload[len(chunk):], "")
|
||||
enc := b64encode(chunk)
|
||||
write_chunk(":d=0" + p + ";" + enc)
|
||||
write_chunk(":d=0:e=1" + p + ";" + enc)
|
||||
}
|
||||
}
|
||||
metadata := create_metadata(opts)
|
||||
metadata := create_metadata(opts, wait_till_closed, expire_time)
|
||||
write_chunk(":d=0" + metadata + ";")
|
||||
add_payload("title", title)
|
||||
if body != "" {
|
||||
@@ -73,22 +77,60 @@ func generate_chunks(title, body, identifier string, opts *Options, wait_till_cl
|
||||
write_chunk(";")
|
||||
}
|
||||
|
||||
func run_loop(title, body, identifier string, opts *Options, wait_till_closed bool) (err error) {
|
||||
func run_loop(title, body, identifier string, opts *Options, wait_till_closed bool, expire_time time.Duration) (err error) {
|
||||
lp, err := loop.New(loop.NoAlternateScreen, loop.NoRestoreColors, loop.NoMouseTracking)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lp.OnInitialize = func() (string, error) {
|
||||
generate_chunks(title, body, identifier, opts, wait_till_closed, func(x string) { lp.QueueWriteString(x) })
|
||||
generate_chunks(title, body, identifier, opts, wait_till_closed, expire_time, func(x string) { lp.QueueWriteString(x) })
|
||||
return "", nil
|
||||
}
|
||||
err = lp.Run()
|
||||
ds := lp.DeathSignalName()
|
||||
if ds != "" {
|
||||
fmt.Println("Killed by signal: ", ds)
|
||||
lp.KillIfSignalled()
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func random_ident() (string, error) {
|
||||
return utils.HumanUUID4()
|
||||
}
|
||||
|
||||
func parse_duration(x string) (ans time.Duration, err error) {
|
||||
switch x {
|
||||
case "never":
|
||||
return 0, nil
|
||||
case "":
|
||||
return -1, nil
|
||||
}
|
||||
trailer := x[len(x)-1]
|
||||
multipler := time.Second
|
||||
switch trailer {
|
||||
case 's':
|
||||
x = x[:len(x)-1]
|
||||
case 'm':
|
||||
x = x[:len(x)-1]
|
||||
multipler = time.Minute
|
||||
case 'h':
|
||||
x = x[:len(x)-1]
|
||||
multipler = time.Hour
|
||||
case 'd':
|
||||
x = x[:len(x)-1]
|
||||
multipler = time.Hour * 24
|
||||
}
|
||||
val, err := strconv.ParseFloat(x, 64)
|
||||
if err != nil {
|
||||
return ans, err
|
||||
}
|
||||
ans = time.Duration(float64(multipler) * val)
|
||||
return
|
||||
}
|
||||
|
||||
func main(_ *cli.Command, opts *Options, args []string) (rc int, err error) {
|
||||
if len(args) == 0 {
|
||||
return 1, fmt.Errorf("Must specify a TITLE for the notification")
|
||||
@@ -107,9 +149,13 @@ func main(_ *cli.Command, opts *Options, args []string) (rc int, err error) {
|
||||
return 1, fmt.Errorf("Failed to generate a random identifier with error: %w", err)
|
||||
}
|
||||
}
|
||||
var expire_time time.Duration
|
||||
if expire_time, err = parse_duration(opts.ExpireTime); err != nil {
|
||||
return 1, fmt.Errorf("Invalid expire time: %s with error: %w", opts.ExpireTime, err)
|
||||
}
|
||||
wait_till_closed := opts.WaitTillClosed
|
||||
if opts.OnlyPrintEscapeCode {
|
||||
generate_chunks(title, body, ident, opts, wait_till_closed, func(x string) {
|
||||
generate_chunks(title, body, ident, opts, wait_till_closed, expire_time, func(x string) {
|
||||
if err == nil {
|
||||
_, err = os.Stdout.WriteString(x)
|
||||
}
|
||||
@@ -118,7 +164,21 @@ func main(_ *cli.Command, opts *Options, args []string) (rc int, err error) {
|
||||
if opts.PrintIdentifier {
|
||||
fmt.Println(ident)
|
||||
}
|
||||
err = run_loop(title, body, ident, opts, wait_till_closed)
|
||||
if wait_till_closed {
|
||||
err = run_loop(title, body, ident, opts, wait_till_closed, expire_time)
|
||||
} else {
|
||||
var term *tty.Term
|
||||
if term, err = tty.OpenControllingTerm(); err != nil {
|
||||
return 1, fmt.Errorf("Failed to open controlling terminal with error: %w", err)
|
||||
}
|
||||
generate_chunks(title, body, ident, opts, wait_till_closed, expire_time, func(x string) {
|
||||
if err == nil {
|
||||
_, err = term.WriteString(x)
|
||||
}
|
||||
})
|
||||
term.RestoreAndClose()
|
||||
}
|
||||
|
||||
}
|
||||
if err != nil {
|
||||
rc = 1
|
||||
|
||||
@@ -16,13 +16,13 @@ The urgency of the notification.
|
||||
|
||||
|
||||
--expire-time -t
|
||||
default=-1
|
||||
type=int
|
||||
The duration, in milliseconds, for the notification to appear on screen. The default is to
|
||||
use the policy of the OS notification service. A value of 0 means the notification should
|
||||
The duration, for the notification to appear on screen. The default is to
|
||||
use the policy of the OS notification service. A value of :code:`never` means the notification should
|
||||
never expire, however, this may or may not work depending on the policies of the OS notification
|
||||
service. Positive values guarantee the notification will be closed automatically
|
||||
after that many milliseconds have elapsed. The notification could be closed before by user
|
||||
service. Time is specified in the form NUMBER[SUFFIX] where SUFFIX can be :code:`s` for seconds, :code:`m` for minutes,
|
||||
:code:`h` for hours or :code:`d` for days. Non-integer numbers are allowed.
|
||||
If not specified, seconds is assumed. The notification is guaranteed to be closed automatically
|
||||
after the specified time has elapsed. The notification could be closed before by user
|
||||
action or OS policy.
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user