Merge branch 'release/3.2.0'

This commit is contained in:
Chris Down 2017-03-19 10:06:35 +00:00
commit 3ab7a6e2e7
4 changed files with 63 additions and 17 deletions

View file

@ -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/

View file

@ -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

View file

@ -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

View file

@ -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"