Skip to content

Commit 9609d26

Browse files
committed
feat: replace useEffect with useLayoutEffect for better performance in useTerminalInput and PromptInput components
1 parent cdee210 commit 9609d26

2 files changed

Lines changed: 10 additions & 15 deletions

File tree

src/ui/hooks/useTerminalInput.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useRef } from "react";
1+
import { useLayoutEffect, useRef } from "react";
22
import { useStdin } from "ink";
33

44
export type InputKey = {
@@ -249,7 +249,7 @@ export function useTerminalInput(
249249
// O(n²) copying when the terminal splits a large paste across many events.
250250
const pasteRef = useRef({ active: false, chunks: [] as string[] });
251251

252-
useEffect(() => {
252+
useLayoutEffect(() => {
253253
if (!isActive) {
254254
pasteRef.current.active = false;
255255
pasteRef.current.chunks = [];
@@ -261,7 +261,7 @@ export function useTerminalInput(
261261
};
262262
}, [isActive, setRawMode]);
263263

264-
useEffect(() => {
264+
useLayoutEffect(() => {
265265
if (!isActive) {
266266
return;
267267
}

src/ui/views/PromptInput.tsx

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,9 @@ import { readClipboardImageAsync } from "../core/clipboard";
4646
import { useTerminalInput, usePasteHandling, useHistoryNavigation } from "../hooks";
4747
import type { InputKey } from "../hooks";
4848
import {
49-
getPromptCursorPlacement,
5049
useHiddenTerminalCursor,
5150
useTerminalExtendedKeys,
5251
useBracketedPaste,
53-
usePromptTerminalCursor,
5452
useTerminalFocusReporting,
5553
} from "../hooks";
5654
import SlashCommandMenu, { isSkillSelected } from "./SlashCommandMenu";
@@ -204,16 +202,9 @@ export const PromptInput = React.memo(function PromptInput({
204202
() => showMenu || showSkillsDropdown || openRawModelDropdown || showModelDropdown || showFileMentionMenu,
205203
[showMenu, showSkillsDropdown, showModelDropdown, openRawModelDropdown, showFileMentionMenu]
206204
);
207-
const cursorPlacement = useMemo(
208-
() => getPromptCursorPlacement(buffer, screenWidth, 2, footerText),
209-
[buffer, footerText, screenWidth]
210-
);
211-
const usePositionedCursor = !disabled && hasTerminalFocus && !showFooterText;
212-
useTerminalFocusReporting(stdout, !disabled);
213-
useTerminalExtendedKeys(stdout, !disabled);
214-
useBracketedPaste(stdout, !disabled);
215-
usePromptTerminalCursor(stdout, cursorPlacement, usePositionedCursor);
216-
useHiddenTerminalCursor(stdout, !disabled && !usePositionedCursor);
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;
217208

218209
const refreshFileMentionItems = React.useCallback(() => {
219210
setFileMentionItems(scanFileMentionItems(projectRoot));
@@ -569,6 +560,10 @@ export const PromptInput = React.memo(function PromptInput({
569560
},
570561
{ isActive: !disabled }
571562
);
563+
useTerminalFocusReporting(stdout, !disabled);
564+
useTerminalExtendedKeys(stdout, !disabled);
565+
useBracketedPaste(stdout, !disabled);
566+
useHiddenTerminalCursor(stdout, hideNativeCursor);
572567

573568
function undo(): void {
574569
const previous = undoPromptEdit(undoRedoRef.current, buffer);

0 commit comments

Comments
 (0)