Merge branch 'release/4.0.0'
This commit is contained in:
commit
ef3102c5e9
|
@ -29,6 +29,11 @@ there, but it basically works like this:
|
||||||
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 `CM_SLEEP` environment variable). Unfortunately there's
|
configured with the `CM_SLEEP` environment variable). Unfortunately 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.
|
||||||
|
|
||||||
|
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
|
2. If `clipmenud` detects changes to the clipboard contents, it writes them out
|
||||||
to the cache directory.
|
to the cache directory.
|
||||||
|
|
||||||
|
|
26
clipmenu
26
clipmenu
|
@ -1,21 +1,17 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
major_version=3
|
: "${CM_LAUNCHER=dmenu}"
|
||||||
|
: "${CM_DIR="${XDG_RUNTIME_DIR-"${TMPDIR-/tmp}"}"}"
|
||||||
|
|
||||||
|
major_version=4
|
||||||
|
|
||||||
shopt -s nullglob
|
shopt -s nullglob
|
||||||
|
|
||||||
cache_dir=/tmp/clipmenu.$major_version.$USER
|
cache_dir=$CM_DIR/clipmenu.$major_version.$USER
|
||||||
cache_file=$cache_dir/line_cache
|
cache_file=$cache_dir/line_cache
|
||||||
|
|
||||||
: "${CM_LAUNCHER=dmenu}"
|
if [[ $1 == --help ]] || [[ $1 == -h ]]; then
|
||||||
|
cat << 'EOF'
|
||||||
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
|
clipmenu is a simple clipboard manager using dmenu and xsel. Launch this
|
||||||
when you want to select a clip.
|
when you want to select a clip.
|
||||||
|
|
||||||
|
@ -23,11 +19,17 @@ All arguments are passed through to dmenu itself.
|
||||||
|
|
||||||
Environment variables:
|
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
|
EOF
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
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
|
# 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
|
||||||
|
|
78
clipmenud
78
clipmenud
|
@ -1,14 +1,16 @@
|
||||||
#!/bin/bash
|
#!/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_ONESHOT=0}"
|
||||||
: "${CM_OWN_CLIPBOARD=1}"
|
: "${CM_OWN_CLIPBOARD=1}"
|
||||||
: "${CM_DEBUG=0}"
|
: "${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() {
|
_xsel() {
|
||||||
timeout 1 xsel --logfile /dev/stderr "$@"
|
timeout 1 xsel --logfile /dev/stderr "$@"
|
||||||
|
@ -51,16 +53,32 @@ debug() {
|
||||||
fi
|
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.
|
# It's ok that this only applies to the final directory.
|
||||||
# shellcheck disable=SC2174
|
# shellcheck disable=SC2174
|
||||||
mkdir -p -m0700 "$cache_dir"
|
mkdir -p -m0700 "$cache_dir"
|
||||||
|
|
||||||
declare -A last_data
|
declare -A last_data
|
||||||
declare -A last_filename
|
|
||||||
|
|
||||||
exec {lock_fd}> "$lock_file"
|
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 ! flock -x -w "$lock_timeout" "$lock_fd"; then
|
||||||
if (( CM_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
|
||||||
|
@ -94,29 +112,24 @@ while sleep "${CM_SLEEP:-0.5}"; do
|
||||||
continue
|
continue
|
||||||
fi
|
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_data[$selection]=$data
|
||||||
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' \
|
debug "New clipboard entry on $selection selection: \"$first_line\""
|
||||||
"$selection" "$first_line"
|
|
||||||
|
|
||||||
filename="$cache_dir/$(cksum <<< "$first_line")"
|
# Without checking ${last_data[any]}, we often double write since both
|
||||||
debug "Writing $data to $filename"
|
# selections get the same content
|
||||||
printf '%s' "$data" > "$filename"
|
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"
|
debug "Writing $first_line to $cache_file"
|
||||||
printf '%s\n' "$first_line" >> "$cache_file"
|
printf '%s\n' "$first_line" >> "$cache_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
last_data[any]=$data
|
||||||
|
|
||||||
if (( CM_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
|
||||||
|
@ -132,6 +145,21 @@ while sleep "${CM_SLEEP:-0.5}"; do
|
||||||
# we would skip first.
|
# we would skip first.
|
||||||
_xsel -o --"$selection" | _xsel -i --"$selection"
|
_xsel -o --"$selection" | _xsel -i --"$selection"
|
||||||
fi
|
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
|
done
|
||||||
|
|
||||||
flock -u "$lock_fd"
|
flock -u "$lock_fd"
|
||||||
|
|
|
@ -14,8 +14,5 @@ ProtectKernelTunables=yes
|
||||||
RestrictAddressFamilies=
|
RestrictAddressFamilies=
|
||||||
RestrictRealtime=yes
|
RestrictRealtime=yes
|
||||||
|
|
||||||
ProtectSystem=strict
|
|
||||||
ReadWritePaths=/tmp
|
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=default.target
|
WantedBy=default.target
|
||||||
|
|
|
@ -4,8 +4,10 @@ set -x
|
||||||
set -e
|
set -e
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
||||||
major_version=3
|
: "${CM_DIR="${XDG_RUNTIME_DIR-"${TMPDIR-/tmp}"}"}"
|
||||||
dir=/tmp/clipmenu.$major_version.$USER
|
|
||||||
|
major_version=4
|
||||||
|
dir=$CM_DIR/clipmenu.$major_version.$USER
|
||||||
cache_file=$dir/line_cache
|
cache_file=$dir/line_cache
|
||||||
|
|
||||||
if [[ $0 == /* ]]; then
|
if [[ $0 == /* ]]; then
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
major_version=3
|
major_version=4
|
||||||
|
|
||||||
msg() {
|
msg() {
|
||||||
printf '>>> %s\n' "$@" >&2
|
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
|
cache_file=$dir/line_cache
|
||||||
|
|
||||||
log=$(mktemp)
|
log=$(mktemp)
|
||||||
|
|
Loading…
Reference in a new issue