Merge branch 'release/5.0.0'
This commit is contained in:
commit
44c0fb3ad2
9
clipmenu
9
clipmenu
|
@ -3,12 +3,12 @@
|
||||||
: "${CM_LAUNCHER=dmenu}"
|
: "${CM_LAUNCHER=dmenu}"
|
||||||
: "${CM_DIR="${XDG_RUNTIME_DIR-"${TMPDIR-/tmp}"}"}"
|
: "${CM_DIR="${XDG_RUNTIME_DIR-"${TMPDIR-/tmp}"}"}"
|
||||||
|
|
||||||
major_version=4
|
major_version=5
|
||||||
|
|
||||||
shopt -s nullglob
|
shopt -s nullglob
|
||||||
|
|
||||||
cache_dir=$CM_DIR/clipmenu.$major_version.$USER
|
cache_dir=$CM_DIR/clipmenu.$major_version.$USER
|
||||||
cache_file=$cache_dir/line_cache
|
cache_file_prefix=$cache_dir/line_cache
|
||||||
|
|
||||||
if [[ $1 == --help ]] || [[ $1 == -h ]]; then
|
if [[ $1 == --help ]] || [[ $1 == -h ]]; then
|
||||||
cat << 'EOF'
|
cat << 'EOF'
|
||||||
|
@ -34,7 +34,10 @@ fi
|
||||||
# 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]++' | "$CM_LAUNCHER" -l 8 "$@")
|
chosen_line=$(
|
||||||
|
cat "$cache_file_prefix"_* /dev/null | sort -rnk 1 | cut -d' ' -f2- |
|
||||||
|
awk '!seen[$0]++' | "$CM_LAUNCHER" -l 8 "$@"
|
||||||
|
)
|
||||||
|
|
||||||
[[ $chosen_line ]] || exit 1
|
[[ $chosen_line ]] || exit 1
|
||||||
|
|
||||||
|
|
68
clipmenud
68
clipmenud
|
@ -6,13 +6,22 @@
|
||||||
: "${CM_DIR="${XDG_RUNTIME_DIR-"${TMPDIR-/tmp}"}"}"
|
: "${CM_DIR="${XDG_RUNTIME_DIR-"${TMPDIR-/tmp}"}"}"
|
||||||
: "${CM_MAX_CLIPS=1000}"
|
: "${CM_MAX_CLIPS=1000}"
|
||||||
|
|
||||||
major_version=4
|
# Shellcheck is mistaken here, this is used later as lowercase.
|
||||||
|
# shellcheck disable=SC2153
|
||||||
|
: "${CM_SELECTIONS=clipboard primary}"
|
||||||
|
|
||||||
|
major_version=5
|
||||||
cache_dir=$CM_DIR/clipmenu.$major_version.$USER/
|
cache_dir=$CM_DIR/clipmenu.$major_version.$USER/
|
||||||
cache_file=$cache_dir/line_cache
|
cache_file_prefix=$cache_dir/line_cache
|
||||||
lock_file=$cache_dir/lock
|
lock_file=$cache_dir/lock
|
||||||
lock_timeout=2
|
lock_timeout=2
|
||||||
has_clipnotify=0
|
has_clipnotify=0
|
||||||
|
|
||||||
|
# This comes from the environment, so we rely on word splitting.
|
||||||
|
# shellcheck disable=SC2206
|
||||||
|
cm_selections=( $CM_SELECTIONS )
|
||||||
|
|
||||||
|
|
||||||
xsel_log=/dev/null
|
xsel_log=/dev/null
|
||||||
for file in /proc/self/fd/2 /dev/stderr; do
|
for file in /proc/self/fd/2 /dev/stderr; do
|
||||||
[[ -f "$file" ]] || continue
|
[[ -f "$file" ]] || continue
|
||||||
|
@ -64,6 +73,17 @@ debug() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
element_in() {
|
||||||
|
local item element
|
||||||
|
item="$1"
|
||||||
|
for element in "${@:2}"; do
|
||||||
|
if [[ "$item" == "$element" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
if [[ $1 == --help ]] || [[ $1 == -h ]]; then
|
if [[ $1 == --help ]] || [[ $1 == -h ]]; then
|
||||||
cat << 'EOF'
|
cat << 'EOF'
|
||||||
clipmenud is the daemon that collects and caches what's on the clipboard.
|
clipmenud is the daemon that collects and caches what's on the clipboard.
|
||||||
|
@ -76,6 +96,7 @@ Environment variables:
|
||||||
- $CM_OWN_CLIPBOARD: take ownership of the clipboard (default: 1)
|
- $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_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)
|
- $CM_DIR: specify the base directory to store the cache dir in (default: $XDG_RUNTIME_DIR, $TMPDIR, or /tmp)
|
||||||
|
- $CM_SELECTIONS: space separated list of the selections to manage (default: "clipboard primary")
|
||||||
EOF
|
EOF
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
@ -86,6 +107,8 @@ fi
|
||||||
mkdir -p -m0700 "$cache_dir"
|
mkdir -p -m0700 "$cache_dir"
|
||||||
|
|
||||||
declare -A last_data
|
declare -A last_data
|
||||||
|
declare -A last_filename
|
||||||
|
declare -A last_cache_file_output
|
||||||
|
|
||||||
command -v clipnotify >/dev/null 2>&1 && has_clipnotify=1
|
command -v clipnotify >/dev/null 2>&1 && has_clipnotify=1
|
||||||
|
|
||||||
|
@ -96,13 +119,16 @@ fi
|
||||||
|
|
||||||
exec {lock_fd}> "$lock_file"
|
exec {lock_fd}> "$lock_file"
|
||||||
|
|
||||||
|
sleep_cmd=(sleep "${CM_SLEEP:-0.5}")
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
if ! (( CM_ONESHOT )); then
|
if ! (( CM_ONESHOT )); then
|
||||||
if (( has_clipnotify )); then
|
if (( has_clipnotify )); then
|
||||||
clipnotify
|
# Fall back to polling if clipnotify fails
|
||||||
|
clipnotify || "${sleep_cmd[@]}"
|
||||||
else
|
else
|
||||||
# Use old polling method
|
# Use old polling method
|
||||||
sleep "${CM_SLEEP:-0.5}"
|
"${sleep_cmd[@]}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -117,7 +143,8 @@ while true; do
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for selection in clipboard primary; do
|
for selection in "${cm_selections[@]}"; do
|
||||||
|
cache_file=${cache_file_prefix}_$selection
|
||||||
data=$(_xsel -o --"$selection"; printf x)
|
data=$(_xsel -o --"$selection"; printf x)
|
||||||
|
|
||||||
debug "Data before stripping: $data"
|
debug "Data before stripping: $data"
|
||||||
|
@ -139,7 +166,23 @@ while true; 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"* ]] ||
|
||||||
|
[[ $possible_partial && $data == *"$possible_partial" ]]; then
|
||||||
|
debug "$possible_partial is a possible partial of $data"
|
||||||
|
debug "Removing ${last_filename[$selection]}"
|
||||||
|
|
||||||
|
previous_size=$(wc -c <<< "${last_cache_file_output[$selection]}")
|
||||||
|
truncate -s -"$previous_size" "$cache_file"
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
@ -147,18 +190,21 @@ while true; do
|
||||||
|
|
||||||
# Without checking ${last_data[any]}, we often double write since both
|
# Without checking ${last_data[any]}, we often double write since both
|
||||||
# selections get the same content
|
# selections get the same content
|
||||||
|
cache_file_output="$(date +%s) $first_line"
|
||||||
if [[ ${last_data[any]} != "$data" ]]; then
|
if [[ ${last_data[any]} != "$data" ]]; then
|
||||||
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"
|
||||||
|
|
||||||
debug "Writing $first_line to $cache_file"
|
debug "Writing $cache_file_output to $cache_file"
|
||||||
printf '%s\n' "$first_line" >> "$cache_file"
|
printf '%s\n' "$cache_file_output" >> "$cache_file"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
last_data[any]=$data
|
last_data[any]=$data
|
||||||
|
last_cache_file_output[$selection]=$cache_file_output
|
||||||
|
|
||||||
if (( CM_OWN_CLIPBOARD )) && [[ $selection != primary ]]; then
|
if (( CM_OWN_CLIPBOARD )) && [[ $selection != primary ]] &&
|
||||||
|
element_in clipboard "${cm_selections[@]}"; 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).
|
||||||
|
@ -170,13 +216,13 @@ while true; do
|
||||||
# We can't colocate this with the above copying code because
|
# We can't colocate this with the above copying code because
|
||||||
# https://github.com/cdown/clipmenu/issues/34 requires knowing if
|
# https://github.com/cdown/clipmenu/issues/34 requires knowing if
|
||||||
# we would skip first.
|
# we would skip first.
|
||||||
_xsel -o --"$selection" | _xsel -i --"$selection"
|
_xsel -o --clipboard | _xsel -i --clipboard
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if (( CM_MAX_CLIPS )); then
|
if (( CM_MAX_CLIPS )) && [[ -f $cache_file ]]; then
|
||||||
mapfile -t to_remove < <(
|
mapfile -t to_remove < <(
|
||||||
head -n -"$CM_MAX_CLIPS" "$cache_file" |
|
head -n -"$CM_MAX_CLIPS" "$cache_file" |
|
||||||
while read -r line; do cksum <<< "$line"; done
|
while read -r line; do cksum <<< "${line#* }"; done
|
||||||
)
|
)
|
||||||
num_to_remove="${#to_remove[@]}"
|
num_to_remove="${#to_remove[@]}"
|
||||||
if (( num_to_remove )); then
|
if (( num_to_remove )); then
|
||||||
|
|
|
@ -6,9 +6,9 @@ set -o pipefail
|
||||||
|
|
||||||
: "${CM_DIR="${XDG_RUNTIME_DIR-"${TMPDIR-/tmp}"}"}"
|
: "${CM_DIR="${XDG_RUNTIME_DIR-"${TMPDIR-/tmp}"}"}"
|
||||||
|
|
||||||
major_version=4
|
major_version=5
|
||||||
dir=$CM_DIR/clipmenu.$major_version.$USER
|
dir=$CM_DIR/clipmenu.$major_version.$USER
|
||||||
cache_file=$dir/line_cache
|
cache_file=$dir/line_cache_primary
|
||||||
|
|
||||||
if [[ $0 == /* ]]; then
|
if [[ $0 == /* ]]; then
|
||||||
location=${0%/*}
|
location=${0%/*}
|
||||||
|
@ -58,8 +58,8 @@ rm -rf "$dir"
|
||||||
mkdir -p "$dir"
|
mkdir -p "$dir"
|
||||||
|
|
||||||
cat > "$cache_file" << 'EOF'
|
cat > "$cache_file" << 'EOF'
|
||||||
Selected text. (2 lines)
|
1234 Selected text. (2 lines)
|
||||||
Selected text 2. (2 lines)
|
1235 Selected text 2. (2 lines)
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cat > "$dir/$(cksum <<< 'Selected text. (2 lines)')" << 'EOF'
|
cat > "$dir/$(cksum <<< 'Selected text. (2 lines)')" << 'EOF'
|
||||||
|
@ -70,7 +70,6 @@ EOF
|
||||||
### TESTS ###
|
### TESTS ###
|
||||||
|
|
||||||
temp=$(mktemp)
|
temp=$(mktemp)
|
||||||
trap 'rm -f -- "$temp"' EXIT
|
|
||||||
|
|
||||||
/tmp/clipmenu --foo bar > "$temp" 2>&1
|
/tmp/clipmenu --foo bar > "$temp" 2>&1
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
major_version=4
|
major_version=5
|
||||||
|
|
||||||
msg() {
|
msg() {
|
||||||
printf '>>> %s\n' "$@" >&2
|
printf '>>> %s\n' "$@" >&2
|
||||||
|
@ -9,7 +9,7 @@ msg() {
|
||||||
: "${CM_DIR="${XDG_RUNTIME_DIR-"${TMPDIR-/tmp}"}"}"
|
: "${CM_DIR="${XDG_RUNTIME_DIR-"${TMPDIR-/tmp}"}"}"
|
||||||
|
|
||||||
dir=$CM_DIR/clipmenu.$major_version.$USER
|
dir=$CM_DIR/clipmenu.$major_version.$USER
|
||||||
cache_file=$dir/line_cache
|
cache_file=$dir/line_cache_primary
|
||||||
|
|
||||||
log=$(mktemp)
|
log=$(mktemp)
|
||||||
tim=$(mktemp)
|
tim=$(mktemp)
|
||||||
|
@ -62,7 +62,7 @@ if ! (( NO_RECREATE )); then
|
||||||
)
|
)
|
||||||
read -r first_line_raw <<< "$data"
|
read -r first_line_raw <<< "$data"
|
||||||
printf -v first_line '%s (%s lines)\n' "$first_line_raw" "$num_lines"
|
printf -v first_line '%s (%s lines)\n' "$first_line_raw" "$num_lines"
|
||||||
printf '%s' "$first_line" >> "$cache_file"
|
printf '%d %s' "$i" "$first_line" >> "$cache_file"
|
||||||
fn=$dir/$(cksum <<< "$first_line")
|
fn=$dir/$(cksum <<< "$first_line")
|
||||||
printf '%s' "$data" > "$fn"
|
printf '%s' "$data" > "$fn"
|
||||||
done
|
done
|
||||||
|
|
Loading…
Reference in a new issue