Skip to content

Commit 285e245

Browse files
authored
Merge pull request #161 from hqwlkj/main
feat(ui): 优化 PromptInput 组件的光标显示与布局
2 parents 7799f52 + 6710512 commit 285e245

1 file changed

Lines changed: 28 additions & 11 deletions

File tree

src/ui/views/PromptInput.tsx

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,13 @@ import {
4343
} from "../core/file-mentions";
4444
import type { FileMentionItem } from "../core/file-mentions";
4545
import { readClipboardImageAsync } from "../core/clipboard";
46-
import { useTerminalInput, usePasteHandling, useHistoryNavigation } from "../hooks";
46+
import {
47+
useTerminalInput,
48+
usePasteHandling,
49+
useHistoryNavigation,
50+
getPromptCursorPlacement,
51+
usePromptTerminalCursor,
52+
} from "../hooks";
4753
import type { InputKey } from "../hooks";
4854
import {
4955
useHiddenTerminalCursor,
@@ -108,7 +114,11 @@ const PromptPrefixLine = React.memo(function PromptPrefixLine({ busy }: { busy:
108114
}, [busy]);
109115

110116
const prefix = busy ? `${SPINNER_FRAMES[spinnerIndex]} ` : "> ";
111-
return <Text color={busy ? "yellow" : "#229ac3"}>{prefix}</Text>;
117+
return (
118+
<Box width={2}>
119+
<Text color={busy ? "yellow" : "#229ac3"}>{prefix}</Text>
120+
</Box>
121+
);
112122
});
113123

114124
export const PromptInput = React.memo(function PromptInput({
@@ -202,9 +212,17 @@ export const PromptInput = React.memo(function PromptInput({
202212
() => showMenu || showSkillsDropdown || openRawModelDropdown || showModelDropdown || showFileMentionMenu,
203213
[showMenu, showSkillsDropdown, showModelDropdown, openRawModelDropdown, showFileMentionMenu]
204214
);
205-
// The prompt draws its own inverse-video cursor inside the text. Keep the
206-
// native terminal cursor hidden so wrapping edges do not show two cursors.
207-
const hideNativeCursor = !disabled;
215+
216+
const cursorPlacement = useMemo(
217+
() => getPromptCursorPlacement(buffer, screenWidth, 2, footerText),
218+
[buffer, footerText, screenWidth]
219+
);
220+
const usePositionedCursor = !disabled && hasTerminalFocus && !showFooterText;
221+
useTerminalFocusReporting(stdout, !disabled);
222+
useTerminalExtendedKeys(stdout, !disabled);
223+
useBracketedPaste(stdout, !disabled);
224+
usePromptTerminalCursor(stdout, cursorPlacement, usePositionedCursor);
225+
useHiddenTerminalCursor(stdout, !disabled && !usePositionedCursor);
208226

209227
const refreshFileMentionItems = React.useCallback(() => {
210228
setFileMentionItems(scanFileMentionItems(projectRoot));
@@ -560,10 +578,6 @@ export const PromptInput = React.memo(function PromptInput({
560578
},
561579
{ isActive: !disabled }
562580
);
563-
useTerminalFocusReporting(stdout, !disabled);
564-
useTerminalExtendedKeys(stdout, !disabled);
565-
useBracketedPaste(stdout, !disabled);
566-
useHiddenTerminalCursor(stdout, hideNativeCursor);
567581

568582
function undo(): void {
569583
const previous = undoPromptEdit(undoRedoRef.current, buffer);
@@ -742,6 +756,7 @@ export const PromptInput = React.memo(function PromptInput({
742756
) : null}
743757
{/* Input */}
744758
<Box
759+
width={screenWidth}
745760
borderStyle="single"
746761
borderTop={true}
747762
borderBottom={true}
@@ -750,8 +765,10 @@ export const PromptInput = React.memo(function PromptInput({
750765
borderDimColor
751766
>
752767
<PromptPrefixLine busy={busy} />
753-
<Text>{renderBufferWithCursor(buffer, !disabled && hasTerminalFocus, placeholder, pastesRef.current)}</Text>
754-
{inlineHint ? <Text dimColor>{inlineHint}</Text> : null}
768+
<Box flexGrow={1} flexShrink={1} width={screenWidth - 2}>
769+
<Text>{renderBufferWithCursor(buffer, !disabled && hasTerminalFocus, placeholder, pastesRef.current)}</Text>
770+
{inlineHint ? <Text dimColor>{inlineHint}</Text> : null}
771+
</Box>
755772
</Box>
756773
<RawModelDropdown
757774
open={openRawModelDropdown}

0 commit comments

Comments
 (0)