package main import ( "bufio" "fmt" "io" "os" "os/exec" "path" "strings" "golang.design/x/clipboard" ) const DELEMITTER = "---------------------------------------------------------------------------\n" func main() { if len(os.Args) < 2 { fmt.Println("Usage: go-cat [...]") os.Exit(1) } var sb strings.Builder for _, path := range os.Args[1:] { err := processPath(&sb, path) if err != nil { fmt.Fprintf(os.Stderr, "Error processing %s: %v\n", path, err) } } str := sb.String() fmt.Println(str) if err := writeClipboard(str); err != nil { panic(err) } } func writeClipboard(str string) error { if os.Getenv("WAYLAND_DISPLAY") != "" { cmd := exec.Command("wl-copy") p, err := cmd.StdinPipe() if err != nil { return err } if err := cmd.Start(); err != nil { return err } p.Write([]byte(str)) p.Close() return cmd.Wait() } if err := clipboard.Init(); err != nil { return err } clipboard.Write(clipboard.FmtText, []byte(str)) return nil } func processPath(sb *strings.Builder, path string) error { info, err := os.Stat(path) if err != nil { return err } if info.IsDir() { return catDir(sb, path) } return catFile(sb, path) } func catDir(sb *strings.Builder, dir string) error { files, err := os.ReadDir(dir) if err != nil { return err } fmt.Printf("Directory: %s\n", dir) for _, file := range files { i, err := file.Info() if err != nil { continue } path := path.Join(dir, i.Name()) if !file.IsDir() { catFile(sb, path) } else { catDir(sb, path) } } return nil } func catFile(sb *strings.Builder, filePath string) error { file, err := os.Open(filePath) if err != nil { return err } defer file.Close() sb.WriteString(DELEMITTER) sb.WriteString(filePath + "\n") reader := bufio.NewReader(file) for { line, err := reader.ReadString('\n') if err != nil && err != io.EOF { return err } sb.WriteString(line) if err == io.EOF { break } } return nil }