Transcript search: n/N cannot reach most highlighted matches (highlighting scans the screen, navigation uses a narrower index)
Summary
In transcript view (Ctrl+O), / highlights every occurrence rendered on screen, but n/N can only step through matches found by a separate, much narrower message-level index. Any highlighted hit the index missed is unreachable: pressing n does nothing at all.
Repro
- A reasonably long session, fullscreen renderer (default).
Ctrl+Oto open the transcript./and search for a string that occurs in assistant thinking blocks or non-whitelisted tool inputs (e.g. anEditold_string) as well as in ordinary message text.- Scroll up with PageUp — several occurrences are visibly highlighted.
- Press
n/N— it will not visit them.
Debug evidence
claude --debug --debug-file=/tmp/cc.log, then grep -E 'seek\(i=|phantoms' /tmp/cc.log:
[DEBUG] seek(i=61 t=0): 31 positions
[DEBUG] seek(i=61 t=0): 5 positions
[DEBUG] seek(i=27 t=0): 2 positions
[DEBUG] seek(i=27 t=0): 1 positions
[DEBUG] step: wraparound at ptr=0, all 1 msgs phantoms
[DEBUG] step: wraparound at ptr=0, all 1 msgs phantoms
... (one line per `n` press, nothing moves)
all 1 msgs phantoms means the match index contained exactly one message, while many more were highlighted on screen. Note there are no no mount after scrollToIndex, skip lines — this is not a virtualization/mount-timing problem.
Cause
Highlighting and navigation are driven by two independent mechanisms.
Highlighting is a whole-screen scan, independent of the index — every rendered occurrence is painted:
v = tx(p.screen, this.searchHighlightQuery, this.stylePool)
Navigation is built from a message-level index via extractSearchText, whose base extractor only pulls:
user: text blocks, plustool_resultviatoolUseResultassistant: text blocks; fortool_useblocks only a whitelist of input fields —
["command","pattern","file_path","path","prompt","description","query","url","skill"] (plus args, files)
attachment: onlyrelevant_memories,queued_command,tool_host_result_lines- everything else:
""(default: break)
So assistant thinking blocks, non-whitelisted tool inputs (Edit old_string/new_string, Write content, …), and unhandled message types are highlighted but never indexed, and therefore never reachable with n/N.
Secondary issue
When the index legitimately contains a single message, n is a dead key even for that message's own hits. The step function computes:
let se = (M.ptr + C + E.length) % E.length // E.length === 1 => se === 0 === anchor
and the wraparound guard immediately bails and clears the highlight instead of cycling back to the first position within that message.
Expected
n/N should visit every occurrence that gets highlighted.
Environment
- claude 2.1.247 (also reproduced on 2.1.246)
- Arch Linux, kitty 0.48.2, fullscreen renderer