clipboard.go RawHistoryFolder
1package clipboard
2
3import (
4 "fmt"
5 "os/exec"
6)
7
8// CopyToClipboard copies the given text to the system clipboard.
9// It tries wl-copy first (Wayland), then falls back to xclip (X11).
10// Returns an error if both fail.
11func CopyToClipboard(text string) error {
12 if text == "" {
13 return fmt.Errorf("cannot copy empty text to clipboard")
14 }
15
16 // Try wl-copy first (Wayland)
17 if err := tryWlCopy(text); err == nil {
18 return nil
19 }
20
21 // Fallback to xclip (X11)
22 if err := tryXclip(text); err == nil {
23 return nil
24 }
25
26 return fmt.Errorf("clipboard copy failed: neither wl-copy nor xclip available")
27}
28
29// tryWlCopy attempts to copy text using wl-copy (Wayland clipboard)
30func tryWlCopy(text string) error {
31 cmd := exec.Command("wl-copy")
32 cmd.Stdin = nil
33
34 // Set up stdin pipe to pass the text
35 stdin, err := cmd.StdinPipe()
36 if err != nil {
37 return fmt.Errorf("failed to create stdin pipe for wl-copy: %w", err)
38 }
39
40 // Start the command
41 if err := cmd.Start(); err != nil {
42 stdin.Close()
43 return fmt.Errorf("failed to start wl-copy: %w", err)
44 }
45
46 // Write text to stdin and close it
47 _, writeErr := stdin.Write([]byte(text))
48 closeErr := stdin.Close()
49
50 // Wait for command to complete
51 waitErr := cmd.Wait()
52
53 // Return the first error encountered
54 if writeErr != nil {
55 return fmt.Errorf("failed to write to wl-copy stdin: %w", writeErr)
56 }
57 if closeErr != nil {
58 return fmt.Errorf("failed to close wl-copy stdin: %w", closeErr)
59 }
60 if waitErr != nil {
61 return fmt.Errorf("wl-copy command failed: %w", waitErr)
62 }
63
64 return nil
65}
66
67// tryXclip attempts to copy text using xclip (X11 clipboard)
68func tryXclip(text string) error {
69 cmd := exec.Command("xclip", "-selection", "clipboard")
70
71 // Set up stdin pipe to pass the text
72 stdin, err := cmd.StdinPipe()
73 if err != nil {
74 return fmt.Errorf("failed to create stdin pipe for xclip: %w", err)
75 }
76
77 // Start the command
78 if err := cmd.Start(); err != nil {
79 stdin.Close()
80 return fmt.Errorf("failed to start xclip: %w", err)
81 }
82
83 // Write text to stdin and close it
84 _, writeErr := stdin.Write([]byte(text))
85 closeErr := stdin.Close()
86
87 // Wait for command to complete
88 waitErr := cmd.Wait()
89
90 // Return the first error encountered
91 if writeErr != nil {
92 return fmt.Errorf("failed to write to xclip stdin: %w", writeErr)
93 }
94 if closeErr != nil {
95 return fmt.Errorf("failed to close xclip stdin: %w", closeErr)
96 }
97 if waitErr != nil {
98 return fmt.Errorf("xclip command failed: %w", waitErr)
99 }
100
101 return nil
102}
103
104// IsAvailable checks if clipboard functionality is available on the system
105func IsAvailable() bool {
106 // Check if wl-copy is available
107 if _, err := exec.LookPath("wl-copy"); err == nil {
108 return true
109 }
110
111 // Check if xclip is available
112 if _, err := exec.LookPath("xclip"); err == nil {
113 return true
114 }
115
116 return false
117}