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:
M | clipmenu | | | 29 | +++++------------------------ |
M | clipmenud | | | 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,