diff --git a/.gitignore b/.gitignore
index 66fd13c..8311b1d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,3 +13,5 @@
# Dependency directories (remove the comment below to include it)
# vendor/
+
+osa_gen_darwin.go
\ No newline at end of file
diff --git a/file.go b/file.go
deleted file mode 100644
index 9b23b7d..0000000
--- a/file.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package zenity
-
-type opts struct {
- title string
-}
-
-type Option func(*opts)
-
-func (o *opts) Title(title string) {
- o.title = title
-}
-
-type fileopts struct {
- opts
- filename string
- overwrite bool
- filters []FileFilter
-}
-
-type FileOption func(*fileopts)
-
-func Filename(filename string) FileOption {
- return func(o *fileopts) {
- o.filename = filename
- }
-}
-
-func ConfirmOverwrite(o *fileopts) {
- o.overwrite = true
-}
-
-type FileFilter struct {
- Name string
- Exts []string
-}
-
-type FileFilters []FileFilter
-
-func (f FileFilters) New() FileOption {
- return func(o *fileopts) {
- o.filters = f
- }
-}
-
-func fileoptsParse(options []FileOption) (res fileopts) {
- for _, o := range options {
- o(&res)
- }
- return
-}
diff --git a/file_darwin.go b/file_darwin.go
index 3551757..e46ad9e 100644
--- a/file_darwin.go
+++ b/file_darwin.go
@@ -1,24 +1,17 @@
package zenity
import (
- "bytes"
- "html/template"
- "io"
- "os/exec"
"strings"
)
-func SelectFile(options ...FileOption) (string, error) {
- opts := fileoptsParse(options)
-
- cmd := exec.Command("osascript", "-l", "JavaScript")
- cmd.Stdin = scriptExpand(scriptData{
+func SelectFile(options ...Option) (string, error) {
+ opts := optsParse(options)
+ out, err := osaRun("file", osaFile{
Operation: "chooseFile",
Prompt: opts.title,
Location: opts.filename,
Type: appleFilters(opts.filters),
})
- out, err := cmd.Output()
if err != nil {
return "", err
}
@@ -28,18 +21,15 @@ func SelectFile(options ...FileOption) (string, error) {
return string(out), nil
}
-func SelectFileMutiple(options ...FileOption) ([]string, error) {
- opts := fileoptsParse(options)
-
- cmd := exec.Command("osascript", "-l", "JavaScript")
- cmd.Stdin = scriptExpand(scriptData{
+func SelectFileMutiple(options ...Option) ([]string, error) {
+ opts := optsParse(options)
+ out, err := osaRun("file", osaFile{
Operation: "chooseFile",
Multiple: true,
Prompt: opts.title,
Location: opts.filename,
Type: appleFilters(opts.filters),
})
- out, err := cmd.Output()
if err != nil {
return nil, err
}
@@ -52,16 +42,13 @@ func SelectFileMutiple(options ...FileOption) ([]string, error) {
return strings.Split(string(out), "\x00"), nil
}
-func SelectFileSave(options ...FileOption) (string, error) {
- opts := fileoptsParse(options)
-
- cmd := exec.Command("osascript", "-l", "JavaScript")
- cmd.Stdin = scriptExpand(scriptData{
+func SelectFileSave(options ...Option) (string, error) {
+ opts := optsParse(options)
+ out, err := osaRun("file", osaFile{
Operation: "chooseFileName",
Prompt: opts.title,
Location: opts.filename,
})
- out, err := cmd.Output()
if err != nil {
return "", err
}
@@ -71,16 +58,13 @@ func SelectFileSave(options ...FileOption) (string, error) {
return string(out), nil
}
-func SelectDirectory(options ...FileOption) (string, error) {
- opts := fileoptsParse(options)
-
- cmd := exec.Command("osascript", "-l", "JavaScript")
- cmd.Stdin = scriptExpand(scriptData{
+func SelectDirectory(options ...Option) (string, error) {
+ opts := optsParse(options)
+ out, err := osaRun("file", osaFile{
Operation: "chooseFolder",
Prompt: opts.title,
Location: opts.filename,
})
- out, err := cmd.Output()
if err != nil {
return "", err
}
@@ -100,53 +84,10 @@ func appleFilters(filters []FileFilter) []string {
return filter
}
-type scriptData struct {
+type osaFile struct {
Operation string
Prompt string
Location string
Type []string
Multiple bool
}
-
-func scriptExpand(data scriptData) io.Reader {
- var buf bytes.Buffer
-
- err := script.Execute(&buf, data)
- if err != nil {
- panic(err)
- }
-
- var slice = buf.Bytes()
- return bytes.NewReader(slice[len("")])
-}
-
-var script = template.Must(template.New("").Parse(``))
diff --git a/file_linux.go b/file_linux.go
index 3d204f4..a6a410d 100644
--- a/file_linux.go
+++ b/file_linux.go
@@ -5,15 +5,15 @@ import (
"strings"
)
-func SelectFile(options ...FileOption) (string, error) {
- opts := fileoptsParse(options)
+func SelectFile(options ...Option) (string, error) {
+ opts := optsParse(options)
args := []string{"--file-selection"}
if opts.title != "" {
- args = append(args, "--title="+opts.title)
+ args = append(args, "--title", opts.title)
}
if opts.filename != "" {
- args = append(args, "--filename="+opts.filename)
+ args = append(args, "--filename", opts.filename)
}
args = append(args, zenityFilters(opts.filters)...)
cmd := exec.Command("zenity", args...)
@@ -30,15 +30,15 @@ func SelectFile(options ...FileOption) (string, error) {
return string(out), nil
}
-func SelectFileMutiple(options ...FileOption) ([]string, error) {
- opts := fileoptsParse(options)
+func SelectFileMutiple(options ...Option) ([]string, error) {
+ opts := optsParse(options)
args := []string{"--file-selection", "--multiple", "--separator=\x1e"}
if opts.title != "" {
- args = append(args, "--title="+opts.title)
+ args = append(args, "--title", opts.title)
}
if opts.filename != "" {
- args = append(args, "--filename="+opts.filename)
+ args = append(args, "--filename", opts.filename)
}
args = append(args, zenityFilters(opts.filters)...)
cmd := exec.Command("zenity", args...)
@@ -55,15 +55,15 @@ func SelectFileMutiple(options ...FileOption) ([]string, error) {
return strings.Split(string(out), "\x1e"), nil
}
-func SelectFileSave(options ...FileOption) (string, error) {
- opts := fileoptsParse(options)
+func SelectFileSave(options ...Option) (string, error) {
+ opts := optsParse(options)
args := []string{"--file-selection", "--save"}
if opts.title != "" {
- args = append(args, "--title="+opts.title)
+ args = append(args, "--title", opts.title)
}
if opts.filename != "" {
- args = append(args, "--filename="+opts.filename)
+ args = append(args, "--filename", opts.filename)
}
if opts.overwrite {
args = append(args, "--confirm-overwrite")
@@ -83,15 +83,15 @@ func SelectFileSave(options ...FileOption) (string, error) {
return string(out), nil
}
-func SelectDirectory(options ...FileOption) (string, error) {
- opts := fileoptsParse(options)
+func SelectDirectory(options ...Option) (string, error) {
+ opts := optsParse(options)
args := []string{"--file-selection", "--directory"}
if opts.title != "" {
- args = append(args, "--title="+opts.title)
+ args = append(args, "--title", opts.title)
}
if opts.filename != "" {
- args = append(args, "--filename="+opts.filename)
+ args = append(args, "--filename", opts.filename)
}
cmd := exec.Command("zenity", args...)
out, err := cmd.Output()
diff --git a/file_windows.go b/file_windows.go
index 664b2c0..1c75dcd 100644
--- a/file_windows.go
+++ b/file_windows.go
@@ -27,12 +27,12 @@ var (
shCreateItemFromParsingName = shell32.NewProc("SHCreateItemFromParsingName")
)
-func SelectFile(options ...FileOption) (string, error) {
+func SelectFile(options ...Option) (string, error) {
var args _OPENFILENAME
args.StructSize = uint32(unsafe.Sizeof(args))
args.Flags = 0x80008 // OFN_NOCHANGEDIR|OFN_EXPLORER
- opts := fileoptsParse(options)
+ opts := optsParse(options)
if opts.title != "" {
args.Title = syscall.StringToUTF16Ptr(opts.title)
}
@@ -55,12 +55,12 @@ func SelectFile(options ...FileOption) (string, error) {
return syscall.UTF16ToString(res[:]), nil
}
-func SelectFileMutiple(options ...FileOption) ([]string, error) {
+func SelectFileMutiple(options ...Option) ([]string, error) {
var args _OPENFILENAME
args.StructSize = uint32(unsafe.Sizeof(args))
args.Flags = 0x80208 // OFN_NOCHANGEDIR|OFN_ALLOWMULTISELECT|OFN_EXPLORER
- opts := fileoptsParse(options)
+ opts := optsParse(options)
if opts.title != "" {
args.Title = syscall.StringToUTF16Ptr(opts.title)
}
@@ -108,12 +108,12 @@ func SelectFileMutiple(options ...FileOption) ([]string, error) {
return split, nil
}
-func SelectFileSave(options ...FileOption) (string, error) {
+func SelectFileSave(options ...Option) (string, error) {
var args _OPENFILENAME
args.StructSize = uint32(unsafe.Sizeof(args))
args.Flags = 0x80008 // OFN_NOCHANGEDIR|OFN_EXPLORER
- opts := fileoptsParse(options)
+ opts := optsParse(options)
if opts.title != "" {
args.Title = syscall.StringToUTF16Ptr(opts.title)
}
@@ -139,7 +139,7 @@ func SelectFileSave(options ...FileOption) (string, error) {
return syscall.UTF16ToString(res[:]), nil
}
-func SelectDirectory(options ...FileOption) (string, error) {
+func SelectDirectory(options ...Option) (string, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
@@ -151,7 +151,7 @@ func SelectDirectory(options ...FileOption) (string, error) {
defer coUninitialize.Call()
}
- opts := fileoptsParse(options)
+ opts := optsParse(options)
var dialog *_IFileOpenDialog
hr, _, _ = coCreateInstance.Call(
diff --git a/msg_darwin.go b/msg_darwin.go
new file mode 100644
index 0000000..cfb945a
--- /dev/null
+++ b/msg_darwin.go
@@ -0,0 +1,119 @@
+package zenity
+
+import (
+ "os/exec"
+)
+
+func Error(text string, options ...Option) (bool, error) {
+ return message(0, text, options)
+}
+
+func Info(text string, options ...Option) (bool, error) {
+ return message(1, text, options)
+}
+
+func Question(text string, options ...Option) (bool, error) {
+ return message(2, text, options)
+}
+
+func Warning(text string, options ...Option) (bool, error) {
+ return message(3, text, options)
+}
+
+func message(dialog int, text string, options []Option) (bool, error) {
+ opts := optsParse(options)
+
+ data := osaMsg{
+ Text: text,
+ Title: opts.title,
+ Dialog: opts.icon != 0 || dialog == 2,
+ }
+
+ if data.Dialog {
+ switch opts.icon {
+ case ErrorIcon:
+ data.Icon = "stop"
+ case InfoIcon, QuestionIcon:
+ data.Icon = "note"
+ case WarningIcon:
+ data.Icon = "caution"
+ }
+ } else {
+ switch dialog {
+ case 0:
+ data.As = "critical"
+ case 1:
+ data.As = "informational"
+ case 3:
+ data.As = "warning"
+ }
+
+ if opts.title != "" {
+ data.Text = opts.title
+ data.Message = text
+ }
+ }
+
+ if dialog != 2 {
+ opts.cancel = ""
+ if data.Dialog {
+ opts.ok = "OK"
+ }
+ }
+ if opts.ok != "" || opts.cancel != "" || opts.extra != "" || true {
+ if opts.ok == "" {
+ opts.ok = "OK"
+ }
+ if opts.cancel == "" {
+ opts.cancel = "Cancel"
+ }
+ if dialog == 2 {
+ if opts.extra == "" {
+ data.Buttons = []string{opts.cancel, opts.ok}
+ data.Default = 2
+ data.Cancel = 1
+ } else {
+ data.Buttons = []string{opts.extra, opts.cancel, opts.ok}
+ data.Default = 3
+ data.Cancel = 2
+ }
+ } else {
+ if opts.extra == "" {
+ data.Buttons = []string{opts.ok}
+ data.Default = 1
+ } else {
+ data.Buttons = []string{opts.extra, opts.ok}
+ data.Default = 2
+ }
+ }
+ }
+ if opts.defcancel {
+ if data.Cancel != 0 {
+ data.Default = data.Cancel
+ }
+ if data.Dialog && data.Buttons == nil {
+ data.Default = 1
+ }
+ }
+
+ _, err := osaRun("msg", data)
+ if err, ok := err.(*exec.ExitError); ok && err.ExitCode() == 1 {
+ return false, nil
+ }
+ if err != nil {
+ return false, err
+ }
+ return true, err
+}
+
+type osaMsg struct {
+ Dialog bool
+ Text string
+ Message string
+ As string
+ Title string
+ Icon string
+ Buttons []string
+ Cancel int
+ Default int
+}
diff --git a/msg_linux.go b/msg_linux.go
new file mode 100644
index 0000000..6911a74
--- /dev/null
+++ b/msg_linux.go
@@ -0,0 +1,66 @@
+package zenity
+
+import "os/exec"
+
+func Error(text string, options ...Option) (bool, error) {
+ return message("--error", text, options)
+}
+
+func Info(text string, options ...Option) (bool, error) {
+ return message("--info", text, options)
+}
+
+func Question(text string, options ...Option) (bool, error) {
+ return message("--question", text, options)
+}
+
+func Warning(text string, options ...Option) (bool, error) {
+ return message("--warning", text, options)
+}
+
+func message(arg, text string, options []Option) (bool, error) {
+ opts := optsParse(options)
+
+ args := []string{arg, "--text", text, "--no-markup"}
+ if opts.title != "" {
+ args = append(args, "--title", opts.title)
+ }
+ if opts.ok != "" {
+ args = append(args, "--ok-label", opts.ok)
+ }
+ if opts.cancel != "" {
+ args = append(args, "--cancel-label", opts.cancel)
+ }
+ if opts.extra != "" {
+ args = append(args, "--extra-button", opts.extra)
+ }
+ if opts.nowrap {
+ args = append(args, "--no-wrap")
+ }
+ if opts.ellipsize {
+ args = append(args, "--ellipsize")
+ }
+ if opts.defcancel {
+ args = append(args, "--default-cancel")
+ }
+ switch opts.icon {
+ case ErrorIcon:
+ args = append(args, "--icon-name=dialog-error")
+ case InfoIcon:
+ args = append(args, "--icon-name=dialog-information")
+ case QuestionIcon:
+ args = append(args, "--icon-name=dialog-question")
+ case WarningIcon:
+ args = append(args, "--icon-name=dialog-warning")
+ }
+
+ cmd := exec.Command("zenity", args...)
+ _, err := cmd.Output()
+ if err, ok := err.(*exec.ExitError); ok && err.ExitCode() == 1 {
+ return false, nil
+ }
+ if err != nil {
+ return false, err
+ }
+ return true, err
+}
diff --git a/msg_test.go b/msg_test.go
new file mode 100644
index 0000000..67fd5b2
--- /dev/null
+++ b/msg_test.go
@@ -0,0 +1,43 @@
+package zenity
+
+import "testing"
+
+func TestError(t *testing.T) {
+ res, err := Error("An error has occured.", Title("Error"), Icon(ErrorIcon))
+
+ if err != nil {
+ t.Error(err)
+ } else {
+ t.Logf("%#v", res)
+ }
+}
+
+func TestInfo(t *testing.T) {
+ res, err := Info("All updates are complete.", Title("Information"), Icon(InfoIcon))
+
+ if err != nil {
+ t.Error(err)
+ } else {
+ t.Logf("%#v", res)
+ }
+}
+
+func TestWarning(t *testing.T) {
+ res, err := Warning("Are you sure you want to proceed?", Title("Warning"), Icon(WarningIcon))
+
+ if err != nil {
+ t.Error(err)
+ } else {
+ t.Logf("%#v", res)
+ }
+}
+
+func TestQuestion(t *testing.T) {
+ res, err := Question("Are you sure you want to proceed?", Title("Question"), Icon(QuestionIcon))
+
+ if err != nil {
+ t.Error(err)
+ } else {
+ t.Logf("%#v", res)
+ }
+}
diff --git a/msg_windows.go b/msg_windows.go
new file mode 100644
index 0000000..87e94ce
--- /dev/null
+++ b/msg_windows.go
@@ -0,0 +1,65 @@
+package zenity
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ user32 = syscall.NewLazyDLL("user32.dll")
+ messageBox = user32.NewProc("MessageBoxW")
+)
+
+func Error(text string, options ...Option) (bool, error) {
+ return message(0, text, options)
+}
+
+func Info(text string, options ...Option) (bool, error) {
+ return message(1, text, options)
+}
+
+func Question(text string, options ...Option) (bool, error) {
+ return message(2, text, options)
+}
+
+func Warning(text string, options ...Option) (bool, error) {
+ return message(3, text, options)
+}
+
+func message(dialog int, text string, options []Option) (bool, error) {
+ opts := optsParse(options)
+
+ var flags, caption uintptr
+
+ switch {
+ case dialog == 2 && opts.extra != "":
+ flags |= 0x3 // MB_YESNOCANCEL
+ case dialog == 2 || opts.extra != "":
+ flags |= 0x1 // MB_OKCANCEL
+ }
+
+ switch opts.icon {
+ case ErrorIcon:
+ flags |= 0x10 // MB_ICONERROR
+ case QuestionIcon:
+ flags |= 0x20 // MB_ICONQUESTION
+ case WarningIcon:
+ flags |= 0x30 // MB_ICONWARNING
+ case InfoIcon:
+ flags |= 0x40 // MB_ICONINFORMATION
+ }
+
+ if opts.title != "" {
+ caption = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(opts.title)))
+ }
+
+ n, _, err := messageBox.Call(0,
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))),
+ caption, flags)
+
+ if n == 0 {
+ return false, err
+ } else {
+ return n == 1 /* IDOK */ || n == 6 /* IDYES */, nil
+ }
+}
diff --git a/osa_darwin.go b/osa_darwin.go
new file mode 100644
index 0000000..4f5c793
--- /dev/null
+++ b/osa_darwin.go
@@ -0,0 +1,22 @@
+package zenity
+
+import (
+ "os/exec"
+ "strings"
+)
+
+//go:generate go run osa_scripts/generate.go osa_scripts/
+
+func osaRun(script string, data interface{}) ([]byte, error) {
+ var buf strings.Builder
+
+ err := osaScripts.ExecuteTemplate(&buf, script, data)
+ if err != nil {
+ return nil, err
+ }
+
+ var res = buf.String()
+ cmd := exec.Command("osascript", "-l", "JavaScript")
+ cmd.Stdin = strings.NewReader(res[len("")])
+ return cmd.Output()
+}
diff --git a/osa_scripts/file.gots b/osa_scripts/file.gots
new file mode 100644
index 0000000..acaf673
--- /dev/null
+++ b/osa_scripts/file.gots
@@ -0,0 +1,28 @@
+var app = Application.currentApplication()
+app.includeStandardAdditions = true
+app.activate()
+
+var opts = {}
+opts.withPrompt = {{.Prompt}}
+opts.multipleSelectionsAllowed = {{.Multiple}}
+
+{{if .Location -}}
+ opts.defaultLocation = {{.Location}}
+{{end -}}
+{{if .Type -}}
+ opts.ofType = {{.Type}}
+{{end -}}
+
+var res
+try {
+ res = app[{{.Operation}}](opts)
+} catch (e) {
+ if (e.errorNumber !== -128) throw e
+}
+if (Array.isArray(res)) {
+ res.join('\0')
+} else if (res != null) {
+ res.toString()
+} else {
+ void 0
+}
\ No newline at end of file
diff --git a/osa_scripts/generate.go b/osa_scripts/generate.go
new file mode 100644
index 0000000..30c3049
--- /dev/null
+++ b/osa_scripts/generate.go
@@ -0,0 +1,76 @@
+package main
+
+import (
+ "bufio"
+ "io/ioutil"
+ "log"
+ "os"
+ "path/filepath"
+ "strings"
+ "text/template"
+)
+
+func main() {
+ dir := os.Args[1]
+
+ files, err := ioutil.ReadDir(dir)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ var str strings.Builder
+
+ for _, file := range files {
+ if name := file.Name(); filepath.Ext(name) == ".gots" {
+ str.WriteString("\n" + `{{define "`)
+ str.WriteString(strings.TrimSuffix(name, ".gots"))
+ str.WriteString(`"}}{{end}}")
+ }
+ }
+
+ out, err := os.Create("osa_gen_darwin.go")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ err = generator.Execute(out, str.String())
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ err = out.Close()
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+var generator = template.Must(template.New("").Parse(`// Code generated by zenity; DO NOT EDIT.
+
+package zenity
+
+import "html/template"
+
+var osaScripts = template.Must(template.New("").Parse(` + "`{{.}}`" + `))
+`))
diff --git a/osa_scripts/msg.gots b/osa_scripts/msg.gots
new file mode 100644
index 0000000..ffea618
--- /dev/null
+++ b/osa_scripts/msg.gots
@@ -0,0 +1,33 @@
+var app = Application.currentApplication()
+app.includeStandardAdditions = true
+app.activate()
+
+var opts = {}
+
+{{if .Buttons -}}
+ opts.buttons = {{.Buttons}}
+{{end -}}
+{{if .Default -}}
+ opts.defaultButton = {{.Default}}
+{{end -}}
+{{if .Cancel -}}
+ opts.cancelButton = {{.Cancel}}
+{{end -}}
+
+{{if .Dialog -}}
+ {{if .Title -}}
+ opts.withTitle = {{.Title}}
+ {{end -}}
+ {{if .Icon -}}
+ opts.withIcon = {{.Icon}}
+ {{end -}}
+ app.displayDialog({{.Text}}, opts)
+{{else -}}
+ {{if .As -}}
+ opts.as = {{.As}}
+ {{end -}}
+ {{if .Message -}}
+ opts.message = {{.Message}}
+ {{end -}}
+ app.displayAlert({{.Text}}, opts)
+{{end -}}
\ No newline at end of file
diff --git a/zenity.go b/zenity.go
new file mode 100644
index 0000000..97a263e
--- /dev/null
+++ b/zenity.go
@@ -0,0 +1,109 @@
+package zenity
+
+type options struct {
+ // General options
+ title string
+
+ // File selection options
+ filename string
+ overwrite bool
+ filters []FileFilter
+
+ // Message options
+ icon MessageIcon
+ ok string
+ cancel string
+ extra string
+ nowrap bool
+ ellipsize bool
+ defcancel bool
+}
+
+type Option func(*options)
+
+func optsParse(options []Option) (res options) {
+ for _, o := range options {
+ o(&res)
+ }
+ return
+}
+
+// General options
+
+func Title(title string) Option {
+ return func(o *options) {
+ o.title = title
+ }
+}
+
+// File selection options
+
+func Filename(filename string) Option {
+ return func(o *options) {
+ o.filename = filename
+ }
+}
+
+func ConfirmOverwrite(o *options) {
+ o.overwrite = true
+}
+
+type FileFilter struct {
+ Name string
+ Exts []string
+}
+
+type FileFilters []FileFilter
+
+func (f FileFilters) New() Option {
+ return func(o *options) {
+ o.filters = f
+ }
+}
+
+// Message options
+
+type MessageIcon int
+
+const (
+ ErrorIcon MessageIcon = iota + 1
+ InfoIcon
+ QuestionIcon
+ WarningIcon
+)
+
+func Icon(icon MessageIcon) Option {
+ return func(o *options) {
+ o.icon = icon
+ }
+}
+
+func OKLabel(ok string) Option {
+ return func(o *options) {
+ o.ok = ok
+ }
+}
+
+func CancelLabel(cancel string) Option {
+ return func(o *options) {
+ o.cancel = cancel
+ }
+}
+
+func ExtraButton(extra string) Option {
+ return func(o *options) {
+ o.extra = extra
+ }
+}
+
+func NoWrap(o *options) {
+ o.nowrap = true
+}
+
+func Ellipsize(o *options) {
+ o.ellipsize = true
+}
+
+func DefaultCancel(o *options) {
+ o.defcancel = true
+}