clipmenu

Simple clipboard management using dmenu
git clone https://git.sinitax.com/cdown/clipmenu
Log | Files | Refs | README | LICENSE | sfeed.txt

commit e8ba60e43228311b6da89245c49944405ae36a86
parent 7987dd1757a93dad8d706d533f5026cc6037fd49
Author: Chris Down <chris@chrisdown.name>
Date:   Fri,  6 Jan 2017 12:03:13 +0000

Have clipmenud cache first lines

Diffstat:
Mclipmenu | 29+++++------------------------
Mclipmenud | 36++++++++++++++++++++++++++++++++++++
2 files changed, 41 insertions(+), 24 deletions(-)

diff --git a/clipmenu b/clipmenu @@ -5,35 +5,16 @@ shopt -s nullglob # We use this to make sure the cache files are sorted bytewise LC_COLLATE=C -# Some people copy/paste huge swathes of text that could slow down dmenu -line_length_limit=500 - declare -A selections ordered_selections=() -files=("/tmp/clipmenu.$USER/"*) - -# We can't use `for ... in` here because we need to add files to -# ordered_selections from last to first -- that is, newest to oldest. Incoming -# clipboard entries have a ISO datetime prefixed to the front to aid in this. -for (( i=${#files[@]}-1; i>=0; i-- )); do - file=${files[$i]} - - # We look for the first line matching regex /./ here because we want the - # first line that can provide reasonable context to the user. That is, if - # you have 5 leading lines of whitespace, displaying " (6 lines)" is much - # less useful than displaying "foo (6 lines)", where "foo" is the first - # line in the entry with actionable context. - first_line=$(sed -n '/./{p;q}' "$file" | cut -c1-"$line_length_limit") - lines=$(wc -l < "$file") - - if (( lines > 1 )); then - first_line+=" ($lines lines)" - fi +cache_file=/tmp/clipmenu.$USER/line_cache +# We use tac since we want newest to oldest, and we append in clipmenud +while IFS='|' read -r full_file first_line; do ordered_selections+=("$first_line") - selections[$first_line]=$file -done + selections[$first_line]=$full_file +done < <(tac "$cache_file") # 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 diff --git a/clipmenud b/clipmenud @@ -1,5 +1,36 @@ #!/bin/bash +get_first_line() { + # Args: + # - $1, the file or data + # - $2, optional, the line length limit + + data=${1?} + line_length_limit=${2-300} + + # We look for the first line matching regex /./ here because we want the + # first line that can provide reasonable context to the user. That is, if + # you have 5 leading lines of whitespace, displaying " (6 lines)" is much + # less useful than displaying "foo (6 lines)", where "foo" is the first + # line in the entry with actionable context. + awk -v limit="$line_length_limit" ' + BEGIN { printed = 0; } + + printed == 0 && NF { + $0 = substr($0, 0, limit); + printf("%s", $0); + printed = 1; + } + + END { + if (NR > 1) { + print " (" NR " lines)"; + } else { + printf("\n"); + } + }' <<< "$data" +} + hr_msg() { printf -- '\n--- %s ---\n\n' "$1" >&2 } @@ -38,6 +69,7 @@ print_debug_info() { print_debug_info 'Initialising' 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 @@ -96,6 +128,10 @@ while sleep "${CLIPMENUD_SLEEP:-0.5}"; do debug "Writing $data to $filename" printf '%s' "$data" > "$filename" + debug "Writing new entry to $cache_file" + printf '%s|%s\n' \ + "$filename" "$(get_first_line "$data")" >> "$cache_file" + if ! (( NO_OWN_CLIPBOARD )) && [[ $selection != primary ]]; then # Take ownership of the clipboard, in case the original application # is unable to serve the clipboard request (due to being suspended,