Compare commits

..

No commits in common. "d5cf6d9f17d1f4de0441351bc56714f29238454b" and "b069dfe4f6453c01286aa3412301df60c8fdbfc9" have entirely different histories.

5 changed files with 12 additions and 73 deletions

View file

@ -1,16 +1,3 @@
# Next
**New features**
- `--unix` option to normalize all line endings to LF
# 1.5.2
**Notable bug fixes**
- wl-copy is now truly daemonized, allowing calling `alacritty -e sh -c clipman pick`
- fzf couldn't recover the clipboard content in some cases
# 1.5.1 # 1.5.1
**Notable bug fixes** **Notable bug fixes**

View file

@ -24,10 +24,10 @@ These distros ship with clipman binaries in their repos:
## Usage ## Usage
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. 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`.
For primary clipboard support, also add `exec wl-paste -p -t text --watch clipman store -P --histpath="~/.local/share/clipman-primary.json"` (note that both the `-p` in wl-paste and the `-P` in clipman are mandatory in this case).
To query the history and select items, run the binary as `clipman pick -t wofi`. You can assign it to a keybinding: `bindsym $mod+h exec clipman pick -t wofi`. To query the history and select items, run the binary as `clipman pick -t wofi`. You can assign it to a keybinding: `bindsym $mod+h exec clipman pick -t wofi`.
For primary clipboard support, `clipman pick -t wofi --histpath="~/.local/share/clipman-primary.json`.
You can pass additional arguments to the selector like this: `clipman pick --tool wofi -T'--prompt=my-prompt -i'` (both `--prompt` and `-i` are flags of wofi). You can pass additional arguments to the selector like this: `clipman pick --tool wofi -T'--prompt=my-prompt -i'` (both `--prompt` and `-i` are flags of wofi).
You can use a custom selector like this: `clipman pick --print0 --tool=CUSTOM --tool-args="fzf --prompt 'pick > ' --bind 'tab:up' --cycle --read0"`. You can use a custom selector like this: `clipman pick --print0 --tool=CUSTOM --tool-args="fzf --prompt 'pick > ' --bind 'tab:up' --cycle --read0"`.
@ -44,10 +44,6 @@ For more options: `clipman -h`.
- All items stored in history are treated as plain text. - All items stored in history are treated as plain text.
- By default, we continue serving the last copied item even after its owner has exited. This means that, unless you run with the `--no-persist` option, you'll always immediately lose rich content: for example, if you copy formatted text inside Libre Office you'll lose all formatting on paste; or, if you copy a bookmark in Firefox, you won't be able to paste it in another bookmark folder. - By default, we continue serving the last copied item even after its owner has exited. This means that, unless you run with the `--no-persist` option, you'll always immediately lose rich content: for example, if you copy formatted text inside Libre Office you'll lose all formatting on paste; or, if you copy a bookmark in Firefox, you won't be able to paste it in another bookmark folder.
### Vim's Visual Block mode breaks if persistence is enabled
Run `clipman store` with the `--no-persist` option if you are affected. Unfortunately, it seems that there is no way to make them play well together.
## Versions ## Versions
This projects follows SemVer conventions. This projects follows SemVer conventions.

View file

@ -1,4 +1,4 @@
.TH clipman 1 1.5.2 "" .TH clipman 1 1.5.1 ""
.SH "NAME" .SH "NAME"
clipman clipman
.SH "SYNOPSIS" .SH "SYNOPSIS"
@ -35,9 +35,6 @@ history size
.TP .TP
\fB-P, --no-persist\fR \fB-P, --no-persist\fR
Don't persist a copy buffer after a program exits Don't persist a copy buffer after a program exits
.TP
\fB--unix\fR
Normalize line endings to LF
.SS .SS
\fBpick --tool=TOOL [<flags>]\fR \fBpick --tool=TOOL [<flags>]\fR
.PP .PP
@ -79,10 +76,10 @@ Separate items using NULL; recommended if your tool supports --read0 or similar
Serve the last recorded item from history Serve the last recorded item from history
.SH "USAGE" .SH "USAGE"
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. 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.
.PP For primary clipboard support, also add `exec wl-paste -p -t text --watch clipman store --histpath="~/.local/share/clipman-primary.json`.
For primary clipboard support, also add `exec wl-paste -p -t text --watch clipman store -P --histpath="~/.local/share/clipman-primary.json` (note that both the `-p` in wl-paste and the `-P` in clipman are mandatory in this case).
.PP .PP
To query the history and select items, run the binary as `clipman pick -t wofi`. You can assign it to a keybinding: `bindsym $mod+h exec clipman pick -t wofi`. To query the history and select items, run the binary as `clipman pick -t wofi`. You can assign it to a keybinding: `bindsym $mod+h exec clipman pick -t wofi`.
For primary clipboard support, `clipman pick -t wofi --histpath="~/.local/share/clipman-primary.json`.
You can pass additional arguments to the selector like this: `clipman pick --tool wofi -T'--prompt=my-prompt -i'` (both `--prompt` and `-i` are flags of wofi). You can pass additional arguments to the selector like this: `clipman pick --tool wofi -T'--prompt=my-prompt -i'` (both `--prompt` and `-i` are flags of wofi).
You can use a custom selector like this: `clipman pick --print0 --tool=CUSTOM --tool-args="fzf --prompt 'pick > ' --bind 'tab:up' --cycle --read0"`. You can use a custom selector like this: `clipman pick --print0 --tool=CUSTOM --tool-args="fzf --prompt 'pick > ' --bind 'tab:up' --cycle --read0"`.
.PP .PP
@ -90,10 +87,6 @@ To remove items from history, `clipman clear -t wofi` and `clipman clear --all`.
.PP .PP
To serve the last history item at startup, add `exec clipman restore` to your Sway config. To serve the last history item at startup, add `exec clipman restore` to your Sway config.
.SH "KNOWN ISSUES" .SH "KNOWN ISSUES"
\fBAll items stored in history are treated as plain text.\fR All items stored in history are treated as plain text.
.PP .PP
By default, we continue serving the last copied item even after its owner has exited. This means that, unless you run with the `--no-persist` option, you'll always immediately lose rich content: for example, if you copy formatted text inside Libre Office you'll lose all formatting on paste; or, if you copy a bookmark in Firefox, you won't be able to paste it in another bookmark folder. By default, we continue serving the last copied item even after its owner has exited. This means that, unless you run with the `--no-persist` option, you'll always immediately lose rich content: for example, if you copy formatted text inside Libre Office you'll lose all formatting on paste; or, if you copy a bookmark in Firefox, you won't be able to paste it in another bookmark folder.
.PP
\fBVim's Visual Block mode breaks if persistence is enabled\fR
.PP
Run `clipman store` with the `--no-persist` option if you are affected. Unfortunately, it seems that there is no way to make them play well together.

45
main.go
View file

@ -11,12 +11,11 @@ import (
"os" "os"
"os/exec" "os/exec"
"strings" "strings"
"syscall"
"gopkg.in/alecthomas/kingpin.v2" "gopkg.in/alecthomas/kingpin.v2"
) )
const version = "1.5.2" const version = "1.5.1"
var ( var (
app = kingpin.New("clipman", "A clipboard manager for Wayland") app = kingpin.New("clipman", "A clipboard manager for Wayland")
@ -26,7 +25,6 @@ var (
storer = app.Command("store", "Record clipboard events (run as argument to `wl-paste --watch`)") storer = app.Command("store", "Record clipboard events (run as argument to `wl-paste --watch`)")
maxDemon = storer.Flag("max-items", "history size").Default("15").Int() maxDemon = storer.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() noPersist = storer.Flag("no-persist", "Don't persist a copy buffer after a program exits").Short('P').Default("false").Bool()
unix = storer.Flag("unix", "Normalize line endings to LF").Bool()
picker = app.Command("pick", "Pick an item from clipboard history") picker = app.Command("pick", "Pick an item from clipboard history")
maxPicker = picker.Flag("max-items", "scrollview length").Default("15").Int() maxPicker = picker.Flag("max-items", "scrollview length").Default("15").Int()
@ -180,14 +178,8 @@ func serveTxt(s string) {
smartLog(fmt.Sprintf("couldn't find wl-copy: %v\n", err), "low", *alert) smartLog(fmt.Sprintf("couldn't find wl-copy: %v\n", err), "low", *alert)
} }
// daemonize wl-copy into a truly independent process
// necessary for running stuff like `alacritty -e sh -c clipman pick`
attr := &syscall.SysProcAttr{
Setpgid: true,
}
// we mandate the mime type because we know we can only serve text; not doing this leads to weird bugs like #35 // we mandate the mime type because we know we can only serve text; not doing this leads to weird bugs like #35
cmd := exec.Cmd{Path: bin, Args: []string{bin, "-t", "TEXT"}, Stdin: strings.NewReader(s), SysProcAttr: attr} cmd := exec.Cmd{Path: bin, Args: []string{bin, "-t", "TEXT"}, Stdin: strings.NewReader(s)}
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
smartLog(fmt.Sprintf("error running wl-copy: %s\n", err), "low", *alert) smartLog(fmt.Sprintf("error running wl-copy: %s\n", err), "low", *alert)
} }
@ -201,43 +193,14 @@ func scanLines(data []byte, atEOF bool) (advance int, token []byte, err error) {
if i := bytes.IndexByte(data, '\n'); i >= 0 { if i := bytes.IndexByte(data, '\n'); i >= 0 {
// We have a full newline-terminated line. // We have a full newline-terminated line.
b := data[0 : i+1] return i + 1, data[0 : i+1], nil
if *unix {
b = dropCR(b)
}
return i + 1, b, nil
} }
// If we're at EOF, we have a final, non-terminated line. Return it. // If we're at EOF, we have a final, non-terminated line. Return it.
if atEOF { if atEOF {
b := data return len(data), data, nil
if *unix {
b = dropCR(b)
}
return len(data), b, nil
} }
// Request more data. // Request more data.
return 0, nil, nil return 0, nil, nil
} }
// dropCR drops a terminal \r from the data. Modified from Go's Stdlib
func dropCR(data []byte) []byte {
orig := data
var lf bool
if len(data) > 0 && data[len(data)-1] == '\n' {
lf = true
data = data[0 : len(data)-1]
}
if len(data) > 0 && data[len(data)-1] == '\r' {
b := data[0 : len(data)-1]
if lf {
b = append(b, '\n')
}
return b
}
return orig
}

View file

@ -80,7 +80,7 @@ func selector(data []string, max int, tool, prompt, toolArgs string, null bool)
sep = "\000" sep = "\000"
} }
cmd := exec.Cmd{Path: bin, Args: args, Stdin: strings.NewReader(strings.Join(processed, sep))} cmd := exec.Cmd{Path: bin, Args: args, Stdin: strings.NewReader(strings.Join(processed, sep) + "\n")}
cmd.Stderr = os.Stderr // let stderr pass to console cmd.Stderr = os.Stderr // let stderr pass to console
b, err := cmd.Output() b, err := cmd.Output()
if err != nil { if err != nil {