refac!: move from demon to oneshot storer
Breaking change: requires calling with `wl-paste -t text --watch clipman store`. As a side-effect, enable primary clipboard support: `wl-paste -p -t text --watch clipman store --histpath="~/.local/share/clipman-primary.json`! Closes #12
This commit is contained in:
parent
37c48c263a
commit
c42e1cabf8
6 changed files with 57 additions and 68 deletions
|
@ -2,5 +2,6 @@
|
|||
|
||||
**Breaking changes**:
|
||||
|
||||
- switch from flags to subcommands: `clipman listen` instead than `clipman -d` and `clipman pick` instead than `clipman -s`
|
||||
- switch demon from polling to event-driven: requires wl-clipboard 2.0 (or latest git HEAD)
|
||||
- switch from flags to subcommands: `wl-paste -t text --watch clipman store` instead than `clipman -d` and `clipman pick` instead than `clipman -s`
|
||||
- switch demon from polling to event-driven: requires wl-clipboard >= 2.0
|
||||
- primary clipboard support: `wl-paste -p -t text --watch clipman store --histpath="~/.local/share/clipman-primary.json` and `clipman pick --histpath="~/.local/share/clipman-primary.json`
|
||||
|
|
|
@ -16,9 +16,11 @@ Archlinux users can find a PKGBUILD [here](https://aur.archlinux.org/packages/cl
|
|||
|
||||
## Usage
|
||||
|
||||
Run the binary in your Sway session by adding `exec clipman -d` (or `exec clipman -d 1>> PATH/TO/LOGFILE 2>&1 &` to log errors) at the beginning of your config.
|
||||
Run the binary in your Sway session by adding `exec wl-paste -t text --watch clipman store` (or `exec wl-paste -t text --watch clipman store 1>> PATH/TO/LOGFILE 2>&1 &` to log errors) at the beginning of your config.
|
||||
For primary clipboard support, also add `exec wl-paste -p -t text --watch clipman store --histpath="~/.local/share/clipman-primary.json`.
|
||||
|
||||
To query the history and select items, run the binary as `clipman -s`. You can assign it to a keybinding: `bindsym $mod+h exec clipman -s`.
|
||||
To query the history and select items, run the binary as `clipman pick`. You can assign it to a keybinding: `bindsym $mod+h exec clipman pick`.
|
||||
For primary clipboard support, `clipman pick --histpath="~/.local/share/clipman-primary.json`.
|
||||
|
||||
For more options: `clipman -h`.
|
||||
|
||||
|
|
5
go.mod
5
go.mod
|
@ -1,13 +1,12 @@
|
|||
module github.com/yory8/clipman
|
||||
|
||||
go 1.12
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20190910110746-680d30ca3117 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/stretchr/testify v1.4.0 // indirect
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
||||
)
|
||||
|
|
4
go.sum
4
go.sum
|
@ -1,7 +1,7 @@
|
|||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190910110746-680d30ca3117 h1:aUo+WrWZtRRfc6WITdEKzEczFRlEpfW15NhNeLRc17U=
|
||||
github.com/alecthomas/units v0.0.0-20190910110746-680d30ca3117/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
|
|
24
main.go
24
main.go
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
@ -14,10 +15,10 @@ import (
|
|||
var (
|
||||
app = kingpin.New("clipman", "A clipboard manager for Wayland")
|
||||
histpath = app.Flag("histpath", "Path of history file").Default("~/.local/share/clipman.json").String()
|
||||
demon = app.Command("listen", "Run as a demon to record clipboard events")
|
||||
storer = app.Command("store", "Run from `wl-paste --watch` to record clipboard events")
|
||||
picker = app.Command("pick", "Pick an item from clipboard history")
|
||||
noPersist = demon.Flag("no-persist", "Don't persist a copy buffer after a program exits").Short('P').Default("false").Bool()
|
||||
maxDemon = demon.Flag("max-items", "history size").Default("15").Int()
|
||||
noPersist = storer.Flag("no-persist", "Don't persist a copy buffer after a program exits").Short('P').Default("false").Bool()
|
||||
maxDemon = storer.Flag("max-items", "history size").Default("15").Int()
|
||||
maxPicker = picker.Flag("max-items", "scrollview length").Default("15").Int()
|
||||
tool = picker.Flag("selector", "Which selector to use: dmenu/rofi/-").Default("dmenu").String()
|
||||
)
|
||||
|
@ -25,13 +26,26 @@ var (
|
|||
func main() {
|
||||
app.HelpFlag.Short('h')
|
||||
switch kingpin.MustParse(app.Parse(os.Args[1:])) {
|
||||
case "listen":
|
||||
case "store":
|
||||
persist := !*noPersist
|
||||
|
||||
histfile, history, err := getHistory()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
listen(history, histfile, persist, *maxDemon)
|
||||
|
||||
// read copy from stdin
|
||||
var stdin []string
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
for scanner.Scan() {
|
||||
stdin = append(stdin, scanner.Text())
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.Fatal("Error getting input from stdin.")
|
||||
}
|
||||
text := strings.Join(stdin, "\n")
|
||||
|
||||
store(text, history, histfile, *maxDemon, persist)
|
||||
case "pick":
|
||||
_, history, err := getHistory()
|
||||
if err != nil {
|
||||
|
|
|
@ -4,55 +4,9 @@ import (
|
|||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(histfile, histlog, 0644)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func filter(history []string, text string) []string {
|
||||
var (
|
||||
found bool
|
||||
idx int
|
||||
)
|
||||
|
||||
for i, el := range history {
|
||||
if el == text {
|
||||
found = true
|
||||
idx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
// we know that idx can't be the last element, because
|
||||
// we never get to call this function if that's the case
|
||||
history = append(history[:idx], history[idx+1:]...)
|
||||
}
|
||||
|
||||
return history
|
||||
}
|
||||
|
||||
func store(text string, history []string, histfile string, max int, persist bool) []string {
|
||||
l := len(history)
|
||||
if l > 0 {
|
||||
|
@ -87,16 +41,35 @@ func store(text string, history []string, histfile string, max int, persist bool
|
|||
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
|
||||
func filter(history []string, text string) []string {
|
||||
var (
|
||||
found bool
|
||||
idx int
|
||||
)
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
log.Fatalf("Error running wl-paste (cmd.Start): %s", err)
|
||||
for i, el := range history {
|
||||
if el == text {
|
||||
found = true
|
||||
idx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
log.Fatalf("Error running wl-paste (cmd.Wait): %s", err)
|
||||
if found {
|
||||
// we know that idx can't be the last element, because
|
||||
// we never get to call this function if that's the case
|
||||
history = append(history[:idx], history[idx+1:]...)
|
||||
}
|
||||
|
||||
return history
|
||||
}
|
||||
|
||||
func write(history []string, histfile string) error {
|
||||
histlog, err := json.Marshal(history)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(histfile, histlog, 0644)
|
||||
|
||||
return err
|
||||
}
|
Loading…
Reference in a new issue