1// Copyright 2013 @atotto. All rights reserved.
  2// Use of this source code is governed by a BSD-style
  3// license that can be found in the LICENSE file.
  4
  5// +build freebsd linux netbsd openbsd solaris dragonfly
  6
  7package clipboard
  8
  9import (
 10	"errors"
 11	"os"
 12	"os/exec"
 13)
 14
 15const (
 16	xsel               = "xsel"
 17	xclip              = "xclip"
 18	powershellExe      = "powershell.exe"
 19	clipExe            = "clip.exe"
 20	wlcopy             = "wl-copy"
 21	wlpaste            = "wl-paste"
 22	termuxClipboardGet = "termux-clipboard-get"
 23	termuxClipboardSet = "termux-clipboard-set"
 24)
 25
 26var (
 27	Primary bool
 28	trimDos bool
 29
 30	pasteCmdArgs []string
 31	copyCmdArgs  []string
 32
 33	xselPasteArgs = []string{xsel, "--output", "--clipboard"}
 34	xselCopyArgs  = []string{xsel, "--input", "--clipboard"}
 35
 36	xclipPasteArgs = []string{xclip, "-out", "-selection", "clipboard"}
 37	xclipCopyArgs  = []string{xclip, "-in", "-selection", "clipboard"}
 38
 39	powershellExePasteArgs = []string{powershellExe, "Get-Clipboard"}
 40	clipExeCopyArgs        = []string{clipExe}
 41
 42	wlpasteArgs = []string{wlpaste, "--no-newline"}
 43	wlcopyArgs  = []string{wlcopy}
 44
 45	termuxPasteArgs = []string{termuxClipboardGet}
 46	termuxCopyArgs  = []string{termuxClipboardSet}
 47
 48	missingCommands = errors.New("No clipboard utilities available. Please install xsel, xclip, wl-clipboard or Termux:API add-on for termux-clipboard-get/set.")
 49)
 50
 51func init() {
 52	if os.Getenv("WAYLAND_DISPLAY") != "" {
 53		pasteCmdArgs = wlpasteArgs
 54		copyCmdArgs = wlcopyArgs
 55
 56		if _, err := exec.LookPath(wlcopy); err == nil {
 57			if _, err := exec.LookPath(wlpaste); err == nil {
 58				return
 59			}
 60		}
 61	}
 62
 63	pasteCmdArgs = xclipPasteArgs
 64	copyCmdArgs = xclipCopyArgs
 65
 66	if _, err := exec.LookPath(xclip); err == nil {
 67		return
 68	}
 69
 70	pasteCmdArgs = xselPasteArgs
 71	copyCmdArgs = xselCopyArgs
 72
 73	if _, err := exec.LookPath(xsel); err == nil {
 74		return
 75	}
 76
 77	pasteCmdArgs = termuxPasteArgs
 78	copyCmdArgs = termuxCopyArgs
 79
 80	if _, err := exec.LookPath(termuxClipboardSet); err == nil {
 81		if _, err := exec.LookPath(termuxClipboardGet); err == nil {
 82			return
 83		}
 84	}
 85
 86	pasteCmdArgs = powershellExePasteArgs
 87	copyCmdArgs = clipExeCopyArgs
 88	trimDos = true
 89
 90	if _, err := exec.LookPath(clipExe); err == nil {
 91		if _, err := exec.LookPath(powershellExe); err == nil {
 92			return
 93		}
 94	}
 95
 96	Unsupported = true
 97}
 98
 99func getPasteCommand() *exec.Cmd {
100	if Primary {
101		pasteCmdArgs = pasteCmdArgs[:1]
102	}
103	return exec.Command(pasteCmdArgs[0], pasteCmdArgs[1:]...)
104}
105
106func getCopyCommand() *exec.Cmd {
107	if Primary {
108		copyCmdArgs = copyCmdArgs[:1]
109	}
110	return exec.Command(copyCmdArgs[0], copyCmdArgs[1:]...)
111}
112
113func readAll() (string, error) {
114	if Unsupported {
115		return "", missingCommands
116	}
117	pasteCmd := getPasteCommand()
118	out, err := pasteCmd.Output()
119	if err != nil {
120		return "", err
121	}
122	result := string(out)
123	if trimDos && len(result) > 1 {
124		result = result[:len(result)-2]
125	}
126	return result, nil
127}
128
129func writeAll(text string) error {
130	if Unsupported {
131		return missingCommands
132	}
133	copyCmd := getCopyCommand()
134	in, err := copyCmd.StdinPipe()
135	if err != nil {
136		return err
137	}
138
139	if err := copyCmd.Start(); err != nil {
140		return err
141	}
142	if _, err := in.Write([]byte(text)); err != nil {
143		return err
144	}
145	if err := in.Close(); err != nil {
146		return err
147	}
148	return copyCmd.Wait()
149}