1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
package main
import (
"bufio"
"encoding/base64"
"flag"
"fmt"
"github.com/gdamore/tcell/v2"
"io"
"log"
"os"
// "golang.org/x/sys/unix"
)
func encode(fname string, encoder io.WriteCloser) {
var f *os.File
var err error
if fname == "-" {
f = os.Stdin
} else {
if f, err = os.Open(fname); err != nil {
log.Fatalf("Failed to open file %v: %v", fname, err)
} else {
defer f.Close()
}
}
if _, err = io.Copy(encoder, f); err != nil {
log.Fatal(err)
}
}
func opentty() (tty tcell.Tty, err error) {
tty, err = tcell.NewDevTty()
if err == nil {
err = tty.Start()
}
return
}
func closetty(tty tcell.Tty) {
tty.Drain()
tty.Stop()
tty.Close()
}
func main() {
var fnames []string
flag.Usage = func() {
template := `Usage:
%s [file1 [...fileN]]
Copies file contents to system clipboard using the ANSI OSC52 escape sequence.
With no arguments, will read from stdin.
`
fmt.Fprintf(flag.CommandLine.Output(), template, os.Args[0])
}
pasteFlag := flag.Bool("paste", false, "paste operation")
flag.Parse()
tty, err := opentty()
if err != nil {
fmt.Fprintln(os.Stderr, "ERROR: opentty:", err)
return
}
defer closetty(tty)
if !*pasteFlag {
// copy
if len(flag.Args()) > 0 {
fnames = flag.Args()
} else {
fnames = []string{"-"}
}
// Open buffered output, using default max OSC52 length as buffer size
// TODO limit size
out := bufio.NewWriterSize(tty, 1000000)
// Start OSC52
fmt.Fprintf(out, "\033]52;c;")
b64 := base64.NewEncoder(base64.StdEncoding, out)
for _, fname := range fnames {
encode(fname, b64)
}
b64.Close()
// End OSC52
fmt.Fprintf(out, "\a")
out.Flush()
} else {
// paste
// Start OSC52
fmt.Fprintf(tty, "\033]52;c;?\a")
ttyReader := bufio.NewReader(tty)
buf, err := ttyReader.ReadBytes('\a')
if err != nil {
fmt.Fprintln(os.Stderr, "Read error:", err)
return
}
// fmt.Fprintf(os.Stderr, "Read %d bytes, %x\n", len(buf), buf)
// fmt.Fprintf(os.Stderr, "buf[:7]: %q\n", buf[:7])
// fmt.Fprintf(os.Stderr, "buf[len(buf)-1]: %q\n", buf[len(buf)-1])
// fmt.Fprintf(os.Stderr, "%x\n", buf)
buf = buf[7 : len(buf)-1]
// fmt.Fprintf(os.Stderr, "%x\n", buf)
dst := make([]byte, base64.StdEncoding.DecodedLen(len(buf)))
n, err := base64.StdEncoding.Decode(dst, []byte(buf))
if err != nil {
fmt.Fprintln(os.Stderr, "decode error:", err)
return
}
dst = dst[:n]
if _, err := os.Stdout.Write(dst); err != nil {
fmt.Fprintln(os.Stderr, "Error writing to stdout:", err)
}
}
}
|