MCPcopy Index your code
hub / github.com/codeaashu/claude-code / TranscriptSearchBar

Function TranscriptSearchBar

src/screens/REPL.tsx:368–472  ·  view source on GitHub ↗

less-style / bar. 1-row, same border-top styling as TranscriptModeFooter * so swapping them in the bottom slot doesn't shift ScrollBox height. * useSearchInput handles readline editing; we report query changes and * render the counter. Incremental — re-search + highlight per keystroke.

({
  jumpRef,
  count,
  current,
  onClose,
  onCancel,
  setHighlight,
  initialQuery
}: {
  jumpRef: RefObject<JumpHandle | null>;
  count: number;
  current: number;
  /** Enter — commit. Query persists for n/N. */
  onClose: (lastQuery: string) => void;
  /** Esc/ctrl+c/ctrl+g — undo to pre-/ state. */
  onCancel: () => void;
  setHighlight: (query: string) => void;
  // Seed with the previous query (less: / shows last pattern). Mount-fire
  // of the effect re-scans with the same query — idempotent (same matches,
  // nearest-ptr, same highlights). User can edit or clear.
  initialQuery: string;
})

Source from the content-addressed store, hash-verified

366 * useSearchInput handles readline editing; we report query changes and
367 * render the counter. Incremental — re-search + highlight per keystroke. */
368function TranscriptSearchBar({
369 jumpRef,
370 count,
371 current,
372 onClose,
373 onCancel,
374 setHighlight,
375 initialQuery
376}: {
377 jumpRef: RefObject<JumpHandle | null>;
378 count: number;
379 current: number;
380 /** Enter — commit. Query persists for n/N. */
381 onClose: (lastQuery: string) => void;
382 /** Esc/ctrl+c/ctrl+g — undo to pre-/ state. */
383 onCancel: () => void;
384 setHighlight: (query: string) => void;
385 // Seed with the previous query (less: / shows last pattern). Mount-fire
386 // of the effect re-scans with the same query — idempotent (same matches,
387 // nearest-ptr, same highlights). User can edit or clear.
388 initialQuery: string;
389}): React.ReactNode {
390 const {
391 query,
392 cursorOffset
393 } = useSearchInput({
394 isActive: true,
395 initialQuery,
396 onExit: () => onClose(query),
397 onCancel
398 });
399 // Index warm-up runs before the query effect so it measures the real
400 // cost — otherwise setSearchQuery fills the cache first and warm
401 // reports ~0ms while the user felt the actual lag.
402 // First / in a transcript session pays the extractSearchText cost.
403 // Subsequent / return 0 immediately (indexWarmed ref in VML).
404 // Transcript is frozen at ctrl+o so the cache stays valid.
405 // Initial 'building' so warmDone is false on mount — the [query] effect
406 // waits for the warm effect's first resolve instead of racing it. With
407 // null initial, warmDone would be true on mount → [query] fires →
408 // setSearchQuery fills cache → warm reports ~0ms while the user felt
409 // the real lag.
410 const [indexStatus, setIndexStatus] = React.useState<'building' | {
411 ms: number;
412 } | null>('building');
413 React.useEffect(() => {
414 let alive = true;
415 const warm = jumpRef.current?.warmSearchIndex;
416 if (!warm) {
417 setIndexStatus(null); // VML not mounted yet — rare, skip indicator
418 return;
419 }
420 setIndexStatus('building');
421 warm().then(ms => {
422 if (!alive) return;
423 // <20ms = imperceptible. No point showing "indexed in 3ms".
424 if (ms < 20) {
425 setIndexStatus(null);

Callers

nothing calls this directly

Calls 1

useSearchInputFunction · 0.85

Tested by

no test coverage detected