99 lines
2.6 KiB
Go
99 lines
2.6 KiB
Go
//go:build darwin
|
|
|
|
package clipboard
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
)
|
|
|
|
type darwinClipboard struct{}
|
|
|
|
// New creates a macOS clipboard (pbpaste/pbcopy).
|
|
func New() (Clipboard, error) {
|
|
return newDarwinClipboard()
|
|
}
|
|
|
|
func newDarwinClipboard() (*darwinClipboard, error) {
|
|
// Verify pbpaste and pbcopy are available
|
|
if err := checkBinary("pbpaste"); err != nil {
|
|
return nil, fmt.Errorf("clip-sync: pbpaste not found: %w", err)
|
|
}
|
|
if err := checkBinary("pbcopy"); err != nil {
|
|
return nil, fmt.Errorf("clip-sync: pbcopy not found: %w", err)
|
|
}
|
|
return &darwinClipboard{}, nil
|
|
}
|
|
|
|
func (c *darwinClipboard) Read() (string, error) {
|
|
cmd := exec.Command("pbpaste")
|
|
out, err := cmd.Output()
|
|
if err != nil {
|
|
return "", fmt.Errorf("clipboard read (pbpaste): %w", err)
|
|
}
|
|
return strings.TrimRight(string(out), "\n\r"), nil
|
|
}
|
|
|
|
func (c *darwinClipboard) Write(text string) error {
|
|
cmd := exec.Command("pbcopy")
|
|
cmd.Stdin = strings.NewReader(text)
|
|
if err := cmd.Run(); err != nil {
|
|
return fmt.Errorf("clipboard write (pbcopy): %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ReadImage reads a PNG image from the clipboard via AppleScript, writing it to
|
|
// a temporary file and reading it back.
|
|
func (c *darwinClipboard) ReadImage() (string, []byte, error) {
|
|
tmp, err := os.CreateTemp("", "clip-sync-*.png")
|
|
if err != nil {
|
|
return "", nil, err
|
|
}
|
|
tmpPath := tmp.Name()
|
|
tmp.Close()
|
|
defer os.Remove(tmpPath)
|
|
|
|
// AppleScript type code PNGf, wrapped in the chevron quotes AppleScript uses.
|
|
script := `set f to (open for access POSIX file "` + tmpPath + `" with write permission)
|
|
set eof f to 0
|
|
write (the clipboard as «class PNGf») to f
|
|
close access f`
|
|
if err := exec.Command("osascript", "-e", script).Run(); err != nil {
|
|
return "", nil, ErrNoImage
|
|
}
|
|
|
|
data, err := os.ReadFile(tmpPath)
|
|
if err != nil || len(data) == 0 {
|
|
return "", nil, ErrNoImage
|
|
}
|
|
return "image/png", data, nil
|
|
}
|
|
|
|
// WriteImage writes a PNG image to the clipboard via AppleScript.
|
|
func (c *darwinClipboard) WriteImage(mime string, data []byte) error {
|
|
if mime != "" && mime != "image/png" {
|
|
return fmt.Errorf("clipboard: unsupported image mime %q (only PNG)", mime)
|
|
}
|
|
tmp, err := os.CreateTemp("", "clip-sync-*.png")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if _, err := tmp.Write(data); err != nil {
|
|
tmp.Close()
|
|
os.Remove(tmp.Name())
|
|
return err
|
|
}
|
|
tmpPath := tmp.Name()
|
|
tmp.Close()
|
|
defer os.Remove(tmpPath)
|
|
|
|
script := `set the clipboard to (read (POSIX file "` + tmpPath + `") as «class PNGf»)`
|
|
if err := exec.Command("osascript", "-e", script).Run(); err != nil {
|
|
return fmt.Errorf("clipboard write image (osascript): %w", err)
|
|
}
|
|
return nil
|
|
}
|