bin: stop tmux-grab from guessing at line wraps
The wrap-join heuristic in bin/,tmux-grab reconnected hard-wrapped
lines by checking for whitespace at the line boundary, but that
signature also matches almost any two adjacent non-blank terminal
lines (a job-control message right above the next shell prompt, for
instance). It fused unrelated lines into a spurious candidate while
still emitting one of them alone, and once fzf truncated both to the
popup width they read as duplicates.

Capture with tmux capture-pane -J instead: it joins exactly the rows
tmux itself tracked as wrapped, so the heuristic (RUNS_AWK,
combined_candidates, find_run_range) is no longer needed and is
removed. A hard-wrapped URL or path now arrives as one line and the
existing whitespace-tokenizing pass picks it up whole.

Assisted-by: Claude Sonnet 5 via Claude Code
change kxzkrlpsxuxlxlwluvnnsvwwxlmwyozl
commit 1b5941306880ab27c57d5818d46e0a3cebb30eaa
author Alpha Chen <alpha@kejadlen.dev>
date
parent rxxmywlr
diff --git a/bin/,tmux-grab b/bin/,tmux-grab
index f91d6427..cba92444 100755
--- a/bin/,tmux-grab
+++ b/bin/,tmux-grab
@@ -5,79 +5,15 @@ if [[ "${TRACE-0}" == "1" ]]; then
     set -o xtrace
 fi
 
-# Shared awk source, concatenated ahead of a caller-supplied emit()/END.
-# joinable() encodes the wrap heuristic: two physical lines belong to the
-# same logical string only when neither side shows a deliberate break --
-# the left line must not end in whitespace and the right must not begin
-# with it (a padded or indented boundary means the newline was intentional,
-# not a hard terminal wrap). Empty lines fail both tests, so a blank line --
-# two newlines, not "only a newline in between" -- always breaks a run.
-# walk_runs() reports each maximal chain of 2+ such lines via emit(start,end).
-# shellcheck disable=SC2016  # $0 et al. are awk fields, not shell expansions.
-RUNS_AWK='
-function joinable(a, b) {
-    return (a != "" && b != "" && a !~ /[[:space:]]$/ && b !~ /^[[:space:]]/)
-}
-function walk_runs(   i, j) {
-    i = 1
-    while (i <= NR) {
-        j = i
-        while (j < NR && joinable(lines[j], lines[j+1])) j++
-        if (j > i) emit(i, j)
-        i = (j > i) ? j + 1 : i + 1
-    }
-}
-{ lines[NR] = $0 }
-'
-
-# Emits one candidate per wrap-joined run, newest (bottom-most) run first to
-# match the reversed token passes below. Each run yields its no-separator
-# concatenation plus every member line individually, so both the
-# reconstructed string and its pieces stay grabbable.
-combined_candidates() {
-    awk "$RUNS_AWK"'
-    function emit(s, e) { runs_start[++runs_n] = s; runs_end[runs_n] = e }
-    END {
-        walk_runs()
-        for (r = runs_n; r >= 1; r--) {
-            joined = ""
-            for (k = runs_start[r]; k <= runs_end[r]; k++) joined = joined lines[k]
-            print joined
-            for (k = runs_start[r]; k <= runs_end[r]; k++) print lines[k]
-        }
-    }
-    ' <<<"$1"
-}
-
-# Locates the run whose concatenation equals a combined candidate, so the
-# preview can bold its span. Prints "start end" (1-based line numbers) of the
-# last such run -- the one closest to now -- or nothing. TOKEN rides in via
-# the environment to dodge awk -v backslash processing on URLs and paths.
-find_run_range() {
-    local token=$1 file=$2
-    TOKEN="$token" awk "$RUNS_AWK"'
-    function emit(s, e,   k, joined) {
-        joined = ""
-        for (k = s; k <= e; k++) joined = joined lines[k]
-        if (joined == ENVIRON["TOKEN"]) { best_start = s; best_end = e }
-    }
-    END {
-        walk_runs()
-        if (best_start > 0) print best_start, best_end
-    }
-    ' "$file"
-}
-
-# Prints a file window spanning 2 lines on either side of [hlstart, hlend],
-# with that inclusive range bolded (a single line for plain tokens, a span
-# for combined candidates).
+# Prints a file window spanning 2 lines on either side of hlline, with that
+# line bolded.
 render_preview() {
-    local file=$1 hlstart=$2 hlend=$3
-    local start=$(( hlstart > 2 ? hlstart - 2 : 1 ))
-    local end=$(( hlend + 2 ))
-    awk -v start="$start" -v end="$end" -v hlstart="$hlstart" -v hlend="$hlend" '
+    local file=$1 hlline=$2
+    local start=$(( hlline > 2 ? hlline - 2 : 1 ))
+    local end=$(( hlline + 2 ))
+    awk -v start="$start" -v end="$end" -v hlline="$hlline" '
         NR >= start && NR <= end {
-            if (NR >= hlstart && NR <= hlend) printf "\033[1m%s\033[0m\n", $0
+            if (NR == hlline) printf "\033[1m%s\033[0m\n", $0
             else print
         }
     ' "$file"
@@ -90,10 +26,15 @@ main() {
     local pane_id
     pane_id=$(tmux display-message -p -t '{last}' '#{pane_id}')
 
+    # -J asks tmux for its own hard-wrap tracking instead of guessing from
+    # whitespace: rows the terminal actually wrapped come back pre-joined (a
+    # mid-word URL or path split across rows becomes one line), while
+    # separate application-printed lines -- even ones butted up against each
+    # other with no blank line between, like a two-line prompt -- stay apart.
     # 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")
+    pane_text=$(tmux capture-pane -p -J -S - -t "$pane_id")
     [[ -n "$pane_text" ]] || exit 0
 
     # Saved to a file so the preview subprocess -- a separate invocation of
@@ -111,20 +52,19 @@ main() {
     local pane_text_reversed
     pane_text_reversed=$(tail -r <<<"$pane_text")
 
-    # Four passes, feeding a first-seen dedup so exact repeats collapse.
-    # Wrap-joined runs come first (natural order, so it reads the unreversed
-    # capture) to surface reconstructed strings at the top; then
-    # whitespace-delimited tokens (so "foo/bar:baz" is a candidate); then
-    # parenthesized spans with the parens stripped (so "(utils.rb:42)"
-    # yields "utils.rb:42", and a parenthetical phrase survives as one
-    # candidate instead of shattering at its inner spaces); then
-    # punctuation-split sub-tokens (so "foo", "bar", "baz" are too). A final
-    # filter drops any candidate carrying a raw control byte -- stray escape-
-    # sequence remnants, bells, and the like -- so only real text reaches fzf.
+    # Three passes, feeding a first-seen dedup so exact repeats collapse.
+    # Whitespace-delimited tokens first (so "foo/bar:baz" is a candidate,
+    # and a hard-wrapped URL or path -- one line now, courtesy of -J --
+    # comes through whole); then parenthesized spans with the parens
+    # stripped (so "(utils.rb:42)" yields "utils.rb:42", and a parenthetical
+    # phrase survives as one candidate instead of shattering at its inner
+    # spaces); then punctuation-split sub-tokens (so "foo", "bar", "baz" are
+    # too). A final filter drops any candidate carrying a raw control byte --
+    # stray escape-sequence remnants, bells, and the like -- so only real
+    # text reaches fzf.
     local tokens
     tokens=$(
         {
-            combined_candidates "$pane_text"
             printf '%s\n' "$pane_text_reversed" | grep --only-matching --extended-regexp '\S+' || true
             printf '%s\n' "$pane_text_reversed" | awk '{
                 line = $0
@@ -196,23 +136,13 @@ preview_mode() {
         return
     fi
 
-    # A plain token, a substring of a line, or an individual member line of a
-    # run all appear verbatim on some line; grep keeps natural top-to-bottom
-    # order, so the last match is the occurrence closest to "now".
+    # Every candidate, including a hard-wrapped string -J already joined,
+    # appears verbatim on some line; grep keeps natural top-to-bottom order,
+    # so the last match is the occurrence closest to "now".
     local line
     line=$(grep -Fn -- "$token" "$file" | tail -n1 | cut -d: -f1) || true
     if [[ -n "$line" ]]; then
-        render_preview "$file" "$line" "$line"
-        return
-    fi
-
-    # A combined candidate exists only as the concatenation of consecutive
-    # lines, never verbatim, so fall back to locating its run and bolding the
-    # whole span.
-    local range
-    range=$(find_run_range "$token" "$file") || true
-    if [[ -n "$range" ]]; then
-        render_preview "$file" "${range% *}" "${range#* }"
+        render_preview "$file" "$line"
         return
     fi