From 62f3156fa3c23e4ab778365f9ed5a65071cdd6dc Mon Sep 17 00:00:00 2001 From: XXiang Date: Tue, 14 Oct 2025 15:13:33 +0800 Subject: [PATCH 1/2] fix tmux tty --- main.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/main.go b/main.go index 0b3013c..8cc704f 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "bufio" "bytes" "encoding/base64" + "errors" "fmt" "io" "log" @@ -11,14 +12,12 @@ import ( "os/exec" "regexp" "runtime" + "runtime/debug" "strings" "time" "github.com/gdamore/tcell/v2" "github.com/mattn/go-isatty" - - "runtime/debug" - "github.com/spf13/cobra" ) @@ -43,6 +42,7 @@ var ( deviceFlag string clipboardFlag string timeoutFlag float64 + tmuxTTY string debugLog *log.Logger errorLog *log.Logger ) @@ -194,6 +194,16 @@ func copy(fnames []string) error { return fmt.Errorf("tmux allow-passthrough must be set to 'on' or 'all'") } } + if out, err := exec.Command("tmux", "display-message", "-p", "#{client_tty}").Output(); err != nil { + return fmt.Errorf("Error running 'tmux display-message -p #{client_tty}': %w", err) + } else { + outStr := strings.TrimSpace(string(out)) + debugLog.Println("'tmux display-message -p #{client_tty}':", outStr) + if !strings.HasPrefix(outStr, "/dev/") { + return errors.New("posix tty of tmux client must has prefix of '/dev/'") + } + tmuxTTY = outStr + } } var data []byte @@ -526,6 +536,8 @@ func ttyDevice() string { return deviceFlag } else if isScreen { return "/dev/tty" + } else if isTmux { + return tmuxTTY } else if sshtty := os.Getenv("SSH_TTY"); sshtty != "" { return sshtty } else { From 095f1a63fec3fccc5dd837c1ba12f07929c74c89 Mon Sep 17 00:00:00 2001 From: XXiang Date: Sat, 18 Oct 2025 23:05:56 +0800 Subject: [PATCH 2/2] fix staticcheck lint --- main.go | 67 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/main.go b/main.go index 8cc704f..81a67d8 100644 --- a/main.go +++ b/main.go @@ -95,7 +95,7 @@ func initLogging() (*os.File, error) { if logfileFlag != "" { if logOutput, err = os.OpenFile(logfileFlag, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0644); err != nil { - return nil, fmt.Errorf("Failed to open file %v: %v", logfileFlag, err) + return nil, fmt.Errorf("failed to open file %v: %v", logfileFlag, err) } else { logfile = logOutput } @@ -122,10 +122,9 @@ func identifyTerm() error { isTmux = true } else if ti, err := tcell.LookupTerminfo(os.Getenv("TERM")); err != nil { if runtime.GOOS != "windows" { - return fmt.Errorf("Failed to lookup terminfo: %w", err) - } else { - debugLog.Println("On Windows, failed to lookup terminfo:", err) + return fmt.Errorf("failed to lookup terminfo: %w", err) } + debugLog.Println("On Windows, failed to lookup terminfo:", err) } else { debugLog.Printf("term name: %s, aliases: %q", ti.Name, ti.Aliases) if strings.HasPrefix(ti.Name, "screen") { @@ -186,21 +185,21 @@ func copy(fnames []string) error { // copy if isTmux { if out, err := exec.Command("tmux", "show", "-gwsv", "allow-passthrough").Output(); err != nil { - return fmt.Errorf("Error running 'tmux show -gwsv allow-passthrough': %w", err) + return fmt.Errorf("error running 'tmux show -gwsv allow-passthrough': %w", err) } else { outStr := strings.TrimSpace(string(out)) debugLog.Println("'tmux show -gwsv allow-passthrough':", outStr) if outStr != "on" && outStr != "all" { - return fmt.Errorf("tmux allow-passthrough must be set to 'on' or 'all'") + return errors.New("tmux allow-passthrough must be set to 'on' or 'all'") } } if out, err := exec.Command("tmux", "display-message", "-p", "#{client_tty}").Output(); err != nil { - return fmt.Errorf("Error running 'tmux display-message -p #{client_tty}': %w", err) + return fmt.Errorf("error running 'tmux display-message -p #{client_tty}': %w", err) } else { outStr := strings.TrimSpace(string(out)) debugLog.Println("'tmux display-message -p #{client_tty}':", outStr) if !strings.HasPrefix(outStr, "/dev/") { - return errors.New("posix tty of tmux client must has prefix of '/dev/'") + return errors.New("posix tty of tmux client must have prefix of '/dev/'") } tmuxTTY = outStr } @@ -209,12 +208,12 @@ func copy(fnames []string) error { var data []byte if len(fnames) == 0 { if isatty.IsTerminal(os.Stdin.Fd()) || isatty.IsCygwinTerminal(os.Stdin.Fd()) { - return fmt.Errorf("Nothing on stdin") + return errors.New("nothing on stdin") } var err error if data, err = io.ReadAll(os.Stdin); err != nil { - return fmt.Errorf("Error reading stdin: %w", err) + return fmt.Errorf("error reading stdin: %w", err) } else { debugLog.Printf("Read %d bytes from stdin", len(data)) } @@ -223,11 +222,11 @@ func copy(fnames []string) error { for _, fname := range fnames { if f, err := os.Open(fname); err != nil { - return fmt.Errorf("Error opening file %s: %w", fname, err) + return fmt.Errorf("error opening file %s: %w", fname, err) } else if n, err := io.Copy(&dataBuff, f); err != nil { - return fmt.Errorf("Error reading file %s: %w", fname, err) + return fmt.Errorf("error reading file %s: %w", fname, err) } else if err := f.Close(); err != nil { - return fmt.Errorf("Error closing file %s: %w", fname, err) + return fmt.Errorf("error closing file %s: %w", fname, err) } else { debugLog.Printf("Read %d bytes from %s", n, fname) } @@ -239,7 +238,7 @@ func copy(fnames []string) error { tty, err := opentty() if err != nil { - return fmt.Errorf("Error opening tty: %w", err) + return fmt.Errorf("error opening tty: %w", err) } defer closetty(tty) @@ -256,7 +255,7 @@ func copy(fnames []string) error { // Start OSC52 if _, err := fmt.Fprint(ttyWriter, oscOpen); err != nil { - return fmt.Errorf("Error writing osc open: %w", err) + return fmt.Errorf("error writing osc open: %w", err) } var b64 io.WriteCloser @@ -267,20 +266,20 @@ func copy(fnames []string) error { } if _, err := b64.Write(data); err != nil { - return fmt.Errorf("Error writing data: %w", err) + return fmt.Errorf("error writing data: %w", err) } if err := b64.Close(); err != nil { - return fmt.Errorf("Error closing encoder: %w", err) + return fmt.Errorf("error closing encoder: %w", err) } // End OSC52 if _, err := fmt.Fprint(ttyWriter, oscClose); err != nil { - return fmt.Errorf("Error writing osc close: %w", err) + return fmt.Errorf("error writing osc close: %w", err) } if err := ttyWriter.Flush(); err != nil { - return fmt.Errorf("Error flushing bufio: %w", err) + return fmt.Errorf("error flushing bufio: %w", err) } return nil @@ -288,17 +287,17 @@ func copy(fnames []string) error { func tmux_paste() error { if out, err := exec.Command("tmux", "show", "-v", "set-clipboard").Output(); err != nil { - return fmt.Errorf("Error running 'tmux show -v set-clipboard': %w", err) + return fmt.Errorf("error running 'tmux show -v set-clipboard': %w", err) } else { outStr := strings.TrimSpace(string(out)) debugLog.Println("'tmux show -v set-clipboard':", outStr) if outStr != "on" && outStr != "external" { - return fmt.Errorf("tmux set-clipboard must be set to 'on' or 'external'") + return errors.New("tmux set-clipboard must be set to 'on' or 'external'") } } // refresh client list if out, err := exec.Command("tmux", "refresh-client", "-l").Output(); err != nil { - return fmt.Errorf("Error running 'tmux refresh-client -l': %v", err) + return fmt.Errorf("error running 'tmux refresh-client -l': %v", err) } else { debugLog.Println("tmux refresh-client output:", string(out)) } @@ -342,7 +341,7 @@ func paste() error { if isTmux { return tmux_paste() } else if isZellij { - return fmt.Errorf("paste unsupported under zellij, unset ZELLIJ env var to force") + return errors.New("paste unsupported under zellij, unset ZELLIJ env var to force") } timeout := time.Duration(timeoutFlag*1_000_000_000) * time.Nanosecond debugLog.Println("Beginning osc52 paste operation, timeout:", timeout) @@ -350,7 +349,7 @@ func paste() error { if data, err := func() ([]byte, error) { tty, err := opentty() if err != nil { - return nil, fmt.Errorf("Error opening tty: %w", err) + return nil, fmt.Errorf("error opening tty: %w", err) } defer closetty(tty) @@ -366,7 +365,7 @@ func paste() error { // Start OSC52 if _, err := fmt.Fprint(ttyWriter, oscOpen+"?"+oscClose); err != nil { - return nil, fmt.Errorf("Error writing osc open: %w", err) + return nil, fmt.Errorf("error writing osc open: %w", err) } var ttyReader *bufio.Reader @@ -397,30 +396,30 @@ func paste() error { select { case res := <-readChan: if res.err != nil { - return nil, fmt.Errorf("Initial ReadSlice error: %w", res.err) + return nil, fmt.Errorf("initial ReadSlice error: %w", res.err) } else if !bytes.Equal(res.data, []byte(OSC)) { return nil, fmt.Errorf("osc header mismatch: %q", res.data) } case <-time.After(timeout): - return nil, fmt.Errorf("tty read timeout") + return nil, errors.New("tty read timeout") } // ignore clipboard info if _, e := ttyReader.ReadSlice(';'); e != nil { - return nil, fmt.Errorf("Clipboard metadata ReadSlice error: %w", e) + return nil, fmt.Errorf("clipboard metadata ReadSlice error: %w", e) } pr := pasteReader{r: ttyReader} decoder := base64.NewDecoder(base64.StdEncoding, &pr) if data, err := io.ReadAll(decoder); err != nil { - return nil, fmt.Errorf("Error reading from decoder: %w", err) + return nil, fmt.Errorf("error reading from decoder: %w", err) } else { return data, nil } }(); err != nil { return err } else if _, err := os.Stdout.Write(data); err != nil { - return fmt.Errorf("Error writing to stdout: %w", err) + return fmt.Errorf("error writing to stdout: %w", err) } debugLog.Println("Ended osc52") @@ -444,9 +443,9 @@ osc copy [file1 [...fileN]] With no arguments, will read from stdin.`, RunE: func(cmd *cobra.Command, args []string) error { if matched, err := regexp.MatchString(CLIPBOARD_REGEX, clipboardFlag); err != nil { - return fmt.Errorf("Invalid clipboard flag: %w", err) + return fmt.Errorf("invalid clipboard flag: %w", err) } else if !matched { - return fmt.Errorf("Invalid clipboard flag: %s", clipboardFlag) + return fmt.Errorf("invalid clipboard flag: %s", clipboardFlag) } rc := func() int { if logfile, err := initLogging(); err != nil { @@ -482,9 +481,9 @@ osc paste`, Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { if matched, err := regexp.MatchString(CLIPBOARD_REGEX, clipboardFlag); err != nil { - return fmt.Errorf("Invalid clipboard flag: %w", err) + return fmt.Errorf("invalid clipboard flag: %w", err) } else if !matched { - return fmt.Errorf("Invalid clipboard flag: %s", clipboardFlag) + return fmt.Errorf("invalid clipboard flag: %s", clipboardFlag) } rc := func() int { if logfile, err := initLogging(); err != nil {