feat(tui): enhance autocomplete functionality and UI interactions

This commit is contained in:
asepharyana
2026-09-03 16:13:29 +07:00
parent 2100e7ab54
commit 008f737e1f
5 changed files with 111 additions and 25 deletions
+18 -17
View File
@@ -447,7 +447,7 @@ export function ZesdexApp(props: { state: AppStateRest; onQuit: () => void }): R
<TranscriptView state={state} width={width} />
</scrollbox>
{/* Autocomplete dropdown (shown above the input row) */}
{state.input.autocompleteVisible && <AutocompleteView state={state} width={width} />}
{state.input.autocompleteVisible && <AutocompleteView state={state} />}
{/* Live activity breadcrumb of the running turn */}
<ActivityBar state={state} running={running} />
<InputView state={state} width={width} />
@@ -572,32 +572,33 @@ function InputView(props: { state: AppStateRest; width: number }): ReactNode {
/* ── Autocomplete ─────────────────────────────────────────────────── */
function AutocompleteView(props: { state: AppStateRest; width: number }): ReactNode {
const { state, width } = props;
function AutocompleteView(props: { state: AppStateRest }): ReactNode {
const { state } = props;
const candidates = state.input.autocompleteCandidates;
const kind = state.input.autocompleteKind;
const title = kind === "command" ? "commands" : "files";
const selected = Math.min(state.input.autocompleteIdx, candidates.length - 1);
const visible = candidates.slice(0, 10);
// Render the whole panel as ONE multiline <text> — the OpenTUI box renders a
// single text node reliably, whereas sibling <text> children can overlap.
const body = [
` ${title}`,
...visible.map((c, i) =>
i === selected ? `▸ ${c}` : ` ${c}`,
),
` ↑/↓ navigate · Tab accept · Esc close`,
].join("\n");
return (
<box
width="100%"
style={{
border: true,
borderColor: C.border,
backgroundColor: C.surface,
padding: 1,
}}
flexDirection="column"
flexGrow={1}
flexShrink={0}
style={{ border: true, borderColor: C.border, backgroundColor: C.surface, padding: 1 }}
>
<text fg={C.magenta}>
<b>{` ${title}`}</b>
<text fg={kind === "command" ? C.accent : C.magenta}>
{body}
</text>
{visible.map((c, i) => (
<text key={c} fg={i === selected ? C.accent : C.fg}>
{i === selected ? `${"▸ "}${c}${" ".repeat(Math.max(0, width - c.length - 4))}` : ` ${c}`}
</text>
))}
<text fg={C.dim}>{` ↑/↓ navigate · Tab accept · Esc close`}</text>
</box>
);
}