85 lines
2.1 KiB
Go
85 lines
2.1 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"os/exec"
|
|
"runtime"
|
|
)
|
|
|
|
type textClipboard interface {
|
|
ReadText() (string, error)
|
|
WriteText(string) error
|
|
}
|
|
|
|
type systemTextClipboard struct{}
|
|
|
|
func (systemTextClipboard) ReadText() (string, error) {
|
|
command, args, err := clipboardCommand(false)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
output, err := exec.Command(command, args...).Output()
|
|
if err != nil {
|
|
return "", fmt.Errorf("read system clipboard: %w", err)
|
|
}
|
|
return string(output), nil
|
|
}
|
|
|
|
func (systemTextClipboard) WriteText(value string) error {
|
|
command, args, err := clipboardCommand(true)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
process := exec.Command(command, args...)
|
|
process.Stdin = bytes.NewBufferString(value)
|
|
if output, err := process.CombinedOutput(); err != nil {
|
|
if len(output) > 0 {
|
|
return fmt.Errorf("write system clipboard: %w: %s", err, bytes.TrimSpace(output))
|
|
}
|
|
return fmt.Errorf("write system clipboard: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func clipboardCommand(write bool) (string, []string, error) {
|
|
switch runtime.GOOS {
|
|
case "darwin":
|
|
if write {
|
|
return "pbcopy", nil, nil
|
|
}
|
|
return "pbpaste", nil, nil
|
|
case "windows":
|
|
script := "Get-Clipboard -Raw"
|
|
if write {
|
|
script = "$input | Set-Clipboard"
|
|
}
|
|
return "powershell.exe", []string{"-NoProfile", "-NonInteractive", "-Command", script}, nil
|
|
default:
|
|
type candidate struct {
|
|
command string
|
|
write []string
|
|
read []string
|
|
}
|
|
candidates := []candidate{
|
|
{command: "wl-copy", read: []string{"-n"}, write: nil},
|
|
{command: "xclip", read: []string{"-selection", "clipboard", "-o"}, write: []string{"-selection", "clipboard", "-i"}},
|
|
{command: "xsel", read: []string{"--clipboard", "--output"}, write: []string{"--clipboard", "--input"}},
|
|
}
|
|
for _, candidate := range candidates {
|
|
command := candidate.command
|
|
args := candidate.read
|
|
if candidate.command == "wl-copy" && !write {
|
|
command = "wl-paste"
|
|
}
|
|
if write {
|
|
args = candidate.write
|
|
}
|
|
if _, err := exec.LookPath(command); err == nil {
|
|
return command, args, nil
|
|
}
|
|
}
|
|
return "", nil, fmt.Errorf("system clipboard unavailable: install wl-clipboard, xclip, or xsel")
|
|
}
|
|
}
|