More work on notify kitten

This commit is contained in:
Kovid Goyal
2024-07-29 08:21:45 +05:30
parent f6a24af229
commit 9bd155ae50
2 changed files with 77 additions and 17 deletions

View File

@@ -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

View File

@@ -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.