Merge branch 'release/3.0.0'
This commit is contained in:
commit
d938354148
|
@ -8,6 +8,7 @@ before_script:
|
|||
|
||||
script:
|
||||
- shellcheck -s bash clipmenu clipmenud
|
||||
- tests/test-clipmenu
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
|
33
README.md
33
README.md
|
@ -1,11 +1,38 @@
|
|||
clipmenu is a simple clipboard manager using [dmenu][] and [xsel][].
|
||||
|
||||
To use it, start the `clipmenud` daemon, and then call `clipmenu` to launch
|
||||
`dmenu`. Upon choosing an entry, it is copied to the clipboard.
|
||||
# Usage
|
||||
|
||||
Start `clipmenud`, then run `clipmenu` to select something to put on the
|
||||
clipboard.
|
||||
|
||||
A systemd user service for starting clipmenud is included at
|
||||
[init/clipmenud.service](https://github.com/cdown/clipmenu/blob/develop/init/clipmenud.service).
|
||||
|
||||
All args passed to clipmenu are transparently dispatched to dmenu. That is, if
|
||||
you usually call dmenu with args to set colours and other properties, you can
|
||||
invoke clipmenu in exactly the same way to get the same effect.
|
||||
invoke clipmenu in exactly the same way to get the same effect, like so:
|
||||
|
||||
clipmenu -i -fn Terminus:size=8 -nb '#002b36' -nf '#839496' -sb '#073642' -sf '#93a1a1'
|
||||
|
||||
# How does it work?
|
||||
|
||||
The code is fairly simple and easy to follow, you may find it easier to read
|
||||
there, but it basically works like this:
|
||||
|
||||
## clipmenud
|
||||
|
||||
1. `clipmenud` polls the clipboard every 0.5 seconds (or another interval as
|
||||
configured with the `CLIPMENUD_SLEEP` environment variable). Unfortunately
|
||||
there's 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
|
||||
to the cache directory.
|
||||
|
||||
## clipmenu
|
||||
|
||||
1. `clipmenu` reads the cache directory to find all available clips.
|
||||
2. `dmenu` is executed to allow the user to select a clip.
|
||||
3. After selection, the clip is put onto the PRIMARY and CLIPBOARD X
|
||||
selections.
|
||||
|
||||
[dmenu]: http://tools.suckless.org/dmenu/
|
||||
[xsel]: http://www.vergenet.net/~conrad/software/xsel/
|
||||
|
|
10
clipmenu
10
clipmenu
|
@ -1,15 +1,17 @@
|
|||
#!/bin/bash
|
||||
|
||||
major_version=3
|
||||
|
||||
shopt -s nullglob
|
||||
|
||||
cache_dir=/tmp/clipmenu.$USER
|
||||
cache_dir=/tmp/clipmenu.$major_version.$USER
|
||||
cache_file=$cache_dir/line_cache
|
||||
|
||||
# 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
|
||||
# one will be ignored.
|
||||
chosen_line=$(tac "$cache_file" | uniq | dmenu -l 8 "$@")
|
||||
chosen_line=$(tac "$cache_file" | awk '!seen[$0]++' | dmenu -l 8 "$@")
|
||||
|
||||
[[ $chosen_line ]] || exit 1
|
||||
|
||||
|
@ -22,9 +24,5 @@ if ! [[ -f "$file" ]]; then
|
|||
fi
|
||||
|
||||
for selection in clipboard primary; do
|
||||
if type -p xsel >/dev/null 2>&1; then
|
||||
xsel --logfile /dev/null -i --"$selection" < "$file"
|
||||
else
|
||||
xclip -sel "$selection" < "$file"
|
||||
fi
|
||||
done
|
||||
|
|
18
clipmenud
18
clipmenud
|
@ -1,5 +1,9 @@
|
|||
#!/bin/bash
|
||||
|
||||
major_version=3
|
||||
cache_dir=/tmp/clipmenu.$major_version.$USER/
|
||||
cache_file=$cache_dir/line_cache
|
||||
|
||||
get_first_line() {
|
||||
# Args:
|
||||
# - $1, the file or data
|
||||
|
@ -37,9 +41,6 @@ debug() {
|
|||
fi
|
||||
}
|
||||
|
||||
cache_dir=/tmp/clipmenu.$USER/
|
||||
cache_file=$cache_dir/line_cache
|
||||
|
||||
# It's ok that this only applies to the final directory.
|
||||
# shellcheck disable=SC2174
|
||||
mkdir -p -m0700 "$cache_dir"
|
||||
|
@ -48,15 +49,8 @@ declare -A last_data
|
|||
declare -A last_filename
|
||||
|
||||
while sleep "${CLIPMENUD_SLEEP:-0.5}"; do
|
||||
|
||||
for selection in clipboard primary; do
|
||||
if type -p xsel >/dev/null 2>&1; then
|
||||
debug 'Using xsel'
|
||||
data=$(xsel --logfile /dev/null -o --"$selection"; printf x)
|
||||
else
|
||||
debug 'Using xclip'
|
||||
data=$(xclip -o -sel "$selection"; printf x)
|
||||
fi
|
||||
|
||||
debug "Data before stripping: $data"
|
||||
|
||||
|
@ -109,11 +103,7 @@ while sleep "${CLIPMENUD_SLEEP:-0.5}"; do
|
|||
# We can't colocate this with the above copying code because
|
||||
# https://github.com/cdown/clipmenu/issues/34 requires knowing if
|
||||
# we would skip first.
|
||||
if type -p xsel >/dev/null 2>&1; then
|
||||
xsel --logfile /dev/null -o --"$selection" | xsel -i --"$selection"
|
||||
else
|
||||
xclip -o -sel "$selection" | xclip -i -sel "$selection"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
|
31
init/clipmenud.service
Normal file
31
init/clipmenud.service
Normal file
|
@ -0,0 +1,31 @@
|
|||
[Unit]
|
||||
Description=Clipmenu daemon
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/clipmenud
|
||||
Restart=always
|
||||
RestartSec=0
|
||||
Environment=DISPLAY=:0
|
||||
|
||||
SystemCallFilter=@basic-io @default @io-event @ipc @network-io @process \
|
||||
brk fadvise64 getegid geteuid getgid getgroups getpgrp \
|
||||
getpid getppid getrlimit getuid ioctl mprotect rt_sigaction \
|
||||
rt_sigprocmask setitimer setsid sysinfo umask uname wait4
|
||||
|
||||
# @file-system will handle this once v233 is released, see
|
||||
# http://bit.ly/2l1r8Ah for more details.
|
||||
SystemCallFilter=access chdir close faccessat fcntl fstat getcwd mkdir mmap \
|
||||
munmap open stat statfs unlink
|
||||
|
||||
MemoryDenyWriteExecute=yes
|
||||
NoNewPrivileges=yes
|
||||
ProtectControlGroups=yes
|
||||
ProtectKernelTunables=yes
|
||||
RestrictAddressFamilies=
|
||||
RestrictRealtime=yes
|
||||
|
||||
ProtectSystem=strict
|
||||
ReadWritePaths=/tmp
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
81
tests/test-clipmenu
Executable file
81
tests/test-clipmenu
Executable file
|
@ -0,0 +1,81 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -x
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
major_version=3
|
||||
dir=/tmp/clipmenu.$major_version.$USER
|
||||
cache_file=$dir/line_cache
|
||||
|
||||
if [[ $0 == /* ]]; then
|
||||
location=${0%/*}
|
||||
else
|
||||
location=$PWD/${0#./}
|
||||
location=${location%/*}
|
||||
fi
|
||||
|
||||
cat - "$location/../clipmenu" > /tmp/clipmenu << 'EOF'
|
||||
#!/bin/bash
|
||||
|
||||
shopt -s expand_aliases
|
||||
|
||||
shim() {
|
||||
printf '%s args:' "$1" >&2
|
||||
printf ' %q' "${@:2}" >&2
|
||||
printf '\n' >&2
|
||||
|
||||
i=0
|
||||
|
||||
while IFS= read -r line; do
|
||||
let i++
|
||||
printf '%s line %d stdin: %s\n' "$1" "$i" "$line" >&2
|
||||
done
|
||||
|
||||
if [[ -v SHIM_STDOUT ]]; then
|
||||
printf '%s\n' "$SHIM_STDOUT"
|
||||
fi
|
||||
}
|
||||
|
||||
alias dmenu='SHIM_STDOUT="Selected text. (2 lines)" shim dmenu'
|
||||
alias xsel='shim xsel'
|
||||
alias xclip='shim xclip'
|
||||
EOF
|
||||
|
||||
chmod a+x /tmp/clipmenu
|
||||
|
||||
rm -rf "$dir"
|
||||
mkdir -p "$dir"
|
||||
|
||||
cat > "$cache_file" << 'EOF'
|
||||
Selected text. (2 lines)
|
||||
Selected text 2. (2 lines)
|
||||
EOF
|
||||
|
||||
cat > "$dir/$(cksum <<< 'Selected text. (2 lines)')" << 'EOF'
|
||||
Selected text.
|
||||
Yes, it's selected text.
|
||||
EOF
|
||||
|
||||
### TESTS ###
|
||||
|
||||
output=$(/tmp/clipmenu --foo bar 2>&1)
|
||||
|
||||
temp=$(mktemp)
|
||||
trap 'rm -f -- "$temp"' EXIT
|
||||
|
||||
printf '%s\n' "$output" > "$temp"
|
||||
|
||||
# Arguments are transparently passed to dmenu
|
||||
grep -Fxq 'dmenu args: -l 8 --foo bar' "$temp"
|
||||
|
||||
# Output from cache file should get to dmenu, reversed
|
||||
grep -Fxq 'dmenu line 1 stdin: Selected text 2. (2 lines)' "$temp"
|
||||
grep -Fxq 'dmenu line 2 stdin: Selected text. (2 lines)' "$temp"
|
||||
|
||||
# xsel should copy both to clipboard *and* primary
|
||||
grep -Fxq 'xsel args: --logfile /dev/null -i --clipboard' "$temp"
|
||||
grep -Fxq 'xsel args: --logfile /dev/null -i --primary' "$temp"
|
||||
|
||||
grep -Fxq 'xsel line 1 stdin: Selected text.' "$temp"
|
||||
grep -Fxq "xsel line 2 stdin: Yes, it's selected text." "$temp"
|
|
@ -1,10 +1,12 @@
|
|||
#!/bin/bash
|
||||
|
||||
major_version=3
|
||||
|
||||
msg() {
|
||||
printf '>>> %s\n' "$@" >&2
|
||||
}
|
||||
|
||||
dir=/tmp/clipmenu.$USER
|
||||
dir=/tmp/clipmenu.$major_version.$USER
|
||||
cache_file=$dir/line_cache
|
||||
|
||||
log=$(mktemp)
|
||||
|
@ -35,7 +37,6 @@ shopt -s expand_aliases
|
|||
|
||||
alias dmenu=:
|
||||
alias xsel=:
|
||||
alias xclip=:
|
||||
|
||||
EOF
|
||||
|
Loading…
Reference in a new issue