diff --git a/clipmenu b/clipmenu index 4bdffe6..3d0d579 100755 --- a/clipmenu +++ b/clipmenu @@ -3,17 +3,10 @@ shopt -s nullglob # We use this to make sure the cache files are sorted bytewise -LC_COLLATE=C - -declare -A selections +export LC_COLLATE=C 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 - 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 # argument to override an earlier one. That is, if the user passes in `-l`, our @@ -22,10 +15,32 @@ chosen_line=$(sed 's/^[^|]\+|//' "$cache_file" | tac | uniq | dmenu -l 8 "$@") [[ $chosen_line ]] || exit 1 +# Naive, but performant path, only follow expensive path if it doesn't work +out_line=$(grep -F "|$chosen_line" "$cache_file") +out_length=$(wc -l <<< "$out_line") + +if (( out_length == 1 )); then + # Cheap path succeded + file=${out_line%%|*} +elif (( out_length > 1 )); then + # Cheap path failed + while IFS='|' read -r full_file first_line; do + if [[ $first_line == "$chosen_line" ]]; then + file=$full_file + break + fi + done <<< "$out_line" +else + # We didn't find this in cache + printf 'FATAL: %s not in cache, run clipmenu-fsck\n' "$chosen_line" >&2 + exit 2 +fi + + for selection in clipboard primary; do if type -p xsel >/dev/null 2>&1; then - xsel -i --"$selection" < "${selections[$chosen_line]}" + xsel -i --"$selection" < "$file" else - xclip -sel "$selection" < "${selections[$chosen_line]}" + xclip -sel "$selection" < "$file" fi done