Merge branch 'release/3.0.0'

This commit is contained in:
Chris Down 2017-02-17 12:07:05 -05:00
commit d938354148
7 changed files with 157 additions and 28 deletions

View file

@ -8,6 +8,7 @@ before_script:
script: script:
- shellcheck -s bash clipmenu clipmenud - shellcheck -s bash clipmenu clipmenud
- tests/test-clipmenu
matrix: matrix:
fast_finish: true fast_finish: true

View file

@ -1,11 +1,38 @@
clipmenu is a simple clipboard manager using [dmenu][] and [xsel][]. clipmenu is a simple clipboard manager using [dmenu][] and [xsel][].
To use it, start the `clipmenud` daemon, and then call `clipmenu` to launch # Usage
`dmenu`. Upon choosing an entry, it is copied to the clipboard.
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 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 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/ [dmenu]: http://tools.suckless.org/dmenu/
[xsel]: http://www.vergenet.net/~conrad/software/xsel/ [xsel]: http://www.vergenet.net/~conrad/software/xsel/

View file

@ -1,15 +1,17 @@
#!/bin/bash #!/bin/bash
major_version=3
shopt -s nullglob shopt -s nullglob
cache_dir=/tmp/clipmenu.$USER cache_dir=/tmp/clipmenu.$major_version.$USER
cache_file=$cache_dir/line_cache cache_file=$cache_dir/line_cache
# 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" | uniq | dmenu -l 8 "$@") chosen_line=$(tac "$cache_file" | awk '!seen[$0]++' | dmenu -l 8 "$@")
[[ $chosen_line ]] || exit 1 [[ $chosen_line ]] || exit 1
@ -22,9 +24,5 @@ if ! [[ -f "$file" ]]; then
fi fi
for selection in clipboard primary; do for selection in clipboard primary; do
if type -p xsel >/dev/null 2>&1; then xsel --logfile /dev/null -i --"$selection" < "$file"
xsel --logfile /dev/null -i --"$selection" < "$file"
else
xclip -sel "$selection" < "$file"
fi
done done

View file

@ -1,5 +1,9 @@
#!/bin/bash #!/bin/bash
major_version=3
cache_dir=/tmp/clipmenu.$major_version.$USER/
cache_file=$cache_dir/line_cache
get_first_line() { get_first_line() {
# Args: # Args:
# - $1, the file or data # - $1, the file or data
@ -37,9 +41,6 @@ debug() {
fi fi
} }
cache_dir=/tmp/clipmenu.$USER/
cache_file=$cache_dir/line_cache
# 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"
@ -48,15 +49,8 @@ declare -A last_data
declare -A last_filename declare -A last_filename
while sleep "${CLIPMENUD_SLEEP:-0.5}"; do while sleep "${CLIPMENUD_SLEEP:-0.5}"; do
for selection in clipboard primary; do for selection in clipboard primary; do
if type -p xsel >/dev/null 2>&1; then data=$(xsel --logfile /dev/null -o --"$selection"; printf x)
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" 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 # 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.
if type -p xsel >/dev/null 2>&1; then xsel --logfile /dev/null -o --"$selection" | xsel -i --"$selection"
xsel --logfile /dev/null -o --"$selection" | xsel -i --"$selection"
else
xclip -o -sel "$selection" | xclip -i -sel "$selection"
fi
fi fi
done done
done done

31
init/clipmenud.service Normal file
View 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
View 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"

View file

@ -1,10 +1,12 @@
#!/bin/bash #!/bin/bash
major_version=3
msg() { msg() {
printf '>>> %s\n' "$@" >&2 printf '>>> %s\n' "$@" >&2
} }
dir=/tmp/clipmenu.$USER dir=/tmp/clipmenu.$major_version.$USER
cache_file=$dir/line_cache cache_file=$dir/line_cache
log=$(mktemp) log=$(mktemp)
@ -35,7 +37,6 @@ shopt -s expand_aliases
alias dmenu=: alias dmenu=:
alias xsel=: alias xsel=:
alias xclip=:
EOF EOF