diff --git a/cmd/zenity/main.go b/cmd/zenity/main.go index 7584780..2faabb0 100644 --- a/cmd/zenity/main.go +++ b/cmd/zenity/main.go @@ -29,6 +29,7 @@ var ( infoDlg bool warningDlg bool questionDlg bool + passwordDlg bool fileSelectionDlg bool colorSelectionDlg bool @@ -95,7 +96,7 @@ func main() { errResult(zenity.Notify(text, opts...)) case entryDlg: - strResult(zenity.Entry(text, opts...)) + strOKResult(zenity.Entry(text, opts...)) case errorDlg: okResult(zenity.Error(text, opts...)) @@ -106,6 +107,10 @@ func main() { case questionDlg: okResult(zenity.Question(text, opts...)) + case passwordDlg: + _, pw, ok, err := zenity.Password(opts...) + strOKResult(pw, ok, err) + case fileSelectionDlg: switch { default: @@ -131,6 +136,7 @@ func setupFlags() { flag.BoolVar(&infoDlg, "info", false, "Display info dialog") flag.BoolVar(&warningDlg, "warning", false, "Display warning dialog") flag.BoolVar(&questionDlg, "question", false, "Display question dialog") + flag.BoolVar(&passwordDlg, "password", false, "Display password dialog") flag.BoolVar(&fileSelectionDlg, "file-selection", false, "Display file selection dialog") flag.BoolVar(&colorSelectionDlg, "color-selection", false, "Display color selection dialog") @@ -207,6 +213,9 @@ func validateFlags() { if questionDlg { n++ } + if passwordDlg { + n++ + } if fileSelectionDlg { n++ } @@ -255,6 +264,10 @@ func loadFlags() []zenity.Option { setDefault(&text, "Are you sure you want to proceed?") setDefault(&okLabel, "Yes") setDefault(&cancelLabel, "No") + case passwordDlg: + setDefault(&icon, "dialog-password") + setDefault(&okLabel, "OK") + setDefault(&cancelLabel, "Cancel") default: setDefault(&text, "") } @@ -386,11 +399,11 @@ func listResult(l []string, err error) { if err != nil { errResult(err) } - os.Stdout.WriteString(strings.Join(l, zenutil.Separator)) - os.Stdout.WriteString(zenutil.LineBreak) if l == nil { os.Exit(1) } + os.Stdout.WriteString(strings.Join(l, zenutil.Separator)) + os.Stdout.WriteString(zenutil.LineBreak) os.Exit(0) } @@ -406,6 +419,18 @@ func colorResult(c color.Color, err error) { os.Exit(0) } +func strOKResult(s string, ok bool, err error) { + if err != nil { + errResult(err) + } + if !ok { + os.Exit(1) + } + os.Stdout.WriteString(s) + os.Stdout.WriteString(zenutil.LineBreak) + os.Exit(0) +} + func ingestPath(path string) string { if runtime.GOOS == "windows" && path != "" { var args []string diff --git a/entry.go b/entry.go index b19e01c..259fb82 100644 --- a/entry.go +++ b/entry.go @@ -2,14 +2,23 @@ package zenity // Entry displays the text entry dialog. // -// Returns nil on cancel. +// Returns false on cancel, or ErrExtraButton. // // Valid options: Title, Width, Height, OKLabel, CancelLabel, ExtraButton, // Icon, EntryText, HideText. -func Entry(text string, options ...Option) (string, error) { +func Entry(text string, options ...Option) (string, bool, error) { return entry(text, applyOptions(options)) } +// Password displays the password dialog. +// +// Returns false on cancel, or ErrExtraButton. +// +// Valid options: Title, OKLabel, CancelLabel, ExtraButton, Icon, Username. +func Password(options ...Option) (usr string, pw string, ok bool, err error) { + return password(applyOptions(options)) +} + // EntryText returns an Option to set the entry text. func EntryText(text string) Option { return funcOption(func(o *options) { o.entryText = text }) @@ -19,3 +28,8 @@ func EntryText(text string) Option { func HideText() Option { return funcOption(func(o *options) { o.hideText = true }) } + +// Username returns an Option to display the username (Unix only). +func Username() Option { + return funcOption(func(o *options) { o.username = true }) +} diff --git a/entry_darwin.go b/entry_darwin.go index 60a68a6..d296f56 100644 --- a/entry_darwin.go +++ b/entry_darwin.go @@ -6,7 +6,7 @@ import ( "github.com/ncruces/zenity/internal/zenutil" ) -func entry(text string, opts options) (string, error) { +func entry(text string, opts options) (string, bool, error) { var data zenutil.Dialog data.Text = text data.Operation = "displayDialog" @@ -47,12 +47,18 @@ func entry(text string, opts options) (string, error) { if err, ok := err.(*exec.ExitError); ok && err.ExitCode() == 1 { if len(out) > 0 && opts.extraButton != nil && string(out[:len(out)-1]) == *opts.extraButton { - return "", ErrExtraButton + return "", false, ErrExtraButton } - return "", nil + return "", false, nil } if err != nil { - return "", err + return "", false, err } - return string(out[:len(out)-1]), err + return string(out[:len(out)-1]), true, nil +} + +func password(opts options) (string, string, bool, error) { + opts.hideText = true + pass, ok, err := entry("Type your password", opts) + return "", pass, ok, err } diff --git a/entry_unix.go b/entry_unix.go index bc1009b..35c024d 100644 --- a/entry_unix.go +++ b/entry_unix.go @@ -5,11 +5,12 @@ package zenity import ( "os/exec" "strconv" + "strings" "github.com/ncruces/zenity/internal/zenutil" ) -func entry(text string, opts options) (string, error) { +func entry(text string, opts options) (string, bool, error) { args := []string{"--entry", "--text", text, "--entry-text", opts.entryText} if opts.title != nil { args = append(args, "--title", *opts.title) @@ -47,12 +48,49 @@ func entry(text string, opts options) (string, error) { if err, ok := err.(*exec.ExitError); ok && err.ExitCode() == 1 { if len(out) > 0 && opts.extraButton != nil && string(out[:len(out)-1]) == *opts.extraButton { - return "", ErrExtraButton + return "", false, ErrExtraButton } - return "", nil + return "", false, nil } if err != nil { - return "", err + return "", false, err } - return string(out[:len(out)-1]), err + return string(out[:len(out)-1]), true, nil +} + +func password(opts options) (string, string, bool, error) { + args := []string{"--password"} + if opts.title != nil { + args = append(args, "--title", *opts.title) + } + if opts.okLabel != nil { + args = append(args, "--ok-label", *opts.okLabel) + } + if opts.cancelLabel != nil { + args = append(args, "--cancel-label", *opts.cancelLabel) + } + if opts.extraButton != nil { + args = append(args, "--extra-button", *opts.extraButton) + } + if opts.username { + args = append(args, "--username") + } + + out, err := zenutil.Run(opts.ctx, args) + if err, ok := err.(*exec.ExitError); ok && err.ExitCode() == 1 { + if len(out) > 0 && opts.extraButton != nil && + string(out[:len(out)-1]) == *opts.extraButton { + return "", "", false, ErrExtraButton + } + return "", "", false, nil + } + if err != nil { + return "", "", false, err + } + if opts.username { + if split := strings.SplitN(string(out[:len(out)-1]), "|", 2); len(split) == 2 { + return split[0], split[1], true, nil + } + } + return "", string(out[:len(out)-1]), true, nil } diff --git a/zenity.go b/zenity.go index b0b4afd..0162829 100644 --- a/zenity.go +++ b/zenity.go @@ -34,6 +34,7 @@ type options struct { // Entry options entryText string hideText bool + username bool // Message options noWrap bool