Skip to content

Commit 7c1918e

Browse files
committed
Refine state management to ensure the @ sign undo value is correctly saved and cleared during input changes and history navigation
1 parent 089223e commit 7c1918e

1 file changed

Lines changed: 58 additions & 0 deletions

File tree

‎packages/ui/src/components/editor/panel/ChatInput/hooks/use-handlers.ts‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import { ChatInputProps } from '../ChatInput'
44
export const use_handlers = (props: ChatInputProps) => {
55
const [history_index, set_history_index] = useState(-1)
66
const [is_history_enabled, set_is_history_enabled] = useState(!props.value)
7+
const [saved_value_before_at_sign, set_saved_value_before_at_sign] = useState<
8+
string | null
9+
>(null)
710

811
const handle_select = (e: React.SyntheticEvent<HTMLTextAreaElement>) => {
912
const textarea = e.currentTarget
@@ -15,16 +18,21 @@ export const use_handlers = (props: ChatInputProps) => {
1518
props.on_change('')
1619
set_history_index(-1)
1720
set_is_history_enabled(true)
21+
set_saved_value_before_at_sign(null)
1822
}
1923

2024
const handle_input_change = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
2125
const new_value = e.target.value
2226
props.on_change(new_value)
2327
set_history_index(-1)
2428

29+
// Clear saved value on any input change
30+
set_saved_value_before_at_sign(null)
31+
2532
const textarea = e.target
2633
const caret_position = textarea.selectionStart
2734
if (new_value.charAt(caret_position - 1) == '@') {
35+
set_saved_value_before_at_sign(props.value)
2836
setTimeout(() => {
2937
props.on_at_sign_click()
3038
}, 150)
@@ -55,6 +63,37 @@ export const use_handlers = (props: ChatInputProps) => {
5563
}
5664

5765
const handle_key_down = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
66+
if (e.key === 'Backspace') {
67+
const textarea = e.currentTarget
68+
const { selectionStart, selectionEnd, value } = textarea
69+
70+
if (selectionStart > 0 && selectionStart === selectionEnd) {
71+
const text_before_cursor = value.substring(0, selectionStart)
72+
const path_regex = /`([^\s`]*\.[^\s`]+)`$/
73+
const match = text_before_cursor.match(path_regex)
74+
75+
if (match) {
76+
const full_match = match[0] // e.g., `path/to/file.ts`
77+
const file_path = match[1] // e.g., path/to/file.ts
78+
79+
if (props.context_file_paths?.includes(file_path)) {
80+
e.preventDefault()
81+
const new_caret_position = selectionStart - full_match.length
82+
const new_value =
83+
value.substring(0, new_caret_position) +
84+
value.substring(selectionStart)
85+
props.on_change(new_value)
86+
set_is_history_enabled(!new_value)
87+
88+
setTimeout(() => {
89+
textarea.selectionStart = new_caret_position
90+
textarea.selectionEnd = new_caret_position
91+
}, 0)
92+
return
93+
}
94+
}
95+
}
96+
}
5897
if (e.key == 'Enter' && e.shiftKey) {
5998
e.preventDefault()
6099
const textarea = e.currentTarget
@@ -77,6 +116,8 @@ export const use_handlers = (props: ChatInputProps) => {
77116
(e.key == 'ArrowUp' || e.key == 'ArrowDown') &&
78117
is_history_enabled
79118
) {
119+
set_saved_value_before_at_sign(null)
120+
80121
const active_history = props.chat_history
81122

82123
if (active_history.length == 0) return
@@ -99,6 +140,23 @@ export const use_handlers = (props: ChatInputProps) => {
99140
props.on_change('')
100141
}
101142
}
143+
} else if (
144+
e.key == 'z' &&
145+
(e.ctrlKey || e.metaKey) &&
146+
!e.shiftKey &&
147+
saved_value_before_at_sign !== null
148+
) {
149+
// Handle Cmd/Ctrl + Z to undo @ sign action
150+
e.preventDefault()
151+
const restored_value = saved_value_before_at_sign
152+
set_saved_value_before_at_sign(null)
153+
props.on_change(restored_value)
154+
155+
// Restore caret position
156+
setTimeout(() => {
157+
const textarea = e.currentTarget
158+
textarea.selectionStart = textarea.selectionEnd = restored_value.length
159+
}, 0)
102160
} else if (props.value) {
103161
set_is_history_enabled(false)
104162
}

0 commit comments

Comments
 (0)