diff --git a/date_windows.go b/date_windows.go index b59ea5c..9ecc876 100644 --- a/date_windows.go +++ b/date_windows.go @@ -74,16 +74,16 @@ func (dlg *calendarDialog) setup(text string, opts options) (time.Time, error) { 12, 30, 241, 164, dlg.wnd, 0, instance, nil) dlg.okBtn, _ = win.CreateWindowEx(0, - strptr("BUTTON"), strptr(*opts.okLabel), + strptr("BUTTON"), strptr(quoteAccelerators(*opts.okLabel)), _WS_ZEN_BUTTON|win.BS_DEFPUSHBUTTON, 12, 206, 75, 24, dlg.wnd, win.IDOK, instance, nil) dlg.cancelBtn, _ = win.CreateWindowEx(0, - strptr("BUTTON"), strptr(*opts.cancelLabel), + strptr("BUTTON"), strptr(quoteAccelerators(*opts.cancelLabel)), _WS_ZEN_BUTTON, 12, 206, 75, 24, dlg.wnd, win.IDCANCEL, instance, nil) if opts.extraButton != nil { dlg.extraBtn, _ = win.CreateWindowEx(0, - strptr("BUTTON"), strptr(*opts.extraButton), + strptr("BUTTON"), strptr(quoteAccelerators(*opts.extraButton)), _WS_ZEN_BUTTON, 12, 206, 75, 24, dlg.wnd, win.IDNO, instance, nil) } diff --git a/entry_windows.go b/entry_windows.go index 2da2931..a21bc98 100644 --- a/entry_windows.go +++ b/entry_windows.go @@ -77,16 +77,16 @@ func (dlg *entryDialog) setup(text string, opts options) (string, error) { 12, 30, 241, 24, dlg.wnd, 0, instance, nil) dlg.okBtn, _ = win.CreateWindowEx(0, - strptr("BUTTON"), strptr(*opts.okLabel), + strptr("BUTTON"), strptr(quoteAccelerators(*opts.okLabel)), _WS_ZEN_BUTTON|win.BS_DEFPUSHBUTTON, 12, 66, 75, 24, dlg.wnd, win.IDOK, instance, nil) dlg.cancelBtn, _ = win.CreateWindowEx(0, - strptr("BUTTON"), strptr(*opts.cancelLabel), + strptr("BUTTON"), strptr(quoteAccelerators(*opts.cancelLabel)), _WS_ZEN_BUTTON, 12, 66, 75, 24, dlg.wnd, win.IDCANCEL, instance, nil) if opts.extraButton != nil { dlg.extraBtn, _ = win.CreateWindowEx(0, - strptr("BUTTON"), strptr(*opts.extraButton), + strptr("BUTTON"), strptr(quoteAccelerators(*opts.extraButton)), _WS_ZEN_BUTTON, 12, 66, 75, 24, dlg.wnd, win.IDNO, instance, nil) } diff --git a/internal/zencmd/window_unix_test.go b/internal/zencmd/window_unix_test.go index a0769f7..bd82624 100644 --- a/internal/zencmd/window_unix_test.go +++ b/internal/zencmd/window_unix_test.go @@ -7,6 +7,27 @@ import ( "testing" ) +func TestParseWindowId(t *testing.T) { + tests := []struct { + name string + text string + want int + }{ + {name: "Zero", text: "0", want: 0}, + {name: "Dec", text: "10", want: 10}, + {name: "Hex", text: "0700", want: 0700}, + {name: "Oct", text: "0xFF", want: 0xff}, + {name: "Error", text: "a", want: 0}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := ParseWindowId(tt.text); got != tt.want { + t.Errorf("ParseWindowId(%q) = %v; want %v", tt.text, got, tt.want) + } + }) + } +} + func Test_getPidToPpidMap(t *testing.T) { got, err := getPidToPpidMap() if err != nil { diff --git a/list.go b/list.go index f8ff565..dd06cd0 100644 --- a/list.go +++ b/list.go @@ -31,7 +31,7 @@ func ListMultiple(text string, items []string, options ...Option) ([]string, err // // May return: ErrCanceled, ErrUnsupported. func ListMultipleItems(text string, items ...string) ([]string, error) { - return ListMultiple(text, items) + return ListMultiple(text, items, CheckList()) } // CheckList returns an Option to show check boxes (Unix only). diff --git a/list_windows.go b/list_windows.go index 3b97f13..b2f0be4 100644 --- a/list_windows.go +++ b/list_windows.go @@ -91,20 +91,20 @@ func (dlg *listDialog) setup(text string, opts options) ([]string, error) { flags |= win.LBS_EXTENDEDSEL } dlg.listCtl, _ = win.CreateWindowEx(win.WS_EX_CLIENTEDGE, - strptr("LISTBOX"), strptr(opts.entryText), flags, + strptr("LISTBOX"), nil, flags, 12, 30, 241, 164, dlg.wnd, 0, instance, nil) dlg.okBtn, _ = win.CreateWindowEx(0, - strptr("BUTTON"), strptr(*opts.okLabel), + strptr("BUTTON"), strptr(quoteAccelerators(*opts.okLabel)), _WS_ZEN_BUTTON|win.BS_DEFPUSHBUTTON, 12, 206, 75, 24, dlg.wnd, win.IDOK, instance, nil) dlg.cancelBtn, _ = win.CreateWindowEx(0, - strptr("BUTTON"), strptr(*opts.cancelLabel), + strptr("BUTTON"), strptr(quoteAccelerators(*opts.cancelLabel)), _WS_ZEN_BUTTON, 12, 206, 75, 24, dlg.wnd, win.IDCANCEL, instance, nil) if opts.extraButton != nil { dlg.extraBtn, _ = win.CreateWindowEx(0, - strptr("BUTTON"), strptr(*opts.extraButton), + strptr("BUTTON"), strptr(quoteAccelerators(*opts.extraButton)), _WS_ZEN_BUTTON, 12, 206, 75, 24, dlg.wnd, win.IDNO, instance, nil) } diff --git a/msg_windows.go b/msg_windows.go index 1f292ea..26a8048 100644 --- a/msg_windows.go +++ b/msg_windows.go @@ -88,14 +88,14 @@ func hookMessageDialog(opts options) (context.CancelFunc, error) { if opts.okLabel != nil || opts.cancelLabel != nil || opts.extraButton != nil || opts.icon != nil { init = func(wnd win.HWND) { if opts.okLabel != nil { - win.SetDlgItemText(wnd, win.IDOK, strptr(*opts.okLabel)) - win.SetDlgItemText(wnd, win.IDYES, strptr(*opts.okLabel)) + win.SetDlgItemText(wnd, win.IDOK, strptr(quoteAccelerators(*opts.okLabel))) + win.SetDlgItemText(wnd, win.IDYES, strptr(quoteAccelerators(*opts.okLabel))) } if opts.cancelLabel != nil { - win.SetDlgItemText(wnd, win.IDCANCEL, strptr(*opts.cancelLabel)) + win.SetDlgItemText(wnd, win.IDCANCEL, strptr(quoteAccelerators(*opts.cancelLabel))) } if opts.extraButton != nil { - win.SetDlgItemText(wnd, win.IDNO, strptr(*opts.extraButton)) + win.SetDlgItemText(wnd, win.IDNO, strptr(quoteAccelerators(*opts.extraButton))) } if icon.handle != 0 { diff --git a/progress_windows.go b/progress_windows.go index 7b80305..61ff704 100644 --- a/progress_windows.go +++ b/progress_windows.go @@ -157,18 +157,18 @@ func (dlg *progressDialog) setup(opts options) error { 12, 30, 241, 16, dlg.wnd, 0, instance, nil) dlg.okBtn, _ = win.CreateWindowEx(0, - strptr("BUTTON"), strptr(*opts.okLabel), + strptr("BUTTON"), strptr(quoteAccelerators(*opts.okLabel)), _WS_ZEN_BUTTON|win.BS_DEFPUSHBUTTON|win.WS_DISABLED, 12, 58, 75, 24, dlg.wnd, win.IDOK, instance, nil) if !opts.noCancel { dlg.cancelBtn, _ = win.CreateWindowEx(0, - strptr("BUTTON"), strptr(*opts.cancelLabel), + strptr("BUTTON"), strptr(quoteAccelerators(*opts.cancelLabel)), _WS_ZEN_BUTTON, 12, 58, 75, 24, dlg.wnd, win.IDCANCEL, instance, nil) } if opts.extraButton != nil { dlg.extraBtn, _ = win.CreateWindowEx(0, - strptr("BUTTON"), strptr(*opts.extraButton), + strptr("BUTTON"), strptr(quoteAccelerators(*opts.extraButton)), _WS_ZEN_BUTTON, 12, 58, 75, 24, dlg.wnd, win.IDNO, instance, nil) } diff --git a/pwd_windows.go b/pwd_windows.go index 0d46c12..ac003b9 100644 --- a/pwd_windows.go +++ b/pwd_windows.go @@ -93,16 +93,16 @@ func (dlg *passwordDialog) setup(opts options) (string, string, error) { 12, 80, 241, 24, dlg.wnd, 0, instance, nil) dlg.okBtn, _ = win.CreateWindowEx(0, - strptr("BUTTON"), strptr(*opts.okLabel), + strptr("BUTTON"), strptr(quoteAccelerators(*opts.okLabel)), _WS_ZEN_BUTTON|win.BS_DEFPUSHBUTTON, 12, 116, 75, 24, dlg.wnd, win.IDOK, instance, nil) dlg.cancelBtn, _ = win.CreateWindowEx(0, - strptr("BUTTON"), strptr(*opts.cancelLabel), + strptr("BUTTON"), strptr(quoteAccelerators(*opts.cancelLabel)), _WS_ZEN_BUTTON, 12, 116, 75, 24, dlg.wnd, win.IDCANCEL, instance, nil) if opts.extraButton != nil { dlg.extraBtn, _ = win.CreateWindowEx(0, - strptr("BUTTON"), strptr(*opts.extraButton), + strptr("BUTTON"), strptr(quoteAccelerators(*opts.extraButton)), _WS_ZEN_BUTTON, 12, 116, 75, 24, dlg.wnd, win.IDNO, instance, nil) } diff --git a/util_unix.go b/util.go similarity index 96% rename from util_unix.go rename to util.go index c14242f..4084bf7 100644 --- a/util_unix.go +++ b/util.go @@ -1,5 +1,3 @@ -//go:build !windows - package zenity import ( @@ -12,6 +10,10 @@ import ( "github.com/ncruces/zenity/internal/zenutil" ) +func quoteAccelerators(text string) string { + return strings.ReplaceAll(text, "&", "&&") +} + func appendGeneral(args []string, opts options) []string { if opts.title != nil { args = append(args, "--title", *opts.title) diff --git a/util_unix_test.go b/util_test.go similarity index 66% rename from util_unix_test.go rename to util_test.go index 1aa65d2..861dd58 100644 --- a/util_unix_test.go +++ b/util_test.go @@ -1,16 +1,35 @@ -//go:build !windows - package zenity import ( "errors" "os/exec" "reflect" + "runtime" "testing" "github.com/ncruces/zenity/internal/zenutil" ) +func Test_quoteAccelerators(t *testing.T) { + tests := []struct { + name string + text string + want string + }{ + {name: "None", text: "abc", want: "abc"}, + {name: "One", text: "&abc", want: "&&abc"}, + {name: "Two", text: "&a&bc", want: "&&a&&bc"}, + {name: "Three", text: "ab&&c", want: "ab&&&&c"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := quoteAccelerators(tt.text); got != tt.want { + t.Errorf("quoteAccelerators(%q) = %q; want %q", tt.text, got, tt.want) + } + }) + } +} + func Test_appendGeneral(t *testing.T) { got := appendGeneral(nil, options{ title: stringPtr("Title"), @@ -85,7 +104,7 @@ func Test_appendWindowIcon(t *testing.T) { func Test_strResult(t *testing.T) { sentinel := errors.New("sentinel") - cancel := exec.Command("false").Run() + cancel := exit1Cmd().Run() if out, err := strResult(options{}, []byte("out"), nil); out != "out" || err != nil { t.Errorf(`strResult("out", nil) = %q, %v`, out, err) @@ -101,10 +120,10 @@ func Test_strResult(t *testing.T) { func Test_lstResult(t *testing.T) { zenutil.Separator = "|" sentinel := errors.New("sentinel") - cancel := exec.Command("false").Run() + cancel := exit1Cmd().Run() if out, err := lstResult(options{}, []byte(""), nil); !reflect.DeepEqual(out, []string{}) || err != nil { - t.Errorf(`lstResult("out", nil) = %v, %v`, out, err) + t.Errorf(`lstResult("", nil) = %v, %v`, out, err) } if out, err := lstResult(options{}, []byte("out"), nil); !reflect.DeepEqual(out, []string{"out"}) || err != nil { t.Errorf(`lstResult("out", nil) = %v, %v`, out, err) @@ -119,3 +138,35 @@ func Test_lstResult(t *testing.T) { t.Errorf(`lstResult("out", cancel) = %v, %v`, out, err) } } + +func Test_pwdResult(t *testing.T) { + username := options{username: true} + sentinel := errors.New("sentinel") + cancel := exit1Cmd().Run() + + if usr, pwd, err := pwdResult("|", options{}, []byte(""), nil); usr != "" || pwd != "" || err != nil { + t.Errorf(`pwdResult("", nil) = %v, %q, %q`, usr, pwd, err) + } + if usr, pwd, err := pwdResult("|", options{}, []byte("out"), nil); usr != "" || pwd != "out" || err != nil { + t.Errorf(`pwdResult("out", nil) = %v, %q, %q`, usr, pwd, err) + } + if usr, pwd, err := pwdResult("|", username, []byte("one|two"), nil); usr != "one" || pwd != "two" || err != nil { + t.Errorf(`pwdResult("one|two", nil) = %v, %q, %q`, usr, pwd, err) + } + if usr, pwd, err := pwdResult("|", options{}, []byte("one|two"), nil); usr != "" || pwd != "one|two" || err != nil { + t.Errorf(`pwdResult("one|two", nil) = %v, %q, %q`, usr, pwd, err) + } + if usr, pwd, err := pwdResult("|", options{}, []byte("out"), sentinel); usr != "" || pwd != "" || err != sentinel { + t.Errorf(`pwdResult("out", error) = %v, %q, %q`, usr, pwd, err) + } + if usr, pwd, err := pwdResult("|", options{}, []byte("out"), cancel); usr != "" || pwd != "" || err != ErrCanceled { + t.Errorf(`pwdResult("out", cancel) = %v, %q, %q`, usr, pwd, err) + } +} + +func exit1Cmd() *exec.Cmd { + if runtime.GOOS == "windows" { + return exec.Command("cmd", "/k", "exit", "1") + } + return exec.Command("false") +} diff --git a/zenity_test.go b/zenity_test.go index 9ca6c85..8eb5d14 100644 --- a/zenity_test.go +++ b/zenity_test.go @@ -42,6 +42,8 @@ func Test_applyOptions(t *testing.T) { {name: "Username", args: Username(), want: options{username: true}}, // List options + {name: "CheckList", args: CheckList(), want: options{listKind: checkListKind}}, + {name: "RadioList", args: RadioList(), want: options{listKind: radioListKind}}, {name: "DisallowEmpty", args: DisallowEmpty(), want: options{disallowEmpty: true}}, {name: "DefaultItems", args: DefaultItems("a", "b"), want: options{defaultItems: []string{"a", "b"}}},