diff --git a/README.md b/README.md index 383e218..7b30706 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ A basic clipboard manager for Wayland, with support for persisting copy buffers Requirements: - a windows manager that uses `wlr-data-control`, like Sway and other wlroots-based WMs. -- wl-clipboard from latest master (NOT v1.0) +- wl-clipboard >= 2.0 - dmenu or rofi [Install go](https://golang.org/doc/install), add `$GOPATH/bin` to your path, then run `go get github.com/yory8/clipman` OR run `go install` inside this folder. diff --git a/demon.go b/demon.go index 54478dd..f4a316e 100644 --- a/demon.go +++ b/demon.go @@ -4,10 +4,22 @@ import ( "encoding/json" "io/ioutil" "log" + "os" "os/exec" - "time" ) +type historyBuf struct { + buf []string // field name as required by io.Writer, don't change + histfile string + max int + persist bool +} + +func (hb *historyBuf) Write(p []byte) (n int, err error) { + hb.buf = store(string(p), hb.buf, hb.histfile, hb.max, hb.persist) + return len(p), err // signature as required by io.Writer, don't change +} + func write(history []string, histfile string) error { histlog, err := json.Marshal(history) if err != nil { @@ -41,58 +53,50 @@ func filter(history []string, text string) []string { return history } -func listen(history []string, histfile string, persist bool, max int) { - for { - t, err := exec.Command("wl-paste", "-n", "-t", "text").CombinedOutput() - if err != nil { - // wl-paste exits 1 if there's no selection (e.g., when running it at OS startup) - if string(t) != "No selection\n" { - log.Printf("Error running wl-paste: %s", t) - } - time.Sleep(1 * time.Second) - continue +func store(text string, history []string, histfile string, max int, persist bool) []string { + l := len(history) + if l > 0 { + if history[l-1] == text { + return history } - text := string(t) - - if text == "" { - // there's nothing to select, so we sleep. - time.Sleep(1 * time.Second) - continue + if l >= max { + // usually just one item, but more if we reduce our --max-items value + history = history[l-max+1:] } - l := len(history) + // remove duplicates + history = filter(history, text) + } - if l > 0 { - // wl-paste will always give back the last copied text - // (as long as the place we copied from is still running) - if history[l-1] == text { - time.Sleep(1 * time.Second) - continue - } + history = append(history, text) - if l >= max { - // usually just one item, but more if we reduce our --max-items value - history = history[l-max+1:] - } + // dump history to file so that other apps can query it + if err := write(history, histfile); err != nil { + log.Fatalf("Fatal error writing history: %s", err) + } - // remove duplicates - history = filter(history, text) - } - - history = append(history, text) - - // dump history to file so that other apps can query it - if err := write(history, histfile); err != nil { - log.Fatalf("Fatal error writing history: %s", err) - } - - if persist { - // make the copy buffer available to all applications, - // even when the source has disappeared - if err := exec.Command("wl-copy", []string{"--", text}...).Run(); err != nil { - log.Printf("Error running wl-copy: %s", err) - } + if persist { + // make the copy buffer available to all applications, + // even when the source has disappeared + if err := exec.Command("wl-copy", []string{"--", text}...).Run(); err != nil { + log.Printf("Error running wl-copy: %s", err) } } + + return history +} + +func listen(history []string, histfile string, persist bool, max int) { + cmd := exec.Command("wl-paste", "-t", "text", "--watch", "cat") + cmd.Stdout = &historyBuf{history, histfile, max, persist} + cmd.Stderr = os.Stderr + + if err := cmd.Start(); err != nil { + log.Fatalf("Error running wl-paste (cmd.Start): %s", err) + } + + if err := cmd.Wait(); err != nil { + log.Fatalf("Error running wl-paste (cmd.Wait): %s", err) + } }