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}
150