tmux-grab: preview scrollback context for the highlighted item
Token extraction flattens the pane's scrollback into a deduped list,
losing which line each token came from. The fzf --preview flag now calls
the script itself with a "__preview__" sentinel argument and the
highlighted token, letting fzf handle quoting instead of hand-building
an escaped command string. That invocation reads the captured pane text
from a temp file the main run wrote and exported via PANE_GRAB_FILE, and
prints 2 lines of context on either side of the token's most recent
occurrence, with the matching line bolded.
Also swaps tac for tail -r in the reversal step (not every machine has
tac installed) and fixes a stale comment that still referenced tac.
Assisted-by: Claude Sonnet 5 via pi
diff --git a/bin/,tmux-grab b/bin/,tmux-grab
index 5d08cafc..99c285eb 100755
--- a/bin/,tmux-grab
+++ b/bin/,tmux-grab
@@ -12,20 +12,35 @@ main() {
local pane_id
pane_id=$(tmux display-message -p -t '{last}' '#{pane_id}')
- # tac reverses line order so the most recent scrollback surfaces first in
- # the fzf list, while keeping left-to-right token order within each line.
+ # Captured once in natural (oldest-to-newest) order; reused both as the
+ # preview's context source and, reversed below, for token extraction.
local pane_text
- pane_text=$(tmux capture-pane -p -S - -t "$pane_id" | tail -r)
+ pane_text=$(tmux capture-pane -p -S - -t "$pane_id")
[[ -n "$pane_text" ]] || exit 0
+ # Saved to a file so the preview subprocess -- a separate invocation of
+ # this script, spawned by fzf once per highlighted item -- can look up
+ # context for that item without re-capturing the pane itself.
+ local pane_file
+ pane_file=$(mktemp)
+ trap 'rm -f "$pane_file"' EXIT
+ printf '%s\n' "$pane_text" >"$pane_file"
+ export PANE_GRAB_FILE="$pane_file"
+
+ # tail -r reverses line order so the most recent scrollback surfaces
+ # first in the fzf list, while keeping left-to-right token order within
+ # each line.
+ local pane_text_reversed
+ pane_text_reversed=$(tail -r <<<"$pane_text")
+
# Two passes: whitespace-delimited tokens first (so "foo/bar:baz" is a
# candidate), then punctuation-split sub-tokens (so "foo", "bar", "baz"
# are too). Dedup preserves first-seen order, so exact repeats collapse.
local tokens
tokens=$(
{
- printf '%s\n' "$pane_text" | grep --only-matching --extended-regexp '\S+' || true
- printf '%s\n' "$pane_text" | grep --only-matching --extended-regexp '[[:alnum:]_]+' || true
+ printf '%s\n' "$pane_text_reversed" | grep --only-matching --extended-regexp '\S+' || true
+ printf '%s\n' "$pane_text_reversed" | grep --only-matching --extended-regexp '[[:alnum:]_]+' || true
} | awk '!seen[$0]++'
)
[[ -n "$tokens" ]] || exit 0
@@ -52,6 +67,7 @@ main() {
--highlight-line --info inline-right \
--header 'enter: insert ctrl-y: copy ctrl-o: open' --header-first \
--expect ctrl-y,ctrl-o \
+ --preview "\"$0\" __preview__ {}" \
--border-label ' grab ') || exit 0
[[ -n "$result" ]] || exit 0
@@ -74,4 +90,41 @@ main() {
esac
}
+# Renders the preview pane for the item currently highlighted in fzf: the
+# 2 lines of scrollback on either side of that item's most recent occurrence,
+# with the matching line itself bolded. Invoked as a fresh instance of this
+# script (via the --preview flag above), so it reads the captured pane text
+# from the file path the main invocation exported, rather than recapturing.
+preview_mode() {
+ local token=${1:-}
+ local file=${PANE_GRAB_FILE:-}
+ if [[ -z "$token" || -z "$file" || ! -f "$file" ]]; then
+ echo '(no preview available)'
+ return
+ fi
+
+ # grep preserves the file's natural top-to-bottom order, so the last
+ # match is the occurrence closest to "now" in the scrollback.
+ local line
+ line=$(grep -Fn -- "$token" "$file" | tail -n1 | cut -d: -f1) || true
+ if [[ -z "$line" ]]; then
+ echo '(not found in scrollback)'
+ return
+ fi
+
+ local start=$(( line > 2 ? line - 2 : 1 ))
+ local end=$(( line + 2 ))
+ awk -v start="$start" -v end="$end" -v hl="$line" '
+ NR >= start && NR <= end {
+ if (NR == hl) printf "\033[1m%s\033[0m\n", $0
+ else print
+ }
+ ' "$file"
+}
+
+if [[ "${1:-}" == "__preview__" ]]; then
+ preview_mode "${2:-}"
+ exit 0
+fi
+
main "$@"