Skip to content

Commit 3ed04b3

Browse files
authored
fix cursor movement in chat input (#64)
1 parent 243436d commit 3ed04b3

File tree

4 files changed

+43
-9
lines changed

4 files changed

+43
-9
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@vibe-kit/grok-cli",
3-
"version": "0.0.19",
3+
"version": "0.0.20",
44
"description": "An open-source AI agent that brings the power of Grok directly into your terminal.",
55
"main": "dist/index.js",
66
"bin": {

src/hooks/use-input-handler.ts

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export function useInputHandler({
4343
isConfirmationActive = false,
4444
}: UseInputHandlerProps) {
4545
const [input, setInput] = useState("");
46+
const [cursorPosition, setCursorPosition] = useState(0);
4647
const [showCommandSuggestions, setShowCommandSuggestions] = useState(false);
4748
const [selectedCommandIndex, setSelectedCommandIndex] = useState(0);
4849
const [showModelSelection, setShowModelSelection] = useState(false);
@@ -86,6 +87,7 @@ export function useInputHandler({
8687
confirmationService.resetSession();
8788

8889
setInput("");
90+
setCursorPosition(0);
8991
return true;
9092
}
9193

@@ -127,6 +129,7 @@ Examples:
127129
};
128130
setChatHistory((prev) => [...prev, helpEntry]);
129131
setInput("");
132+
setCursorPosition(0);
130133
return true;
131134
}
132135

@@ -139,6 +142,7 @@ Examples:
139142
setShowModelSelection(true);
140143
setSelectedModelIndex(0);
141144
setInput("");
145+
setCursorPosition(0);
142146
return true;
143147
}
144148

@@ -167,6 +171,7 @@ Available models: ${modelNames.join(", ")}`,
167171
}
168172

169173
setInput("");
174+
setCursorPosition(0);
170175
return true;
171176
}
172177

@@ -371,6 +376,7 @@ Respond with ONLY the commit message, no additional text.`;
371376
setIsProcessing(false);
372377
setIsStreaming(false);
373378
setInput("");
379+
setCursorPosition(0);
374380
return true;
375381
}
376382

@@ -428,6 +434,7 @@ Respond with ONLY the commit message, no additional text.`;
428434
}
429435

430436
setInput("");
437+
setCursorPosition(0);
431438
return true;
432439
}
433440

@@ -444,6 +451,7 @@ Respond with ONLY the commit message, no additional text.`;
444451

445452
setIsProcessing(true);
446453
setInput("");
454+
setCursorPosition(0);
447455

448456
try {
449457
setIsStreaming(true);
@@ -642,7 +650,9 @@ Respond with ONLY the commit message, no additional text.`;
642650
filteredSuggestions.length - 1
643651
);
644652
const selectedCommand = filteredSuggestions[safeIndex];
645-
setInput(selectedCommand.command + " ");
653+
const newInput = selectedCommand.command + " ";
654+
setInput(newInput);
655+
setCursorPosition(newInput.length);
646656
setShowCommandSuggestions(false);
647657
setSelectedCommandIndex(0);
648658
return;
@@ -693,20 +703,35 @@ Respond with ONLY the commit message, no additional text.`;
693703
return;
694704
}
695705

706+
// Handle left and right arrow keys for cursor movement
707+
if (key.leftArrow && !showCommandSuggestions && !showModelSelection) {
708+
setCursorPosition(prev => Math.max(0, prev - 1));
709+
return;
710+
}
711+
712+
if (key.rightArrow && !showCommandSuggestions && !showModelSelection) {
713+
setCursorPosition(prev => Math.min(input.length, prev + 1));
714+
return;
715+
}
716+
696717
if (key.backspace || key.delete) {
697-
const newInput = input.slice(0, -1);
698-
setInput(newInput);
718+
if (cursorPosition > 0) {
719+
const newInput = input.slice(0, cursorPosition - 1) + input.slice(cursorPosition);
720+
setInput(newInput);
721+
setCursorPosition(prev => prev - 1);
699722

700-
if (!newInput.startsWith("/")) {
701-
setShowCommandSuggestions(false);
702-
setSelectedCommandIndex(0);
723+
if (!newInput.startsWith("/")) {
724+
setShowCommandSuggestions(false);
725+
setSelectedCommandIndex(0);
726+
}
703727
}
704728
return;
705729
}
706730

707731
if (inputChar && !key.ctrl && !key.meta) {
708-
const newInput = input + inputChar;
732+
const newInput = input.slice(0, cursorPosition) + inputChar + input.slice(cursorPosition);
709733
setInput(newInput);
734+
setCursorPosition(prev => prev + 1);
710735

711736
if (newInput.startsWith("/")) {
712737
setShowCommandSuggestions(true);
@@ -720,6 +745,7 @@ Respond with ONLY the commit message, no additional text.`;
720745

721746
return {
722747
input,
748+
cursorPosition,
723749
showCommandSuggestions,
724750
selectedCommandIndex,
725751
showModelSelection,

src/ui/components/chat-input.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,27 @@ import { Box, Text } from "ink";
33

44
interface ChatInputProps {
55
input: string;
6+
cursorPosition: number;
67
isProcessing: boolean;
78
isStreaming: boolean;
89
}
910

1011
export function ChatInput({
1112
input,
13+
cursorPosition,
1214
isProcessing,
1315
isStreaming,
1416
}: ChatInputProps) {
17+
const beforeCursor = input.slice(0, cursorPosition);
18+
const afterCursor = input.slice(cursorPosition);
19+
1520
return (
1621
<Box borderStyle="round" borderColor="gray" paddingX={1} marginTop={1}>
1722
<Text color="gray"></Text>
1823
<Text>
19-
{input}
24+
{beforeCursor}
2025
{!isProcessing && !isStreaming && <Text color="white"></Text>}
26+
{afterCursor}
2127
</Text>
2228
</Box>
2329
);

src/ui/components/chat-interface.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ function ChatInterfaceWithAgent({ agent }: { agent: GrokAgent }) {
3636

3737
const {
3838
input,
39+
cursorPosition,
3940
showCommandSuggestions,
4041
selectedCommandIndex,
4142
showModelSelection,
@@ -210,6 +211,7 @@ function ChatInterfaceWithAgent({ agent }: { agent: GrokAgent }) {
210211

211212
<ChatInput
212213
input={input}
214+
cursorPosition={cursorPosition}
213215
isProcessing={isProcessing}
214216
isStreaming={isStreaming}
215217
/>

0 commit comments

Comments
 (0)