MCPcopy Create free account
hub / github.com/claude-code-best/claude-code / QuickOpenDialog

Function QuickOpenDialog

src/components/QuickOpenDialog.tsx:28–165  ·  view source on GitHub ↗
({ onDone, onInsert }: Props)

Source from the content-addressed store, hash-verified

26 * Fuzzy file finder with a syntax-highlighted preview of the focused file.
27 */
28export function QuickOpenDialog({ onDone, onInsert }: Props): React.ReactNode {
29 useRegisterOverlay('quick-open');
30 const { columns, rows } = useTerminalSize();
31 // Chrome (title + search + hints + pane border + gaps) eats ~14 rows.
32 // Shrink the list on short terminals so the dialog doesn't clip.
33 const visibleResults = Math.min(VISIBLE_RESULTS, Math.max(4, rows - 14));
34
35 const [results, setResults] = useState<string[]>([]);
36 const [query, setQuery] = useState('');
37 const [focusedPath, setFocusedPath] = useState<string | undefined>(undefined);
38 const [preview, setPreview] = useState<{
39 path: string;
40 content: string;
41 } | null>(null);
42 const queryGenRef = useRef(0);
43 useEffect(() => () => void queryGenRef.current++, []);
44
45 const previewOnRight = columns >= 120;
46 // Side preview sits in a fixed-height row alongside the list (visibleCount
47 // rows), so overflowing that height garbles the layout — cap to fit, minus
48 // one for the path header line.
49 const effectivePreviewLines = previewOnRight ? VISIBLE_RESULTS - 1 : PREVIEW_LINES;
50
51 // A generation counter invalidates stale results if the user types faster
52 // than the index can respond.
53 const handleQueryChange = (q: string) => {
54 setQuery(q);
55 const gen = ++queryGenRef.current;
56 if (!q.trim()) {
57 // generateFileSuggestions('') returns raw readdir() of cwd (designed for
58 // @-mentions). For Quick Open that's just noise — show the empty state.
59 setResults([]);
60 return;
61 }
62 void generateFileSuggestions(q, true).then(items => {
63 if (gen !== queryGenRef.current) return;
64 // Filter out directory entries — they come back with a trailing path.sep
65 // from getTopLevelPaths() and would cause readFileInRange to throw EISDIR,
66 // leaving the preview pane stuck on "Loading preview…".
67 // Normalize separators to '/' so truncatePathMiddle (which uses
68 // lastIndexOf('/')) can find the filename on Windows too.
69 const paths = items
70 .filter(i => i.id.startsWith('file-'))
71 .map(i => i.displayText)
72 .filter(p => !p.endsWith(path.sep))
73 .map(p => p.split(path.sep).join('/'));
74 setResults(paths);
75 });
76 };
77
78 // Load a short preview of the focused file. Each navigation aborts the
79 // previous read so holding ↓ doesn't pile up whole-file reads and so a
80 // slow early read can't overwrite a faster later one. The stale preview
81 // stays visible until the new one arrives — renderPreview overlays a dim
82 // loading indicator rather than blanking the pane.
83 useEffect(() => {
84 if (!focusedPath) {
85 // No results — clear so the empty-state renders instead of a stale

Callers

nothing calls this directly

Calls 11

useRegisterOverlayFunction · 0.85
useTerminalSizeFunction · 0.85
getCwdFunction · 0.85
readFileInRangeFunction · 0.85
truncatePathMiddleFunction · 0.85
highlightMatchFunction · 0.85
truncateToWidthFunction · 0.85
maxMethod · 0.80
handleInsertFunction · 0.70
abortMethod · 0.65
resolveMethod · 0.45

Tested by

no test coverage detected