Notification listen.
This commit is contained in:
parent
d6dcc4b176
commit
a1e9ae327f
5 changed files with 211 additions and 25 deletions
|
@ -38,20 +38,20 @@ var (
|
|||
notification bool
|
||||
|
||||
// General options
|
||||
title string
|
||||
width uint
|
||||
height uint
|
||||
okLabel string
|
||||
cancelLabel string
|
||||
extraButton string
|
||||
text string
|
||||
icon string
|
||||
multiple bool
|
||||
title string
|
||||
width uint
|
||||
height uint
|
||||
okLabel string
|
||||
cancelLabel string
|
||||
extraButton string
|
||||
text string
|
||||
icon string
|
||||
multiple bool
|
||||
defaultCancel bool
|
||||
|
||||
// Message options
|
||||
noWrap bool
|
||||
ellipsize bool
|
||||
defaultCancel bool
|
||||
noWrap bool
|
||||
ellipsize bool
|
||||
|
||||
// Entry options
|
||||
entryText string
|
||||
|
@ -81,6 +81,9 @@ var (
|
|||
autoKill bool
|
||||
noCancel bool
|
||||
|
||||
// Notify options
|
||||
listen bool
|
||||
|
||||
// Windows specific options
|
||||
unixeol bool
|
||||
cygpath bool
|
||||
|
@ -151,7 +154,7 @@ func main() {
|
|||
errResult(progress(opts...))
|
||||
|
||||
case notification:
|
||||
errResult(zenity.Notify(text, opts...))
|
||||
errResult(notify(opts...))
|
||||
|
||||
default:
|
||||
flag.Usage()
|
||||
|
@ -220,6 +223,9 @@ func setupFlags() {
|
|||
flag.BoolVar(&autoKill, "auto-kill", false, "Kill parent process if Cancel button is pressed (macOS and Unix only)")
|
||||
}
|
||||
|
||||
// Notify options
|
||||
flag.BoolVar(&listen, "listen", false, "Listen for commands on stdin")
|
||||
|
||||
// Windows specific options
|
||||
if runtime.GOOS == "windows" {
|
||||
flag.BoolVar(&unixeol, "unixeol", false, "Use Unix line endings (Windows only)")
|
||||
|
@ -332,6 +338,8 @@ func loadFlags() []zenity.Option {
|
|||
setDefault(&text, "Running...")
|
||||
setDefault(&okLabel, "OK")
|
||||
setDefault(&cancelLabel, "Cancel")
|
||||
case notification:
|
||||
setDefault(&icon, "dialog-information")
|
||||
default:
|
||||
setDefault(&text, "")
|
||||
}
|
||||
|
|
61
cmd/zenity/notify.go
Normal file
61
cmd/zenity/notify.go
Normal file
|
@ -0,0 +1,61 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/ncruces/zenity"
|
||||
"github.com/ncruces/zenity/internal/zenutil"
|
||||
)
|
||||
|
||||
func notify(opts ...zenity.Option) error {
|
||||
if !listen {
|
||||
return zenity.Notify(text, opts...)
|
||||
}
|
||||
|
||||
zenutil.Command = false
|
||||
var icon zenity.DialogIcon
|
||||
for scanner := bufio.NewScanner(os.Stdin); scanner.Scan(); {
|
||||
line := scanner.Text()
|
||||
var cmd, msg string
|
||||
if n := strings.IndexByte(line, ':'); n >= 0 {
|
||||
cmd = strings.TrimSpace(line[:n])
|
||||
msg = strings.TrimSpace(zenutil.Unescape(line[n+1:]))
|
||||
} else {
|
||||
fmt.Fprint(os.Stderr, "Could not parse command from stdin")
|
||||
}
|
||||
switch cmd {
|
||||
case "icon":
|
||||
switch msg {
|
||||
case "error", "dialog-error":
|
||||
icon = zenity.ErrorIcon
|
||||
case "info", "dialog-information":
|
||||
icon = zenity.InfoIcon
|
||||
case "question", "dialog-question":
|
||||
icon = zenity.QuestionIcon
|
||||
case "important", "warning", "dialog-warning":
|
||||
icon = zenity.WarningIcon
|
||||
case "dialog-password":
|
||||
icon = zenity.PasswordIcon
|
||||
default:
|
||||
icon = zenity.NoIcon
|
||||
}
|
||||
case "message", "tooltip":
|
||||
opts := []zenity.Option{zenity.Icon(icon)}
|
||||
if n := strings.IndexByte(msg, '\n'); n >= 0 {
|
||||
opts = append(opts, zenity.Title(msg[:n]))
|
||||
msg = msg[n+1:]
|
||||
}
|
||||
if err := zenity.Notify(msg, opts...); err != nil {
|
||||
return err
|
||||
}
|
||||
case "visible", "hints":
|
||||
// ignored
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "Unknown command %q", cmd)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
89
internal/zenutil/unescape.go
Normal file
89
internal/zenutil/unescape.go
Normal file
|
@ -0,0 +1,89 @@
|
|||
package zenutil
|
||||
|
||||
// Unescape is internal.
|
||||
func Unescape(s string) string {
|
||||
// Apply rules described in:
|
||||
// https://developer.gnome.org/glib/stable/glib-String-Utility-Functions.html#g-strescape
|
||||
|
||||
const (
|
||||
initial = iota
|
||||
escape1
|
||||
escape2
|
||||
escape3
|
||||
)
|
||||
var oct byte
|
||||
var res []byte
|
||||
state := initial
|
||||
for _, b := range []byte(s) {
|
||||
switch state {
|
||||
case initial:
|
||||
switch b {
|
||||
case '\\':
|
||||
state = escape1
|
||||
default:
|
||||
res = append(res, b)
|
||||
state = initial
|
||||
}
|
||||
|
||||
case escape1:
|
||||
switch b {
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7':
|
||||
oct = b - '0'
|
||||
state = escape2
|
||||
case 'b':
|
||||
res = append(res, '\b')
|
||||
state = initial
|
||||
case 'f':
|
||||
res = append(res, '\f')
|
||||
state = initial
|
||||
case 'n':
|
||||
res = append(res, '\n')
|
||||
state = initial
|
||||
case 'r':
|
||||
res = append(res, '\r')
|
||||
state = initial
|
||||
case 't':
|
||||
res = append(res, '\t')
|
||||
state = initial
|
||||
case 'v':
|
||||
res = append(res, '\v')
|
||||
state = initial
|
||||
default:
|
||||
res = append(res, b)
|
||||
state = initial
|
||||
}
|
||||
|
||||
case escape2:
|
||||
switch b {
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7':
|
||||
oct = oct<<3 | (b - '0')
|
||||
state = escape3
|
||||
case '\\':
|
||||
res = append(res, oct)
|
||||
state = escape1
|
||||
default:
|
||||
res = append(res, oct, b)
|
||||
state = initial
|
||||
}
|
||||
|
||||
case escape3:
|
||||
switch b {
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7':
|
||||
oct = oct<<3 | (b - '0')
|
||||
res = append(res, oct)
|
||||
state = initial
|
||||
case '\\':
|
||||
res = append(res, oct)
|
||||
state = escape1
|
||||
default:
|
||||
res = append(res, oct, b)
|
||||
state = initial
|
||||
}
|
||||
}
|
||||
}
|
||||
if state == escape2 || state == escape3 {
|
||||
res = append(res, oct)
|
||||
}
|
||||
|
||||
return string(res)
|
||||
}
|
28
internal/zenutil/unescape_test.go
Normal file
28
internal/zenutil/unescape_test.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
package zenutil
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestUnescape(t *testing.T) {
|
||||
tests := []struct {
|
||||
data string
|
||||
want string
|
||||
}{
|
||||
{`abc`, "abc"},
|
||||
{`ab\c`, "abc"},
|
||||
{`a\bc`, "a\bc"},
|
||||
{`a\1c`, "a\001c"},
|
||||
{`a\12c`, "a\012c"},
|
||||
{`a\123c`, "a\123c"},
|
||||
{`a\1\b`, "a\001\b"},
|
||||
{`a\12\b`, "a\012\b"},
|
||||
{`a\123\b`, "a\123\b"},
|
||||
{`abc\1`, "abc\001"},
|
||||
{`abc\12`, "abc\012"},
|
||||
{`abc\123`, "abc\123"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
if got := Unescape(tt.data); got != tt.want {
|
||||
t.Errorf("Unescape(%q) = %q, want %q", tt.data, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
24
zenity.go
24
zenity.go
|
@ -31,24 +31,24 @@ const ErrUnsupported = zenutil.ErrUnsupported
|
|||
|
||||
type options struct {
|
||||
// General options
|
||||
title *string
|
||||
width uint
|
||||
height uint
|
||||
okLabel *string
|
||||
cancelLabel *string
|
||||
extraButton *string
|
||||
icon DialogIcon
|
||||
title *string
|
||||
width uint
|
||||
height uint
|
||||
okLabel *string
|
||||
cancelLabel *string
|
||||
extraButton *string
|
||||
icon DialogIcon
|
||||
defaultCancel bool
|
||||
|
||||
// Message options
|
||||
noWrap bool
|
||||
ellipsize bool
|
||||
|
||||
// Entry options
|
||||
entryText string
|
||||
hideText bool
|
||||
username bool
|
||||
|
||||
// Message options
|
||||
noWrap bool
|
||||
ellipsize bool
|
||||
defaultCancel bool
|
||||
|
||||
// List options
|
||||
disallowEmpty bool
|
||||
defaultItems []string
|
||||
|
|
Loading…
Reference in a new issue