Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unix: move clipboard utility discovery out of init() #64

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 43 additions & 39 deletions clipboard_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build freebsd || linux || netbsd || openbsd || solaris || dragonfly
// +build freebsd linux netbsd openbsd solaris dragonfly

package clipboard
Expand All @@ -24,12 +25,6 @@ const (
)

var (
Primary bool
trimDos bool

pasteCmdArgs []string
copyCmdArgs []string

xselPasteArgs = []string{xsel, "--output", "--clipboard"}
xselCopyArgs = []string{xsel, "--input", "--clipboard"}

Expand All @@ -48,89 +43,98 @@ var (
missingCommands = errors.New("No clipboard utilities available. Please install xsel, xclip, wl-clipboard or Termux:API add-on for termux-clipboard-get/set.")
)

func init() {
type commandInfo struct {
trimDOS bool

pasteCmdArgs []string
copyCmdArgs []string

unsupported bool
}

func findClipboardUtility() commandInfo {
c := commandInfo{}

if os.Getenv("WAYLAND_DISPLAY") != "" {
pasteCmdArgs = wlpasteArgs
copyCmdArgs = wlcopyArgs
c.pasteCmdArgs = wlpasteArgs
c.copyCmdArgs = wlcopyArgs

if _, err := exec.LookPath(wlcopy); err == nil {
if _, err := exec.LookPath(wlpaste); err == nil {
return
return c
}
}
}

pasteCmdArgs = xclipPasteArgs
copyCmdArgs = xclipCopyArgs
c.pasteCmdArgs = xclipPasteArgs
c.copyCmdArgs = xclipCopyArgs

if _, err := exec.LookPath(xclip); err == nil {
return
return c
}

pasteCmdArgs = xselPasteArgs
copyCmdArgs = xselCopyArgs
c.pasteCmdArgs = xselPasteArgs
c.copyCmdArgs = xselCopyArgs

if _, err := exec.LookPath(xsel); err == nil {
return
return c
}

pasteCmdArgs = termuxPasteArgs
copyCmdArgs = termuxCopyArgs
c.pasteCmdArgs = termuxPasteArgs
c.copyCmdArgs = termuxCopyArgs

if _, err := exec.LookPath(termuxClipboardSet); err == nil {
if _, err := exec.LookPath(termuxClipboardGet); err == nil {
return
return c
}
}

pasteCmdArgs = powershellExePasteArgs
copyCmdArgs = clipExeCopyArgs
trimDos = true
c.pasteCmdArgs = powershellExePasteArgs
c.copyCmdArgs = clipExeCopyArgs
c.trimDOS = true

if _, err := exec.LookPath(clipExe); err == nil {
if _, err := exec.LookPath(powershellExe); err == nil {
return
return c
}
}

Unsupported = true
return commandInfo{unsupported: true}
}

func getPasteCommand() *exec.Cmd {
if Primary {
pasteCmdArgs = pasteCmdArgs[:1]
}
return exec.Command(pasteCmdArgs[0], pasteCmdArgs[1:]...)
func getPasteCommand(c commandInfo) *exec.Cmd {
return exec.Command(c.pasteCmdArgs[0], c.pasteCmdArgs[1:]...)
}

func getCopyCommand() *exec.Cmd {
if Primary {
copyCmdArgs = copyCmdArgs[:1]
}
return exec.Command(copyCmdArgs[0], copyCmdArgs[1:]...)
func getCopyCommand(c commandInfo) *exec.Cmd {
return exec.Command(c.copyCmdArgs[0], c.copyCmdArgs[1:]...)
}

func readAll() (string, error) {
if Unsupported {
c := findClipboardUtility()
Copy link

@norbjd norbjd May 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi 👋 just a small comment: instead of instantiating a new commandInfo every time readAll() or writeAll() is called, should it be possible to create a singleton:

 var instance commandInfo
 var once sync.Once

 func GetInstance() commandInfo {
     once.Do(func() {
         instance = findClipboardUtility()
     })
     return instance
 }

And call c := GetInstance() instead of c := findClipboardUtility()?

It will be quicker since findClipboardUtility() will be called only once (at the first call).

What do you think? BTW, thanks for this PR 🙌

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I considered this option, but it didn't seem worth the additional complication for a call that is unlikely to be called very often. If making this change helps the PR get merged though, I'm all for it.

if c.unsupported {
return "", missingCommands
}
pasteCmd := getPasteCommand()

pasteCmd := getPasteCommand(c)
out, err := pasteCmd.Output()
if err != nil {
return "", err
}
result := string(out)
if trimDos && len(result) > 1 {
if c.trimDOS && len(result) > 1 {
result = result[:len(result)-2]
}
return result, nil
}

func writeAll(text string) error {
if Unsupported {
c := findClipboardUtility()
if c.unsupported {
return missingCommands
}
copyCmd := getCopyCommand()

copyCmd := getCopyCommand(c)
in, err := copyCmd.StdinPipe()
if err != nil {
return err
Expand Down