in codex-cli/src/components/history-overlay.tsx [13:99]
export default function HistoryOverlay({ items, onExit }: Props): JSX.Element {
const [mode, setMode] = useState<Mode>("commands");
const [cursor, setCursor] = useState(0);
const { commands, files } = useMemo(
() => formatHistoryForDisplay(items),
[items],
);
const list = mode === "commands" ? commands : files;
useInput((input, key) => {
if (key.escape) {
onExit();
return;
}
if (input === "c") {
setMode("commands");
setCursor(0);
return;
}
if (input === "f") {
setMode("files");
setCursor(0);
return;
}
if (key.downArrow || input === "j") {
setCursor((c) => Math.min(list.length - 1, c + 1));
} else if (key.upArrow || input === "k") {
setCursor((c) => Math.max(0, c - 1));
} else if (key.pageDown) {
setCursor((c) => Math.min(list.length - 1, c + 10));
} else if (key.pageUp) {
setCursor((c) => Math.max(0, c - 10));
} else if (input === "g") {
setCursor(0);
} else if (input === "G") {
setCursor(list.length - 1);
}
});
const rows = process.stdout.rows || 24;
const headerRows = 2;
const footerRows = 1;
const maxVisible = Math.max(4, rows - headerRows - footerRows);
const firstVisible = Math.min(
Math.max(0, cursor - Math.floor(maxVisible / 2)),
Math.max(0, list.length - maxVisible),
);
const visible = list.slice(firstVisible, firstVisible + maxVisible);
return (
<Box
flexDirection="column"
borderStyle="round"
borderColor="gray"
width={100}
>
<Box paddingX={1}>
<Text bold>
{mode === "commands" ? "Commands run" : "Files touched"} (
{list.length})
</Text>
</Box>
<Box flexDirection="column" paddingX={1}>
{visible.map((txt, idx) => {
const absIdx = firstVisible + idx;
const selected = absIdx === cursor;
return (
<Text key={absIdx} color={selected ? "cyan" : undefined}>
{selected ? "› " : " "}
{txt}
</Text>
);
})}
</Box>
<Box paddingX={1}>
<Text dimColor>
esc Close ↑↓ Scroll PgUp/PgDn g/G First/Last c Commands f Files
</Text>
</Box>
</Box>
);
}