You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ntool/nsys/clipboard/clipboard.go

211 lines
4.4 KiB
Go

1 year ago
package clipboard
import (
"bytes"
"errors"
"fmt"
"git.noahlan.cn/noahlan/ntool/ncli"
"git.noahlan.cn/noahlan/ntool/nfs"
"git.noahlan.cn/noahlan/ntool/nsys"
"github.com/gookit/color"
"io"
"os/exec"
"strings"
)
// Clipboard struct
type Clipboard struct {
// TODO add event on write, read
// buffer for write
buf *bytes.Buffer
// print exec command line on run
verbose bool
// available - bin file exist on the OS.
writeable, readable bool
readerBin string
readArgs []string
writerBin string
writeArgs []string
}
// New instance
func New() *Clipboard {
// special handle on with args
reader, readArgs := parseLine(GetReaderBin())
writer, writeArgs := parseLine(GetWriterBin())
return &Clipboard{
readerBin: reader,
readArgs: readArgs,
writerBin: writer,
writeArgs: writeArgs,
readable: nsys.HasExecutable(reader),
writeable: nsys.HasExecutable(writer),
}
}
// WithVerbose setting
func (c *Clipboard) WithVerbose(yn bool) *Clipboard {
c.verbose = yn
return c
}
// Clean the clipboard
func (c *Clipboard) Clean() error { return c.Reset() }
// Reset and clean the clipboard
func (c *Clipboard) Reset() error {
if c.buf != nil {
c.buf.Reset()
}
// echo empty string for clean clipboard.
// run: echo '' | pbcopy
return c.WriteFrom(strings.NewReader(""))
}
//
// ---------------------------------------- write ----------------------------------------
//
// Write bytes data to clipboard
func (c *Clipboard) Write(p []byte) (int, error) {
return c.WriteString(string(p))
}
// WriteString data to clipboard
func (c *Clipboard) WriteString(s string) (int, error) {
// if c.addSlashes {
// s = strutil.AddSlashes(s)
// }
return c.buffer().WriteString(s)
}
// Flush buffer contents to clipboard
func (c *Clipboard) Flush() error {
if c.buf == nil || c.buf.Len() == 0 {
return errors.New("clipboard: empty contents for write")
}
defer c.buf.Reset()
return c.WriteFrom(c.buf)
}
// WriteFromFile contents to clipboard
func (c *Clipboard) WriteFromFile(filepath string) error {
// eg:
// Mac: pbcopy < tempfile.txt
file, err := nfs.OpenReadFile(filepath)
if err != nil {
return err
}
defer file.Close()
return c.WriteFrom(file)
}
// WriteFrom reader data to clipboard
func (c *Clipboard) WriteFrom(r io.Reader) error {
if !c.writeable {
return fmt.Errorf("clipboard: write driver %q not found on OS", c.writerBin)
}
cmd := exec.Command(c.writerBin, c.writeArgs...)
cmd.Stdin = r
if c.verbose {
color.Yellow.Printf("clipboard> %s\n", ncli.BuildLine(c.writerBin, c.writeArgs))
}
return cmd.Run()
}
//
// ---------------------------------------- read ----------------------------------------
//
// Read contents from clipboard
func (c *Clipboard) Read() ([]byte, error) {
buf, err := c.ReadToBuffer()
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// ReadToBuffer contents from clipboard
func (c *Clipboard) ReadToBuffer() (*bytes.Buffer, error) {
var buf bytes.Buffer
if err := c.ReadTo(&buf); err != nil {
return nil, err
}
return &buf, nil
}
// ReadString contents as string from clipboard
func (c *Clipboard) ReadString() (string, error) {
bts, err := c.Read()
if err != nil {
return "", err
}
// fix: at Windows will always return end of the "\r\n"
if nsys.IsWindows() {
return string(bytes.TrimRight(bts, "\r\n")), nil
}
return string(bts), nil
}
// ReadToFile dump clipboard data to file
func (c *Clipboard) ReadToFile(filepath string) error {
file, err := nfs.QuickOpenFile(filepath)
if err != nil {
return err
}
defer file.Close()
return c.ReadTo(file)
}
// ReadTo read clipboard contents to writer
func (c *Clipboard) ReadTo(w io.Writer) error {
if !c.readable {
return fmt.Errorf("clipboard: read driver %q not found on OS", c.readerBin)
}
cmd := exec.Command(c.readerBin, c.readArgs...)
cmd.Stdout = w
if c.verbose {
color.Yellow.Printf("clipboard> %s\n", ncli.BuildLine(c.writerBin, c.writeArgs))
}
return cmd.Run()
}
//
// ---------------------------------------- help ----------------------------------------
//
// Available check
func (c *Clipboard) Available() bool {
return c.writeable && c.readable && available()
}
// Writeable check
func (c *Clipboard) Writeable() bool {
return c.writeable
}
// Readable check
func (c *Clipboard) Readable() bool {
return c.readable
}
func (c *Clipboard) buffer() *bytes.Buffer {
if c.buf == nil {
c.buf = new(bytes.Buffer)
}
return c.buf
}