MCPcopy Create free account
hub / github.com/Noumena-Network/code / TranscriptSearchBar

Function TranscriptSearchBar

src/screens/REPL.tsx:425–529  ·  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

423 * useSearchInput handles readline editing; we report query changes and
424 * render the counter. Incremental — re-search + highlight per keystroke. */
425function TranscriptSearchBar({
426 jumpRef,
427 count,
428 current,
429 onClose,
430 onCancel,
431 setHighlight,
432 initialQuery
433}: {
434 jumpRef: RefObject<JumpHandle | null>;
435 count: number;
436 current: number;
437 /** Enter — commit. Query persists for n/N. */
438 onClose: (lastQuery: string) => void;
439 /** Esc/ctrl+c/ctrl+g — undo to pre-/ state. */
440 onCancel: () => void;
441 setHighlight: (query: string) => void;
442 // Seed with the previous query (less: / shows last pattern). Mount-fire
443 // of the effect re-scans with the same query — idempotent (same matches,
444 // nearest-ptr, same highlights). User can edit or clear.
445 initialQuery: string;
446}): React.ReactNode {
447 const {
448 query,
449 cursorOffset
450 } = useSearchInput({
451 isActive: true,
452 initialQuery,
453 onExit: () => onClose(query),
454 onCancel
455 });
456 // Index warm-up runs before the query effect so it measures the real
457 // cost — otherwise setSearchQuery fills the cache first and warm
458 // reports ~0ms while the user felt the actual lag.
459 // First / in a transcript session pays the extractSearchText cost.
460 // Subsequent / return 0 immediately (indexWarmed ref in VML).
461 // Transcript is frozen at ctrl+o so the cache stays valid.
462 // Initial 'building' so warmDone is false on mount — the [query] effect
463 // waits for the warm effect's first resolve instead of racing it. With
464 // null initial, warmDone would be true on mount → [query] fires →
465 // setSearchQuery fills cache → warm reports ~0ms while the user felt
466 // the real lag.
467 const [indexStatus, setIndexStatus] = React.useState<'building' | {
468 ms: number;
469 } | null>('building');
470 React.useEffect(() => {
471 let alive = true;
472 const warm = jumpRef.current?.warmSearchIndex;
473 if (!warm) {
474 setIndexStatus(null); // VML not mounted yet — rare, skip indicator
475 return;
476 }
477 setIndexStatus('building');
478 warm().then(ms => {
479 if (!alive) return;
480 // <20ms = imperceptible. No point showing "indexed in 3ms".
481 if (ms < 20) {
482 setIndexStatus(null);

Callers

nothing calls this directly

Calls 1

useSearchInputFunction · 0.85

Tested by

no test coverage detected