@@ -4,6 +4,9 @@ import { ChatInputProps } from '../ChatInput'
44export 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