Compare commits
10 commits
b069dfe4f6
...
d5cf6d9f17
Author | SHA1 | Date | |
---|---|---|---|
|
d5cf6d9f17 | ||
|
8aac681b97 | ||
|
14bf2b7baa | ||
|
167e9ac93f | ||
|
77706941a3 | ||
|
c5de70df5f | ||
|
1eb93a5ff0 | ||
|
bb95b603d0 | ||
|
e1dea61d31 | ||
|
ef9e6bece2 |
5 changed files with 73 additions and 12 deletions
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -1,4 +1,17 @@
|
||||||
# 1.5.1
|
# 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
|
||||||
|
|
||||||
**Notable bug fixes**
|
**Notable bug fixes**
|
||||||
|
|
||||||
|
|
|
@ -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,6 +44,10 @@ 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.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
.TH clipman 1 1.5.1 ""
|
.TH clipman 1 1.5.2 ""
|
||||||
.SH "NAME"
|
.SH "NAME"
|
||||||
clipman
|
clipman
|
||||||
.SH "SYNOPSIS"
|
.SH "SYNOPSIS"
|
||||||
|
@ -35,6 +35,9 @@ 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
|
||||||
|
@ -76,10 +79,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.
|
||||||
For primary clipboard support, also add `exec wl-paste -p -t text --watch clipman store --histpath="~/.local/share/clipman-primary.json`.
|
.PP
|
||||||
|
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
|
||||||
|
@ -87,6 +90,10 @@ 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"
|
||||||
All items stored in history are treated as plain text.
|
\fBAll items stored in history are treated as plain text.\fR
|
||||||
.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
45
main.go
|
@ -11,11 +11,12 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"gopkg.in/alecthomas/kingpin.v2"
|
"gopkg.in/alecthomas/kingpin.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const version = "1.5.1"
|
const version = "1.5.2"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
app = kingpin.New("clipman", "A clipboard manager for Wayland")
|
app = kingpin.New("clipman", "A clipboard manager for Wayland")
|
||||||
|
@ -25,6 +26,7 @@ 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()
|
||||||
|
@ -178,8 +180,14 @@ 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)}
|
cmd := exec.Cmd{Path: bin, Args: []string{bin, "-t", "TEXT"}, Stdin: strings.NewReader(s), SysProcAttr: attr}
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -193,14 +201,43 @@ 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.
|
||||||
return i + 1, data[0 : i+1], nil
|
b := data[0 : i+1]
|
||||||
|
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 {
|
||||||
return len(data), data, nil
|
b := data
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -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) + "\n")}
|
cmd := exec.Cmd{Path: bin, Args: args, Stdin: strings.NewReader(strings.Join(processed, sep))}
|
||||||
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 {
|
||||||
|
|
Loading…
Reference in a new issue