File dialogs for macos.
This commit is contained in:
parent
b477ca2786
commit
5dd85636fd
3 changed files with 196 additions and 0 deletions
138
dialog/dialog_darwin.go
Normal file
138
dialog/dialog_darwin.go
Normal file
|
@ -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("<script>") : len(slice)-len("</script>")])
|
||||
}
|
||||
|
||||
var script = template.Must(template.New("").Parse(`<script>
|
||||
var app = Application.currentApplication();
|
||||
app.includeStandardAdditions = true;
|
||||
|
||||
var opts = {};
|
||||
opts.withPrompt = {{.Title}};
|
||||
opts.multipleSelectionsAllowed = {{.Multiple}};
|
||||
|
||||
{{if .DefaultPath}}
|
||||
opts.defaultLocation = {{.DefaultPath}};
|
||||
{{end}}
|
||||
{{if .Filter}}
|
||||
opts.ofType = {{.Filter}};
|
||||
{{end}}
|
||||
|
||||
var ret = app[{{.Operation}}](opts);
|
||||
if (Array.isArray(ret)) {
|
||||
ret.join('\0');
|
||||
} else {
|
||||
ret.toString();
|
||||
}
|
||||
</script>`))
|
55
dialog/dialog_test.go
Normal file
55
dialog/dialog_test.go
Normal file
|
@ -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)
|
||||
}
|
||||
}
|
3
go.mod
Normal file
3
go.mod
Normal file
|
@ -0,0 +1,3 @@
|
|||
module github.com/ncruces/go-ui
|
||||
|
||||
go 1.13
|
Loading…
Reference in a new issue