Hide caret when the command is not executing

This commit is contained in:
Saoud Rizwan
2024-09-02 00:38:26 -04:00
parent 3a37421ffd
commit 492ffeb5b1
3 changed files with 25 additions and 8 deletions

View File

@@ -1277,7 +1277,7 @@ export class ClaudeDev {
// } // }
} catch (e) { } catch (e) {
if ((e as ExecaError).signal === "SIGINT") { if ((e as ExecaError).signal === "SIGINT") {
await this.say("command_output", `\nUser exited command...`) //await this.say("command_output", `\nUser exited command...`)
result += `\n====\nUser terminated command process via SIGINT. This is not an error. Please continue with your task, but keep in mind that the command is no longer running. For example, if this command was used to start a server for a react app, the server is no longer running and you cannot open a browser to view it anymore.` result += `\n====\nUser terminated command process via SIGINT. This is not an error. Please continue with your task, but keep in mind that the command is no longer running. For example, if this command was used to start a server for a react app, the server is no longer running and you cannot open a browser to view it anymore.`
} else { } else {
throw e // if the command was not terminated by user, let outer catch handle it as a real error throw e // if the command was not terminated by user, let outer catch handle it as a real error

View File

@@ -425,6 +425,7 @@ const ChatRow: React.FC<ChatRowProps> = ({
<Terminal <Terminal
output={command + (output ? "\n" + output : "")} output={command + (output ? "\n" + output : "")}
handleSendStdin={handleSendStdin} handleSendStdin={handleSendStdin}
shouldAllowInput={!!isCommandExecuting && output.length > 0}
/> />
</> </>
) )

View File

@@ -3,6 +3,7 @@ import DynamicTextArea from "react-textarea-autosize"
interface TerminalProps { interface TerminalProps {
output: string output: string
shouldAllowInput: boolean
handleSendStdin: (text: string) => void handleSendStdin: (text: string) => void
} }
@@ -10,7 +11,7 @@ interface TerminalProps {
Inspired by https://phuoc.ng/collection/mirror-a-text-area/create-your-own-custom-cursor-in-a-text-area/ Inspired by https://phuoc.ng/collection/mirror-a-text-area/create-your-own-custom-cursor-in-a-text-area/
*/ */
const Terminal: React.FC<TerminalProps> = ({ output, handleSendStdin }) => { const Terminal: React.FC<TerminalProps> = ({ output, shouldAllowInput, handleSendStdin }) => {
const [userInput, setUserInput] = useState("") const [userInput, setUserInput] = useState("")
const [isFocused, setIsFocused] = useState(false) // Initially not focused const [isFocused, setIsFocused] = useState(false) // Initially not focused
const textAreaRef = useRef<HTMLTextAreaElement>(null) const textAreaRef = useRef<HTMLTextAreaElement>(null)
@@ -26,6 +27,7 @@ const Terminal: React.FC<TerminalProps> = ({ output, handleSendStdin }) => {
}, [output, lastProcessedOutput]) }, [output, lastProcessedOutput])
const handleKeyPress = (e: React.KeyboardEvent<HTMLTextAreaElement>) => { const handleKeyPress = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (!shouldAllowInput) return
if (e.key === "Enter") { if (e.key === "Enter") {
e.preventDefault() e.preventDefault()
handleSendStdin(userInput) handleSendStdin(userInput)
@@ -128,9 +130,12 @@ const Terminal: React.FC<TerminalProps> = ({ output, handleSendStdin }) => {
const caretEle = document.createElement("span") const caretEle = document.createElement("span")
caretEle.classList.add("terminal-cursor") caretEle.classList.add("terminal-cursor")
if (isFocused) { if (isFocused && shouldAllowInput) {
caretEle.classList.add("terminal-cursor-focused") caretEle.classList.add("terminal-cursor-focused")
} }
if (!shouldAllowInput) {
caretEle.classList.add("terminal-cursor-hidden")
}
caretEle.innerHTML = "&nbsp;" caretEle.innerHTML = "&nbsp;"
mirror.appendChild(caretEle) mirror.appendChild(caretEle)
@@ -142,7 +147,7 @@ const Terminal: React.FC<TerminalProps> = ({ output, handleSendStdin }) => {
document.addEventListener("selectionchange", updateMirror) document.addEventListener("selectionchange", updateMirror)
return () => document.removeEventListener("selectionchange", updateMirror) return () => document.removeEventListener("selectionchange", updateMirror)
}, [userInput, isFocused]) }, [userInput, isFocused, shouldAllowInput])
useEffect(() => { useEffect(() => {
// Position the dummy caret at the end of the text on initial render // Position the dummy caret at the end of the text on initial render
@@ -154,15 +159,19 @@ const Terminal: React.FC<TerminalProps> = ({ output, handleSendStdin }) => {
const caretEle = document.createElement("span") const caretEle = document.createElement("span")
caretEle.classList.add("terminal-cursor") caretEle.classList.add("terminal-cursor")
if (isFocused) { if (isFocused && shouldAllowInput) {
caretEle.classList.add("terminal-cursor-focused") caretEle.classList.add("terminal-cursor-focused")
} }
if (!shouldAllowInput) {
caretEle.classList.add("terminal-cursor-hidden")
}
caretEle.innerHTML = "&nbsp;" caretEle.innerHTML = "&nbsp;"
mirror.appendChild(caretEle) mirror.appendChild(caretEle)
} }
}, [output, userInput, isFocused]) }, [output, userInput, isFocused, shouldAllowInput])
const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => { const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
if (!shouldAllowInput) return
const newValue = e.target.value const newValue = e.target.value
if (newValue.startsWith(output)) { if (newValue.startsWith(output)) {
setUserInput(newValue.slice(output.length)) setUserInput(newValue.slice(output.length))
@@ -181,6 +190,7 @@ const Terminal: React.FC<TerminalProps> = ({ output, handleSendStdin }) => {
} }
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => { const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (!shouldAllowInput) return
const textarea = e.target as HTMLTextAreaElement const textarea = e.target as HTMLTextAreaElement
const cursorPosition = textarea.selectionStart const cursorPosition = textarea.selectionStart
@@ -260,11 +270,15 @@ const Terminal: React.FC<TerminalProps> = ({ output, handleSendStdin }) => {
.terminal-cursor-focused { .terminal-cursor-focused {
background-color: var(--vscode-terminalCursor-foreground); background-color: var(--vscode-terminalCursor-foreground);
} }
.terminal-cursor-hidden {
display: none;
}
`} `}
</style> </style>
<DynamicTextArea <DynamicTextArea
ref={textAreaRef} ref={textAreaRef}
value={output + userInput} value={output + (shouldAllowInput ? userInput : "")}
onChange={handleChange} onChange={handleChange}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
onKeyPress={handleKeyPress} onKeyPress={handleKeyPress}
@@ -272,12 +286,14 @@ const Terminal: React.FC<TerminalProps> = ({ output, handleSendStdin }) => {
onBlur={() => setIsFocused(false)} onBlur={() => setIsFocused(false)}
className="terminal-textarea" className="terminal-textarea"
style={{ style={{
backgroundColor: "var(--vscode-terminal-background)", backgroundColor: "var(--vscode-editor-background)",
caretColor: "transparent", // Hide default caret caretColor: "transparent", // Hide default caret
color: "var(--vscode-terminal-foreground)", color: "var(--vscode-terminal-foreground)",
borderRadius: "3px", borderRadius: "3px",
...(textAreaStyle as any), ...(textAreaStyle as any),
//pointerEvents: shouldAllowInput ? "auto" : "none",
}} }}
readOnly={!shouldAllowInput}
minRows={1} minRows={1}
/> />
<div ref={mirrorRef} className="terminal-mirror"></div> <div ref={mirrorRef} className="terminal-mirror"></div>