diff options
| author | theimpostor <sahirhoda@gmail.com> | 2023-07-16 08:50:50 -0500 |
|---|---|---|
| committer | theimpostor <sahirhoda@gmail.com> | 2023-07-16 08:50:50 -0500 |
| commit | b0079afd80bd4f0106327c0b360f14d4ba169201 (patch) | |
| tree | 0bda473b78f093ff6395ca666d2c2c9ea631fbef /main.go | |
| parent | f8bcf79e7420c1896a7809afa42949e982590ea5 (diff) | |
Fix paste for terminals ending with ESC-backslash instead of BEL, and add debug logging
Diffstat (limited to 'main.go')
| -rw-r--r-- | main.go | 155 |
1 files changed, 117 insertions, 38 deletions
@@ -6,6 +6,7 @@ import ( "flag" "fmt" "github.com/gdamore/tcell/v2" + "golang.org/x/exp/slog" "io" "log" "os" @@ -47,28 +48,63 @@ func closetty(tty tcell.Tty) { func main() { var fnames []string + var err error flag.Usage = func() { - template := `Usage: -%s [file1 [...fileN]] -Copies file contents to system clipboard using the ANSI OSC52 escape sequence. + template := `Reads or writes the system clipboard using the ANSI OSC52 escape sequence. + +Usage: + +COPY mode (default): + + %s [file1 [...fileN]] + With no arguments, will read from stdin. + +PASTE mode: + + %s --paste + +Outputs clipboard contents to stdout. + +Options: ` - fmt.Fprintf(flag.CommandLine.Output(), template, os.Args[0]) + fmt.Fprintf(flag.CommandLine.Output(), template, os.Args[0], os.Args[0]) + flag.PrintDefaults() } - pasteFlag := flag.Bool("paste", false, "paste operation") + var pasteFlag bool + var verboseFlag bool + var logfileFlag string + flag.BoolVar(&pasteFlag, "paste", pasteFlag, "paste operation") + flag.BoolVar(&verboseFlag, "verbose", verboseFlag, "verbose logging") + flag.BoolVar(&verboseFlag, "v", verboseFlag, "verbose logging") + flag.StringVar(&logfileFlag, "logFile", logfileFlag, "redirect logs to file") flag.Parse() - tty, err := opentty() - if err != nil { - fmt.Fprintln(os.Stderr, "ERROR: opentty:", err) - return + logLevel := &slog.LevelVar{} // INFO + logOutput := os.Stdout + + if logfileFlag != "" { + if logOutput, err = os.OpenFile(logfileFlag, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0644); err != nil { + log.Fatalf("Failed to open file %v: %v", logfileFlag, err) + } else { + defer logOutput.Close() + } } - defer closetty(tty) - if !*pasteFlag { + if verboseFlag { + logLevel.Set(slog.LevelDebug) + } + + logger := slog.New(slog.NewTextHandler(logOutput, &slog.HandlerOptions{ + Level: logLevel, + })) + slog.SetDefault(logger) + slog.Debug("logging started") + + if !pasteFlag { // copy if len(flag.Args()) > 0 { fnames = flag.Args() @@ -76,11 +112,19 @@ With no arguments, will read from stdin. fnames = []string{"-"} } + tty, err := opentty() + if err != nil { + slog.Error("ERROR: opentty:", err) + return + } + defer closetty(tty) + // Open buffered output, using default max OSC52 length as buffer size // TODO limit size out := bufio.NewWriterSize(tty, 1000000) // Start OSC52 + slog.Debug("Beginning osc52 copy operation") fmt.Fprintf(out, "\033]52;c;") b64 := base64.NewEncoder(base64.StdEncoding, out) @@ -93,36 +137,71 @@ With no arguments, will read from stdin. fmt.Fprintf(out, "\a") out.Flush() + slog.Debug("Ended osc52") } 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) + data := func() []byte { + + tty, err := opentty() + if err != nil { + slog.Error("ERROR: opentty:", err) + return nil + } + defer closetty(tty) + + // Start OSC52 + slog.Debug("Beginning osc52 paste operation") + fmt.Fprintf(tty, "\033]52;c;?\a") + + ttyReader := bufio.NewReader(tty) + buf := make([]byte, 0, 1024) + for { + if b, err := ttyReader.ReadByte(); err != nil { + slog.Error("ReadByte error:", err) + return nil + } else { + slog.Debug(fmt.Sprintf("Read: %x '%s'", b, string(b))) + if b == '\a' { + break + } + buf = append(buf, b) + if len(buf) > 2 && buf[len(buf)-2] == '\033' && buf[len(buf)-1] == '\\' { + buf = buf[:len(buf)-2] + break + } + } + } + + // buf, err := ttyReader.ReadBytes('\a') + // if err != nil { + // slog.Error("Read error:", err) + // return nil + // } + + // slog.Debug("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:] + // 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 { + slog.Error("decode error:", err) + return nil + } + dst = dst[:n] + + return dst + }() + + if data != nil { + if _, err := os.Stdout.Write(data); err != nil { + slog.Error("Error writing to stdout:", err) + } } + slog.Debug("Ended osc52") } } |
