claude-code/components/QuickOpenDialog.tsx

244 lines
28 KiB
TypeScript
Raw Permalink Normal View History

import { c as _c } from "react/compiler-runtime";
import * as path from 'path';
import * as React from 'react';
import { useEffect, useRef, useState } from 'react';
import { useRegisterOverlay } from '../context/overlayContext.js';
import { generateFileSuggestions } from '../hooks/fileSuggestions.js';
import { useTerminalSize } from '../hooks/useTerminalSize.js';
import { Text } from '../ink.js';
import { logEvent } from '../services/analytics/index.js';
import { getCwd } from '../utils/cwd.js';
import { openFileInExternalEditor } from '../utils/editor.js';
import { truncatePathMiddle, truncateToWidth } from '../utils/format.js';
import { highlightMatch } from '../utils/highlightMatch.js';
import { readFileInRange } from '../utils/readFileInRange.js';
import { FuzzyPicker } from './design-system/FuzzyPicker.js';
import { LoadingState } from './design-system/LoadingState.js';
type Props = {
onDone: () => void;
onInsert: (text: string) => void;
};
const VISIBLE_RESULTS = 8;
const PREVIEW_LINES = 20;
/**
* Quick Open dialog (ctrl+shift+p / cmd+shift+p).
* Fuzzy file finder with a syntax-highlighted preview of the focused file.
*/
export function QuickOpenDialog(t0) {
const $ = _c(35);
const {
onDone,
onInsert
} = t0;
useRegisterOverlay("quick-open");
const {
columns,
rows
} = useTerminalSize();
const visibleResults = Math.min(VISIBLE_RESULTS, Math.max(4, rows - 14));
let t1;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t1 = [];
$[0] = t1;
} else {
t1 = $[0];
}
const [results, setResults] = useState(t1);
const [query, setQuery] = useState("");
const [focusedPath, setFocusedPath] = useState(undefined);
const [preview, setPreview] = useState(null);
const queryGenRef = useRef(0);
let t2;
let t3;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
t2 = () => () => {
queryGenRef.current = queryGenRef.current + 1;
return void queryGenRef.current;
};
t3 = [];
$[1] = t2;
$[2] = t3;
} else {
t2 = $[1];
t3 = $[2];
}
useEffect(t2, t3);
const previewOnRight = columns >= 120;
const effectivePreviewLines = previewOnRight ? VISIBLE_RESULTS - 1 : PREVIEW_LINES;
let t4;
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
t4 = q => {
setQuery(q);
const gen = queryGenRef.current = queryGenRef.current + 1;
if (!q.trim()) {
setResults([]);
return;
}
generateFileSuggestions(q, true).then(items => {
if (gen !== queryGenRef.current) {
return;
}
const paths = items.filter(_temp).map(_temp2).filter(_temp3).map(_temp4);
setResults(paths);
});
};
$[3] = t4;
} else {
t4 = $[3];
}
const handleQueryChange = t4;
let t5;
let t6;
if ($[4] !== effectivePreviewLines || $[5] !== focusedPath) {
t5 = () => {
if (!focusedPath) {
setPreview(null);
return;
}
const controller = new AbortController();
const absolute = path.resolve(getCwd(), focusedPath);
readFileInRange(absolute, 0, effectivePreviewLines, undefined, controller.signal).then(r => {
if (controller.signal.aborted) {
return;
}
setPreview({
path: focusedPath,
content: r.content
});
}).catch(() => {
if (controller.signal.aborted) {
return;
}
setPreview({
path: focusedPath,
content: "(preview unavailable)"
});
});
return () => controller.abort();
};
t6 = [focusedPath, effectivePreviewLines];
$[4] = effectivePreviewLines;
$[5] = focusedPath;
$[6] = t5;
$[7] = t6;
} else {
t5 = $[6];
t6 = $[7];
}
useEffect(t5, t6);
const maxPathWidth = previewOnRight ? Math.max(20, Math.floor((columns - 10) * 0.4)) : Math.max(20, columns - 8);
const previewWidth = previewOnRight ? Math.max(40, columns - maxPathWidth - 14) : columns - 6;
let t7;
if ($[8] !== onDone || $[9] !== results.length) {
t7 = p_1 => {
const opened = openFileInExternalEditor(path.resolve(getCwd(), p_1));
logEvent("tengu_quick_open_select", {
result_count: results.length,
opened_editor: opened
});
onDone();
};
$[8] = onDone;
$[9] = results.length;
$[10] = t7;
} else {
t7 = $[10];
}
const handleOpen = t7;
let t8;
if ($[11] !== onDone || $[12] !== onInsert || $[13] !== results.length) {
t8 = (p_2, mention) => {
onInsert(mention ? `@${p_2} ` : `${p_2} `);
logEvent("tengu_quick_open_insert", {
result_count: results.length,
mention
});
onDone();
};
$[11] = onDone;
$[12] = onInsert;
$[13] = results.length;
$[14] = t8;
} else {
t8 = $[14];
}
const handleInsert = t8;
const t9 = previewOnRight ? "right" : "bottom";
let t10;
if ($[15] !== handleInsert) {
t10 = {
action: "mention",
handler: p_4 => handleInsert(p_4, true)
};
$[15] = handleInsert;
$[16] = t10;
} else {
t10 = $[16];
}
let t11;
if ($[17] !== handleInsert) {
t11 = {
action: "insert path",
handler: p_5 => handleInsert(p_5, false)
};
$[17] = handleInsert;
$[18] = t11;
} else {
t11 = $[18];
}
let t12;
if ($[19] !== maxPathWidth) {
t12 = (p_6, isFocused) => <Text color={isFocused ? "suggestion" : undefined}>{truncatePathMiddle(p_6, maxPathWidth)}</Text>;
$[19] = maxPathWidth;
$[20] = t12;
} else {
t12 = $[20];
}
let t13;
if ($[21] !== preview || $[22] !== previewWidth || $[23] !== query) {
t13 = p_7 => preview ? <><Text dimColor={true}>{truncatePathMiddle(p_7, previewWidth)}{preview.path !== p_7 ? " \xB7 loading\u2026" : ""}</Text>{preview.content.split("\n").map((line, i_1) => <Text key={i_1}>{highlightMatch(truncateToWidth(line, previewWidth), query)}</Text>)}</> : <LoadingState message={"Loading preview\u2026"} dimColor={true} />;
$[21] = preview;
$[22] = previewWidth;
$[23] = query;
$[24] = t13;
} else {
t13 = $[24];
}
let t14;
if ($[25] !== handleOpen || $[26] !== onDone || $[27] !== results || $[28] !== t10 || $[29] !== t11 || $[30] !== t12 || $[31] !== t13 || $[32] !== t9 || $[33] !== visibleResults) {
t14 = <FuzzyPicker title="Quick Open" placeholder={"Type to search files\u2026"} items={results} getKey={_temp5} visibleCount={visibleResults} direction="up" previewPosition={t9} onQueryChange={handleQueryChange} onFocus={setFocusedPath} onSelect={handleOpen} onTab={t10} onShiftTab={t11} onCancel={onDone} emptyMessage={_temp6} selectAction="open in editor" renderItem={t12} renderPreview={t13} />;
$[25] = handleOpen;
$[26] = onDone;
$[27] = results;
$[28] = t10;
$[29] = t11;
$[30] = t12;
$[31] = t13;
$[32] = t9;
$[33] = visibleResults;
$[34] = t14;
} else {
t14 = $[34];
}
return t14;
}
function _temp6(q_0) {
return q_0 ? "No matching files" : "Start typing to search\u2026";
}
function _temp5(p_3) {
return p_3;
}
function _temp4(p_0) {
return p_0.split(path.sep).join("/");
}
function _temp3(p) {
return !p.endsWith(path.sep);
}
function _temp2(i_0) {
return i_0.displayText;
}
function _temp(i) {
return i.id.startsWith("file-");
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJwYXRoIiwiUmVhY3QiLCJ1c2VFZmZlY3QiLCJ1c2VSZWYiLCJ1c2VTdGF0ZSIsInVzZVJlZ2lzdGVyT3ZlcmxheSIsImdlbmVyYXRlRmlsZVN1Z2dlc3Rpb25zIiwidXNlVGVybWluYWxTaXplIiwiVGV4dCIsImxvZ0V2ZW50IiwiZ2V0Q3dkIiwib3BlbkZpbGVJbkV4dGVybmFsRWRpdG9yIiwidHJ1bmNhdGVQYXRoTWlkZGxlIiwidHJ1bmNhdGVUb1dpZHRoIiwiaGlnaGxpZ2h0TWF0Y2giLCJyZWFkRmlsZUluUmFuZ2UiLCJGdXp6eVBpY2tlciIsIkxvYWRpbmdTdGF0ZSIsIlByb3BzIiwib25Eb25lIiwib25JbnNlcnQiLCJ0ZXh0IiwiVklTSUJMRV9SRVNVTFRTIiwiUFJFVklFV19MSU5FUyIsIlF1aWNrT3BlbkRpYWxvZyIsInQwIiwiJCIsIl9jIiwiY29sdW1ucyIsInJvd3MiLCJ2aXNpYmxlUmVzdWx0cyIsIk1hdGgiLCJtaW4iLCJtYXgiLCJ0MSIsIlN5bWJvbCIsImZvciIsInJlc3VsdHMiLCJzZXRSZXN1bHRzIiwicXVlcnkiLCJzZXRRdWVyeSIsImZvY3VzZWRQYXRoIiwic2V0Rm9jdXNlZFBhdGgiLCJ1bmRlZmluZWQiLCJwcmV2aWV3Iiwic2V0UHJldmlldyIsInF1ZXJ5R2VuUmVmIiwidDIiLCJ0MyIsImN1cnJlbnQiLCJwcmV2aWV3T25SaWdodCIsImVmZmVjdGl2ZVByZXZpZXdMaW5lcyIsInQ0IiwicSIsImdlbiIsInRyaW0iLCJ0aGVuIiwiaXRlbXMiLCJwYXRocyIsImZpbHRlciIsIl90ZW1wIiwibWFwIiwiX3RlbXAyIiwiX3RlbXAzIiwiX3RlbXA0IiwiaGFuZGxlUXVlcnlDaGFuZ2UiLCJ0NSIsInQ2IiwiY29udHJvbGxlciIsIkFib3J0Q29udHJvbGxlciIsImFic29sdXRlIiwicmVzb2x2ZSIsInNpZ25hbCIsInIiLCJhYm9ydGVkIiwiY29udGVudCIsImNhdGNoIiwiYWJvcnQiLCJtYXhQYXRoV2lkdGgiLCJmbG9vciIsInByZXZpZXdXaWR0aCIsInQ3IiwibGVuZ3RoIiwicF8xIiwib3BlbmVkIiwicCIsInJlc3VsdF9jb3VudCIsIm9wZW5lZF9lZGl0b3IiLCJoYW5kbGVPcGVuIiwidDgiLCJwXzIiLCJtZW50aW9uIiwiaGFuZGxlSW5zZXJ0IiwidDkiLCJ0MTAiLCJhY3Rpb24iLCJoYW5kbGVyIiwicF80IiwidDExIiwicF81IiwidDEyIiwicF82IiwiaXNGb2N1c2VkIiwidDEzIiwicF83Iiwic3BsaXQiLCJsaW5lIiwiaV8xIiwiaSIsInQxNCIsIl90ZW1wNSIsIl90ZW1wNiIsInFfMCIsInBfMyIsInBfMCIsInNlcCIsImpvaW4iLCJlbmRzV2l0aCIsImlfMCIsImRpc3BsYXlUZXh0IiwiaWQiLCJzdGFydHNXaXRoIl0sInNvdXJjZXMiOlsiUXVpY2tPcGVuRGlhbG9nLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnXG5pbXBvcnQgKiBhcyBSZWFjdCBmcm9tICdyZWFjdCdcbmltcG9ydCB7IHVzZUVmZmVjdCwgdXNlUmVmLCB1c2VTdGF0ZSB9IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgdXNlUmVnaXN0ZXJPdmVybGF5IH0gZnJvbSAnLi4vY29udGV4dC9vdmVybGF5Q29udGV4dC5qcydcbmltcG9ydCB7IGdlbmVyYXRlRmlsZVN1Z2dlc3Rpb25zIH0gZnJvbSAnLi4vaG9va3MvZmlsZVN1Z2dlc3Rpb25zLmpzJ1xuaW1wb3J0IHsgdXNlVGVybWluYWxTaXplIH0gZnJvbSAnLi4vaG9va3MvdXNlVGVybWluYWxTaXplLmpzJ1xuaW1wb3J0IHsgVGV4dCB9IGZyb20gJy4uL2luay5qcydcbmltcG9ydCB7IGxvZ0V2ZW50IH0gZnJvbSAnLi4vc2VydmljZXMvYW5hbHl0aWNzL2luZGV4LmpzJ1xuaW1wb3J0IHsgZ2V0Q3dkIH0gZnJvbSAnLi4vdXRpbHMvY3dkLmpzJ1xuaW1wb3J0IHsgb3BlbkZpbGVJbkV4dGVybmFsRWRpdG9yIH0gZnJvbSAnLi4vdXRpbHMvZWRpdG9yLmpzJ1xuaW1wb3J0IHsgdHJ1bmNhdGVQYXRoTWlkZGxlLCB0cnVuY2F0ZVRvV2lkdGggfSBmcm9tICcuLi91dGlscy9mb3JtYXQuanMnXG5pbXBvcnQgeyBoaWdobGlnaHRNYXRjaCB9IGZyb20gJy4uL3V0aWxzL2hpZ2hsaWdodE1hdGNoLmpzJ1xuaW1wb3J0IHsgcmVhZEZpbGVJblJhbmdlIH0gZnJvbSAnLi4vdXRpbHMvcmVhZEZpbGVJblJhbmdlLmpzJ1xuaW1wb3J0IHsgRnV6enlQaWNrZXIgfSBmcm9tICcuL2Rlc2lnbi1zeXN0ZW0vRnV6enlQaWNrZXIuanMnXG5pbXBvcnQgeyBMb2FkaW5nU3RhdGUgfSBmcm9tICcuL2Rlc2lnbi1zeXN0ZW0vTG9hZGluZ1N0YXRlLmpzJ1xuXG50eXBlIFByb3BzID0ge1xuICBvbkRvbmU6ICgpID0+IHZvaWRcbiAgb25JbnNlcnQ6ICh0ZXh0OiBzdHJpbmcpID0+IHZvaWRcbn1cblxuY29uc3QgVklTSUJMRV9SRVNVTFRTID0gOFxuY29uc3QgUFJFVklFV19MSU5FUyA9IDIwXG5cbi8qKlxuICogUXVpY2sgT3BlbiBkaWFsb2cgKGN0cmwrc2hpZnQrcCAvIGNtZCtzaGlmdCtwKS5cbiAqIEZ1enp5IGZpbGUgZmluZGVyIHdpdGggYSBzeW50YXgtaGlnaGxpZ2h0ZWQgcHJldmlldyBvZiB0aGUgZm9jdXNlZCBmaWxlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gUXVpY2tPcGVuRGlhbG9nKHsgb25Eb25lLCBvbkluc2VydCB9OiBQcm9wcyk6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gIHVzZVJlZ2lzdGVyT3ZlcmxheSgncXVpY2stb3BlbicpXG4gIGNvbnN0IHsgY29sdW1ucywgcm93cyB9ID0gdXNlVGVybWluYWxTaXplKClcbiAgLy8gQ2hyb21lICh0aXRsZSArIHNlYXJjaCArIGhpbnRzICsgcGFuZSBib3JkZXIgKyBnYXBzKSBlYXRzIH4xNCByb3dzLlxuICAvLyBTaHJpbmsgdGhlIGxpc3Qgb24gc2hvcnQgdGVybWluYWxzIHNvIHRoZSBkaWFsb2cgZG9lc24ndCBjbGlwLlxuICBjb25zdCB2aXNpYmxlUmVzdWx0cyA9IE1hdGgubWluKFZJU0lCTEVfUkVTVUxUUywgTWF0aC5tYXgoNCwgcm93cyAtIDE0KSlcblxuICBjb25zdCBbcmVzdWx0cywgc2V0UmVzdWx0c10gPSB1c2VTdGF0ZTxzdHJpbmdbXT4oW10pXG4gIGNvbnN0IFtxdWVyeSwgc2V0UXVlcnldID0gdXNlU3RhdGUoJycpXG4gIGNvbnN0IFtmb2N1c2VkUGF0aCwgc2V0Rm9jdXNlZFBhdGhdID0gdXNlU3RhdGU8c3RyaW5nIHwgdW5kZWZpbmVkPih1bmRlZmluZWQpXG4gIGNvbnN0IFtwcmV2aWV3LCBzZXRQcmV2aWV3XSA9IHVzZVN0YXRlPHtcbiAgICBwYXRoOiB