-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAutocomplete.tsx
More file actions
106 lines (94 loc) · 2.72 KB
/
Autocomplete.tsx
File metadata and controls
106 lines (94 loc) · 2.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import { TextInput } from '@inkjs/ui';
import { Box, Text, useInput } from 'ink';
import { useCallback, useState } from 'react';
import { type Command, COMMANDS, UI } from '../constants';
interface Props {
isDisabled?: boolean;
onSubmit: (value: string) => void;
}
function getMatches(input: string): Command[] {
if (!input.startsWith('/')) {
return [];
}
return COMMANDS.filter((command) => command.name.startsWith(input));
}
export function Autocomplete({ isDisabled = false, onSubmit }: Props) {
const [value, setValue] = useState('');
const [selectedIndex, setSelectedIndex] = useState(0);
const [inputKey, setInputKey] = useState(0);
const matches = getMatches(value);
const isCommandMode = value.startsWith('/');
useInput(
(_char, key) => {
// v8 ignore next
if (!isCommandMode) {
return;
}
if (key.upArrow) {
setSelectedIndex((i) => Math.max(0, i - 1));
return;
}
if (key.downArrow) {
setSelectedIndex((i) => Math.min(matches.length - 1, i + 1));
return;
}
if (key.tab && matches.length > 0) {
// v8 ignore next
const match = matches[selectedIndex] ?? matches[0];
setValue(match.name);
setSelectedIndex(0);
setInputKey((key) => key + 1);
return;
}
},
{ isActive: !isDisabled && isCommandMode },
);
const handleSubmit = useCallback(
(input: string) => {
const submitValue =
isCommandMode && matches.length > 0 && matches[selectedIndex]
? matches[selectedIndex].name
: input;
const trimmed = submitValue.trim();
if (trimmed) {
onSubmit(trimmed);
setValue('');
setSelectedIndex(0);
setInputKey((key) => key + 1);
}
},
[isCommandMode, matches, onSubmit, selectedIndex],
);
return (
<Box flexDirection="column">
<Box>
<Text>{UI.PROMPT_PREFIX}</Text>
<TextInput
key={inputKey}
isDisabled={isDisabled}
defaultValue={value}
onChange={setValue}
onSubmit={handleSubmit}
/>
</Box>
{isCommandMode && matches.length > 0 && (
<Box flexDirection="column" marginLeft={2}>
{matches.map((command, index) => {
const isHighlighted = index === selectedIndex;
return (
<Box key={command.name} gap={3}>
<Text
color={isHighlighted ? 'cyan' : undefined}
bold={isHighlighted}
>
{command.name}
</Text>
<Text dimColor>{command.description}</Text>
</Box>
);
})}
</Box>
)}
</Box>
);
}