Merge branch 'release/4.0.0'

This commit is contained in:
Chris Down 2017-10-25 01:58:03 +01:00
commit ef3102c5e9
6 changed files with 80 additions and 44 deletions

View file

@ -29,6 +29,11 @@ there, but it basically works like this:
1. `clipmenud` polls the clipboard every 0.5 seconds (or another interval as
configured with the `CM_SLEEP` environment variable). Unfortunately there's
no interface to subscribe for changes in X11, so we must poll.
Instead of polling, you can bind your copy key binding to also issue
`CM_ONESHOT=1 clipmenud`. However, there's no generic way to do this, since
any keys or mouse buttons could be bound to do this action in a number of
ways.
2. If `clipmenud` detects changes to the clipboard contents, it writes them out
to the cache directory.

View file

@ -1,21 +1,17 @@
#!/bin/bash
major_version=3
: "${CM_LAUNCHER=dmenu}"
: "${CM_DIR="${XDG_RUNTIME_DIR-"${TMPDIR-/tmp}"}"}"
major_version=4
shopt -s nullglob
cache_dir=/tmp/clipmenu.$major_version.$USER
cache_dir=$CM_DIR/clipmenu.$major_version.$USER
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
if [[ $1 == --help ]] || [[ $1 == -h ]]; then
cat << 'EOF'
clipmenu is a simple clipboard manager using dmenu and xsel. Launch this
when you want to select a clip.
@ -23,11 +19,17 @@ All arguments are passed through to dmenu itself.
Environment variables:
- \$CM_LAUNCHER: specify a dmenu-compatible launcher (default: dmenu)
- $CM_LAUNCHER: specify a dmenu-compatible launcher (default: dmenu)
- $CM_DIR: specify the base directory to store the cache dir in (default: $XDG_RUNTIME_DIR, $TMPDIR, or /tmp)
EOF
exit 0
fi
if [[ "$CM_LAUNCHER" == rofi ]]; then
# rofi supports dmenu-like arguments through the -dmenu flag
set -- -dmenu "$@"
fi
# 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
# argument to override an earlier one. That is, if the user passes in `-l`, our

View file

@ -1,14 +1,16 @@
#!/bin/bash
major_version=3
cache_dir=/tmp/clipmenu.$major_version.$USER/
cache_file=$cache_dir/line_cache
lock_file=$cache_dir/lock
lock_timeout=2
: "${CM_ONESHOT=0}"
: "${CM_OWN_CLIPBOARD=1}"
: "${CM_DEBUG=0}"
: "${CM_DIR="${XDG_RUNTIME_DIR-"${TMPDIR-/tmp}"}"}"
: "${CM_MAX_CLIPS=1000}"
major_version=4
cache_dir=$CM_DIR/clipmenu.$major_version.$USER/
cache_file=$cache_dir/line_cache
lock_file=$cache_dir/lock
lock_timeout=2
_xsel() {
timeout 1 xsel --logfile /dev/stderr "$@"
@ -51,16 +53,32 @@ debug() {
fi
}
if [[ $1 == --help ]] || [[ $1 == -h ]]; then
cat << 'EOF'
clipmenud is the daemon that collects and caches what's on the clipboard.
when you want to select a clip.
Environment variables:
- $CM_ONESHOT: run once immediately, do not loop (default: 0)
- $CM_DEBUG: turn on debugging output (default: 0)
- $CM_OWN_CLIPBOARD: take ownership of the clipboard (default: 1)
- $CM_MAX_CLIPS: maximum number of clips to store, 0 for inf (default: 1000)
- $CM_DIR: specify the base directory to store the cache dir in (default: $XDG_RUNTIME_DIR, $TMPDIR, or /tmp)
EOF
exit 0
fi
# It's ok that this only applies to the final directory.
# shellcheck disable=SC2174
mkdir -p -m0700 "$cache_dir"
declare -A last_data
declare -A last_filename
exec {lock_fd}> "$lock_file"
while sleep "${CM_SLEEP:-0.5}"; do
while (( CM_ONESHOT )) || sleep "${CM_SLEEP:-0.5}"; do
if ! flock -x -w "$lock_timeout" "$lock_fd"; then
if (( CM_ONESHOT )); then
printf 'ERROR: %s\n' 'Timed out waiting for lock' >&2
@ -94,29 +112,24 @@ while sleep "${CM_SLEEP:-0.5}"; do
continue
fi
# If we were in the middle of doing a selection when the previous poll
# ran, then we may have got a partial clip.
possible_partial=${last_data[$selection]}
if [[ $possible_partial && $data == "$possible_partial"* ]]; then
debug "$possible_partial is a possible partial of $data"
debug "Removing ${last_filename[$selection]}"
rm -- "${last_filename[$selection]}"
fi
last_data[$selection]=$data
last_filename[$selection]=$filename
first_line=$(get_first_line "$data")
printf 'New clipboard entry on %s selection: "%s"\n' \
"$selection" "$first_line"
debug "New clipboard entry on $selection selection: \"$first_line\""
filename="$cache_dir/$(cksum <<< "$first_line")"
debug "Writing $data to $filename"
printf '%s' "$data" > "$filename"
# Without checking ${last_data[any]}, we often double write since both
# selections get the same content
if [[ ${last_data[any]} != "$data" ]]; then
filename="$cache_dir/$(cksum <<< "$first_line")"
debug "Writing $data to $filename"
printf '%s' "$data" > "$filename"
debug "Writing $first_line to $cache_file"
printf '%s\n' "$first_line" >> "$cache_file"
debug "Writing $first_line to $cache_file"
printf '%s\n' "$first_line" >> "$cache_file"
fi
last_data[any]=$data
if (( CM_OWN_CLIPBOARD )) && [[ $selection != primary ]]; then
# Take ownership of the clipboard, in case the original application
@ -132,6 +145,21 @@ while sleep "${CM_SLEEP:-0.5}"; do
# we would skip first.
_xsel -o --"$selection" | _xsel -i --"$selection"
fi
if (( CM_MAX_CLIPS )); then
mapfile -t to_remove < <(
head -n -"$CM_MAX_CLIPS" "$cache_file" |
while read -r line; do cksum <<< "$line"; done
)
num_to_remove="${#to_remove[@]}"
if (( num_to_remove )); then
debug "Removing $num_to_remove old clips"
rm -- "${to_remove[@]/#/"$cache_dir/"}"
trunc_tmp=$(mktemp)
tail -n "$CM_MAX_CLIPS" "$cache_file" | uniq > "$trunc_tmp"
mv -- "$trunc_tmp" "$cache_file"
fi
fi
done
flock -u "$lock_fd"

View file

@ -14,8 +14,5 @@ ProtectKernelTunables=yes
RestrictAddressFamilies=
RestrictRealtime=yes
ProtectSystem=strict
ReadWritePaths=/tmp
[Install]
WantedBy=default.target

View file

@ -4,8 +4,10 @@ set -x
set -e
set -o pipefail
major_version=3
dir=/tmp/clipmenu.$major_version.$USER
: "${CM_DIR="${XDG_RUNTIME_DIR-"${TMPDIR-/tmp}"}"}"
major_version=4
dir=$CM_DIR/clipmenu.$major_version.$USER
cache_file=$dir/line_cache
if [[ $0 == /* ]]; then

View file

@ -1,12 +1,14 @@
#!/bin/bash
major_version=3
major_version=4
msg() {
printf '>>> %s\n' "$@" >&2
}
dir=/tmp/clipmenu.$major_version.$USER
: "${CM_DIR="${XDG_RUNTIME_DIR-"${TMPDIR-/tmp}"}"}"
dir=$CM_DIR/clipmenu.$major_version.$USER
cache_file=$dir/line_cache
log=$(mktemp)