From 5dd85636fd4ce153d32c60ff9061fcd83b832236 Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Wed, 11 Dec 2019 10:29:31 +0000 Subject: [PATCH] File dialogs for macos. --- dialog/dialog_darwin.go | 138 ++++++++++++++++++++++++++++++++++++++++ dialog/dialog_test.go | 55 ++++++++++++++++ go.mod | 3 + 3 files changed, 196 insertions(+) create mode 100644 dialog/dialog_darwin.go create mode 100644 dialog/dialog_test.go create mode 100644 go.mod diff --git a/dialog/dialog_darwin.go b/dialog/dialog_darwin.go new file mode 100644 index 0000000..9a2780e --- /dev/null +++ b/dialog/dialog_darwin.go @@ -0,0 +1,138 @@ +package dialog + +import ( + "bytes" + "html/template" + "io" + "os/exec" + "strings" +) + +func OpenFile(title, defaultPath string, filters []FileFilter) (string, error) { + cmd := exec.Command("osascript", "-l", "JavaScript") + cmd.Stdin = scriptExpand(scriptData{ + Operation: "chooseFile", + Title: title, + DefaultPath: defaultPath, + Filter: toFilter(filters), + }) + out, err := cmd.Output() + if err != nil { + return "", err + } + if len(out) > 0 { + out = out[:len(out)-1] + } + return string(out), nil +} + +func OpenFiles(title, defaultPath string, filters []FileFilter) ([]string, error) { + cmd := exec.Command("osascript", "-l", "JavaScript") + cmd.Stdin = scriptExpand(scriptData{ + Operation: "chooseFile", + Multiple: true, + Title: title, + DefaultPath: defaultPath, + Filter: toFilter(filters), + }) + out, err := cmd.Output() + if err != nil { + return nil, err + } + if len(out) > 0 { + out = out[:len(out)-1] + } + return strings.Split(string(out), "\x00"), nil +} + +func SaveFile(title, defaultPath string, filters []FileFilter) (string, error) { + cmd := exec.Command("osascript", "-l", "JavaScript") + cmd.Stdin = scriptExpand(scriptData{ + Operation: "chooseFileName", + Title: title, + DefaultPath: defaultPath, + }) + out, err := cmd.Output() + if err != nil { + return "", err + } + if len(out) > 0 { + out = out[:len(out)-1] + } + return string(out), nil +} + +func PickFolder(title, defaultPath string) (string, error) { + cmd := exec.Command("osascript", "-l", "JavaScript") + cmd.Stdin = scriptExpand(scriptData{ + Operation: "chooseFolder", + Title: title, + DefaultPath: defaultPath, + }) + out, err := cmd.Output() + if err != nil { + return "", err + } + if len(out) > 0 { + out = out[:len(out)-1] + } + return string(out), nil +} + +type FileFilter struct { + Name string + Exts []string +} + +func toFilter(filters []FileFilter) []string { + var filter []string + for _, f := range filters { + for _, e := range f.Exts { + filter = append(filter, strings.TrimPrefix(e, ".")) + } + } + return filter +} + +type scriptData struct { + Operation string + Title string + DefaultPath string + Filter []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/dialog/dialog_test.go b/dialog/dialog_test.go new file mode 100644 index 0000000..211fdaa --- /dev/null +++ b/dialog/dialog_test.go @@ -0,0 +1,55 @@ +package dialog + +import "testing" + +func TestOpenFile(t *testing.T) { + ret, err := OpenFile("", "", []FileFilter{ + {"Go files", []string{".go"}}, + {"Web files", []string{".html", ".js", ".css"}}, + {"Image files", []string{".png", ".ico"}}, + }) + + if err != nil { + t.Error(err) + } else { + t.Logf("%#v", ret) + } +} + +func TestOpenFiles(t *testing.T) { + ret, err := OpenFiles("", "", []FileFilter{ + {"Go files", []string{".go"}}, + {"Web files", []string{".html", ".js", ".css"}}, + {"Image files", []string{".png", ".ico"}}, + }) + + if err != nil { + t.Error(err) + } else { + t.Logf("%#v", ret) + } +} + +func TestSaveFile(t *testing.T) { + ret, err := SaveFile("", "", []FileFilter{ + {"Go files", []string{".go"}}, + {"Web files", []string{".html", ".js", ".css"}}, + {"Image files", []string{".png", ".ico"}}, + }) + + if err != nil { + t.Error(err) + } else { + t.Logf("%#v", ret) + } +} + +func TestPickFolder(t *testing.T) { + ret, err := PickFolder("", "") + + if err != nil { + t.Error(err) + } else { + t.Logf("%#v", ret) + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ed74fb0 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/ncruces/go-ui + +go 1.13