Merge branch 'release/3.2.0'
This commit is contained in:
commit
3ab7a6e2e7
12
README.md
12
README.md
|
@ -1,4 +1,9 @@
|
||||||
clipmenu is a simple clipboard manager using [dmenu][] and [xsel][].
|
clipmenu is a simple clipboard manager using [dmenu][] (or [rofi][]) and
|
||||||
|
[xsel][].
|
||||||
|
|
||||||
|
# Demo
|
||||||
|
|
||||||
|
![Demo](https://cloud.githubusercontent.com/assets/660663/24079784/6f76da94-0c88-11e7-8251-40b1f02ebf3c.gif)
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
|
|
||||||
|
@ -22,8 +27,8 @@ there, but it basically works like this:
|
||||||
## clipmenud
|
## clipmenud
|
||||||
|
|
||||||
1. `clipmenud` polls the clipboard every 0.5 seconds (or another interval as
|
1. `clipmenud` polls the clipboard every 0.5 seconds (or another interval as
|
||||||
configured with the `CLIPMENUD_SLEEP` environment variable). Unfortunately
|
configured with the `CM_SLEEP` environment variable). Unfortunately there's
|
||||||
there's no interface to subscribe for changes in X11, so we must poll.
|
no interface to subscribe for changes in X11, so we must poll.
|
||||||
2. If `clipmenud` detects changes to the clipboard contents, it writes them out
|
2. If `clipmenud` detects changes to the clipboard contents, it writes them out
|
||||||
to the cache directory.
|
to the cache directory.
|
||||||
|
|
||||||
|
@ -35,4 +40,5 @@ there, but it basically works like this:
|
||||||
selections.
|
selections.
|
||||||
|
|
||||||
[dmenu]: http://tools.suckless.org/dmenu/
|
[dmenu]: http://tools.suckless.org/dmenu/
|
||||||
|
[rofi]: https://github.com/DaveDavenport/Rofi
|
||||||
[xsel]: http://www.vergenet.net/~conrad/software/xsel/
|
[xsel]: http://www.vergenet.net/~conrad/software/xsel/
|
||||||
|
|
25
clipmenu
25
clipmenu
|
@ -7,11 +7,32 @@ shopt -s nullglob
|
||||||
cache_dir=/tmp/clipmenu.$major_version.$USER
|
cache_dir=/tmp/clipmenu.$major_version.$USER
|
||||||
cache_file=$cache_dir/line_cache
|
cache_file=$cache_dir/line_cache
|
||||||
|
|
||||||
|
: "${CM_LAUNCHER=dmenu}"
|
||||||
|
|
||||||
|
if [[ "$CM_LAUNCHER" == rofi ]]; then
|
||||||
|
# rofi supports dmenu-like arguments through the -dmenu flag
|
||||||
|
set -- -dmenu "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $1 == --help ]]; then
|
||||||
|
cat << EOF
|
||||||
|
clipmenu is a simple clipboard manager using dmenu and xsel. Launch this
|
||||||
|
when you want to select a clip.
|
||||||
|
|
||||||
|
All arguments are passed through to dmenu itself.
|
||||||
|
|
||||||
|
Environment variables:
|
||||||
|
|
||||||
|
- \$CM_LAUNCHER: specify a dmenu-compatible launcher (default: dmenu)
|
||||||
|
EOF
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
# It's okay to hardcode `-l 8` here as a sensible default without checking
|
# It's okay to hardcode `-l 8` here as a sensible default without checking
|
||||||
# whether `-l` is also in "$@", because the way that dmenu works allows a later
|
# whether `-l` is also in "$@", because the way that dmenu works allows a later
|
||||||
# argument to override an earlier one. That is, if the user passes in `-l`, our
|
# argument to override an earlier one. That is, if the user passes in `-l`, our
|
||||||
# one will be ignored.
|
# one will be ignored.
|
||||||
chosen_line=$(tac "$cache_file" | awk '!seen[$0]++' | dmenu -l 8 "$@")
|
chosen_line=$(tac "$cache_file" | awk '!seen[$0]++' | "$CM_LAUNCHER" -l 8 "$@")
|
||||||
|
|
||||||
[[ $chosen_line ]] || exit 1
|
[[ $chosen_line ]] || exit 1
|
||||||
|
|
||||||
|
@ -24,5 +45,5 @@ if ! [[ -f "$file" ]]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for selection in clipboard primary; do
|
for selection in clipboard primary; do
|
||||||
xsel --logfile /dev/null -i --"$selection" < "$file"
|
xsel --logfile /dev/stderr -i --"$selection" < "$file"
|
||||||
done
|
done
|
||||||
|
|
20
clipmenud
20
clipmenud
|
@ -6,8 +6,12 @@ cache_file=$cache_dir/line_cache
|
||||||
lock_file=$cache_dir/lock
|
lock_file=$cache_dir/lock
|
||||||
lock_timeout=2
|
lock_timeout=2
|
||||||
|
|
||||||
|
: "${CM_ONESHOT=0}"
|
||||||
|
: "${CM_OWN_CLIPBOARD=1}"
|
||||||
|
: "${CM_DEBUG=0}"
|
||||||
|
|
||||||
_xsel() {
|
_xsel() {
|
||||||
timeout 1 xsel --logfile /dev/null "$@"
|
timeout 1 xsel --logfile /dev/stderr "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
get_first_line() {
|
get_first_line() {
|
||||||
|
@ -42,7 +46,7 @@ get_first_line() {
|
||||||
}
|
}
|
||||||
|
|
||||||
debug() {
|
debug() {
|
||||||
if (( DEBUG )); then
|
if (( CM_DEBUG )); then
|
||||||
printf '%s\n' "$@" >&2
|
printf '%s\n' "$@" >&2
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -56,9 +60,9 @@ declare -A last_filename
|
||||||
|
|
||||||
exec {lock_fd}> "$lock_file"
|
exec {lock_fd}> "$lock_file"
|
||||||
|
|
||||||
while sleep "${CLIPMENUD_SLEEP:-0.5}"; do
|
while sleep "${CM_SLEEP:-0.5}"; do
|
||||||
if ! flock -x -w "$lock_timeout" "$lock_fd"; then
|
if ! flock -x -w "$lock_timeout" "$lock_fd"; then
|
||||||
if (( ONESHOT )); then
|
if (( CM_ONESHOT )); then
|
||||||
printf 'ERROR: %s\n' 'Timed out waiting for lock' >&2
|
printf 'ERROR: %s\n' 'Timed out waiting for lock' >&2
|
||||||
exit 1
|
exit 1
|
||||||
else
|
else
|
||||||
|
@ -103,6 +107,10 @@ while sleep "${CLIPMENUD_SLEEP:-0.5}"; do
|
||||||
last_filename[$selection]=$filename
|
last_filename[$selection]=$filename
|
||||||
|
|
||||||
first_line=$(get_first_line "$data")
|
first_line=$(get_first_line "$data")
|
||||||
|
|
||||||
|
printf 'New clipboard entry on %s selection: "%s"\n' \
|
||||||
|
"$selection" "$first_line"
|
||||||
|
|
||||||
filename="$cache_dir/$(cksum <<< "$first_line")"
|
filename="$cache_dir/$(cksum <<< "$first_line")"
|
||||||
debug "Writing $data to $filename"
|
debug "Writing $data to $filename"
|
||||||
printf '%s' "$data" > "$filename"
|
printf '%s' "$data" > "$filename"
|
||||||
|
@ -110,7 +118,7 @@ while sleep "${CLIPMENUD_SLEEP:-0.5}"; do
|
||||||
debug "Writing $first_line to $cache_file"
|
debug "Writing $first_line to $cache_file"
|
||||||
printf '%s\n' "$first_line" >> "$cache_file"
|
printf '%s\n' "$first_line" >> "$cache_file"
|
||||||
|
|
||||||
if ! (( NO_OWN_CLIPBOARD )) && [[ $selection != primary ]]; then
|
if (( CM_OWN_CLIPBOARD )) && [[ $selection != primary ]]; then
|
||||||
# Take ownership of the clipboard, in case the original application
|
# Take ownership of the clipboard, in case the original application
|
||||||
# is unable to serve the clipboard request (due to being suspended,
|
# is unable to serve the clipboard request (due to being suspended,
|
||||||
# etc).
|
# etc).
|
||||||
|
@ -128,7 +136,7 @@ while sleep "${CLIPMENUD_SLEEP:-0.5}"; do
|
||||||
|
|
||||||
flock -u "$lock_fd"
|
flock -u "$lock_fd"
|
||||||
|
|
||||||
if (( ONESHOT )); then
|
if (( CM_ONESHOT )); then
|
||||||
debug 'Oneshot mode enabled, exiting'
|
debug 'Oneshot mode enabled, exiting'
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -37,7 +37,15 @@ shim() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
alias dmenu='SHIM_STDOUT="Selected text. (2 lines)" shim dmenu'
|
# Cannot be an alias due to expansion order with $CM_LAUNCHER
|
||||||
|
dmenu() {
|
||||||
|
SHIM_STDOUT="Selected text. (2 lines)" shim dmenu "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
rofi() {
|
||||||
|
SHIM_STDOUT="Selected text. (2 lines)" shim rofi "$@"
|
||||||
|
}
|
||||||
|
|
||||||
alias xsel='shim xsel'
|
alias xsel='shim xsel'
|
||||||
alias xclip='shim xclip'
|
alias xclip='shim xclip'
|
||||||
EOF
|
EOF
|
||||||
|
@ -59,12 +67,10 @@ EOF
|
||||||
|
|
||||||
### TESTS ###
|
### TESTS ###
|
||||||
|
|
||||||
output=$(/tmp/clipmenu --foo bar 2>&1)
|
|
||||||
|
|
||||||
temp=$(mktemp)
|
temp=$(mktemp)
|
||||||
trap 'rm -f -- "$temp"' EXIT
|
trap 'rm -f -- "$temp"' EXIT
|
||||||
|
|
||||||
printf '%s\n' "$output" > "$temp"
|
/tmp/clipmenu --foo bar > "$temp" 2>&1
|
||||||
|
|
||||||
# Arguments are transparently passed to dmenu
|
# Arguments are transparently passed to dmenu
|
||||||
grep -Fxq 'dmenu args: -l 8 --foo bar' "$temp"
|
grep -Fxq 'dmenu args: -l 8 --foo bar' "$temp"
|
||||||
|
@ -74,8 +80,13 @@ grep -Fxq 'dmenu line 1 stdin: Selected text 2. (2 lines)' "$temp"
|
||||||
grep -Fxq 'dmenu line 2 stdin: Selected text. (2 lines)' "$temp"
|
grep -Fxq 'dmenu line 2 stdin: Selected text. (2 lines)' "$temp"
|
||||||
|
|
||||||
# xsel should copy both to clipboard *and* primary
|
# xsel should copy both to clipboard *and* primary
|
||||||
grep -Fxq 'xsel args: --logfile /dev/null -i --clipboard' "$temp"
|
grep -Fxq 'xsel args: --logfile /dev/stderr -i --clipboard' "$temp"
|
||||||
grep -Fxq 'xsel args: --logfile /dev/null -i --primary' "$temp"
|
grep -Fxq 'xsel args: --logfile /dev/stderr -i --primary' "$temp"
|
||||||
|
|
||||||
grep -Fxq 'xsel line 1 stdin: Selected text.' "$temp"
|
grep -Fxq 'xsel line 1 stdin: Selected text.' "$temp"
|
||||||
grep -Fxq "xsel line 2 stdin: Yes, it's selected text." "$temp"
|
grep -Fxq "xsel line 2 stdin: Yes, it's selected text." "$temp"
|
||||||
|
|
||||||
|
CM_LAUNCHER=rofi /tmp/clipmenu --foo bar > "$temp" 2>&1
|
||||||
|
|
||||||
|
# We have a special case to add -dmenu for rofi
|
||||||
|
grep -Fxq 'rofi args: -l 8 -dmenu --foo bar' "$temp"
|
||||||
|
|
Loading…
Reference in a new issue