0
0
Fork 0

tui(browser): r re-scans mcp-mirror/

r calls onRescan() which re-walks the project root and rerenders the
Browser with the new tree. Optional prop so tests don't have to wire
it.
This commit is contained in:
Karstein Phobic Nyvold Kvistad 2026-04-28 23:17:34 +02:00
parent 2d73d005ef
commit 4d7cbdb6f6
3 changed files with 39 additions and 2 deletions

View file

@ -10,6 +10,7 @@ export interface BrowserProps {
readPou: (pou: POU) => Promise<string>;
writeSelection: (s: Selection) => void;
onQuit: () => void;
onRescan?: () => void;
}
interface FlatRow {
@ -31,7 +32,7 @@ function flatten(project: Project, expanded: Set<string>): FlatRow[] {
return rows;
}
export function Browser({ project, readPou, writeSelection, onQuit }: BrowserProps): React.ReactElement {
export function Browser({ project, readPou, writeSelection, onQuit, onRescan }: BrowserProps): React.ReactElement {
const [expanded, setExpanded] = React.useState<Set<string>>(new Set());
const [cursorIdx, setCursorIdx] = React.useState(0);
const [text, setText] = React.useState<string | null>(null);
@ -73,6 +74,7 @@ export function Browser({ project, readPou, writeSelection, onQuit }: BrowserPro
return;
}
if (input === 'q') return onQuit();
if (input === 'r' && onRescan) return onRescan();
if (input === 'j' || key.downArrow) {
setCursorIdx((i) => Math.min(i + 1, rows.length - 1));
} else if (input === 'k' || key.upArrow) {
@ -116,7 +118,7 @@ export function Browser({ project, readPou, writeSelection, onQuit }: BrowserPro
<Viewer pou={cursor?.pou ?? null} text={text} scrollTop={scrollTop} visibleRows={20} />
</Box>
</Box>
<Text>j/k nav l expand h collapse ? help q quit</Text>
<Text>j/k nav l expand h collapse r rescan ? help q quit</Text>
</Box>
);
}
@ -129,6 +131,7 @@ function HelpOverlay(): React.ReactElement {
<Text> k / move cursor up</Text>
<Text> l / expand device</Text>
<Text> h / collapse device</Text>
<Text> r re-scan mcp-mirror/</Text>
<Text> ? toggle this help</Text>
<Text> Esc close help</Text>
<Text> q quit</Text>

View file

@ -51,12 +51,29 @@ async function runBrowser(maybeRoot: string | undefined): Promise<number> {
resolve(0);
};
const readPou = (pou: { absPath: string }) => fs.readFile(pou.absPath, 'utf8');
const onRescan = async () => {
try {
const next = await walk(root);
app.rerender(
<Browser
project={next}
readPou={readPou}
writeSelection={onWriteSelection}
onQuit={onQuit}
onRescan={onRescan}
/>
);
} catch (err) {
process.stderr.write(`phobiCS-tui: rescan failed: ${(err as Error).message}\n`);
}
};
const app = render(
<Browser
project={project!}
readPou={readPou}
writeSelection={onWriteSelection}
onQuit={onQuit}
onRescan={onRescan}
/>
);
});

View file

@ -99,6 +99,23 @@ describe('<Browser>', () => {
expect(lastFrame()).not.toContain('Keybindings');
});
it('calls onRescan on r', async () => {
const onRescan = vi.fn();
const { stdin } = render(
<Browser
project={project}
readPou={async () => ''}
writeSelection={() => {}}
onQuit={() => {}}
onRescan={onRescan}
/>
);
await flush();
stdin.write('r');
await flush();
expect(onRescan).toHaveBeenCalled();
});
it('closes the help overlay on Esc', async () => {
const { stdin, lastFrame } = render(
<Browser