wave-code 0.8.3 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/components/ChatInterface.d.ts.map +1 -1
  2. package/dist/components/ChatInterface.js +26 -7
  3. package/dist/components/HelpView.d.ts.map +1 -1
  4. package/dist/components/HelpView.js +2 -0
  5. package/dist/components/InputBox.js +4 -3
  6. package/dist/components/MessageBlockItem.d.ts.map +1 -1
  7. package/dist/components/MessageBlockItem.js +1 -1
  8. package/dist/components/MessageList.d.ts +2 -1
  9. package/dist/components/MessageList.d.ts.map +1 -1
  10. package/dist/components/MessageList.js +14 -4
  11. package/dist/components/QueuedMessageList.d.ts +3 -0
  12. package/dist/components/QueuedMessageList.d.ts.map +1 -0
  13. package/dist/components/QueuedMessageList.js +17 -0
  14. package/dist/components/ReasoningDisplay.d.ts +1 -0
  15. package/dist/components/ReasoningDisplay.d.ts.map +1 -1
  16. package/dist/components/ReasoningDisplay.js +3 -3
  17. package/dist/components/RewindCommand.d.ts.map +1 -1
  18. package/dist/components/RewindCommand.js +10 -4
  19. package/dist/components/ToolDisplay.js +1 -1
  20. package/dist/contexts/useChat.d.ts +7 -0
  21. package/dist/contexts/useChat.d.ts.map +1 -1
  22. package/dist/contexts/useChat.js +17 -1
  23. package/dist/hooks/useInputManager.d.ts +3 -3
  24. package/dist/hooks/useInputManager.d.ts.map +1 -1
  25. package/dist/hooks/useInputManager.js +10 -9
  26. package/dist/managers/inputHandlers.d.ts +7 -4
  27. package/dist/managers/inputHandlers.d.ts.map +1 -1
  28. package/dist/managers/inputHandlers.js +165 -42
  29. package/package.json +2 -2
  30. package/src/components/ChatInterface.tsx +42 -15
  31. package/src/components/HelpView.tsx +2 -0
  32. package/src/components/InputBox.tsx +17 -17
  33. package/src/components/MessageBlockItem.tsx +8 -3
  34. package/src/components/MessageList.tsx +16 -3
  35. package/src/components/QueuedMessageList.tsx +31 -0
  36. package/src/components/ReasoningDisplay.tsx +8 -2
  37. package/src/components/RewindCommand.tsx +21 -5
  38. package/src/components/ToolDisplay.tsx +2 -2
  39. package/src/contexts/useChat.tsx +29 -1
  40. package/src/hooks/useInputManager.ts +9 -21
  41. package/src/managers/inputHandlers.ts +197 -56
@@ -35,6 +35,7 @@ export const RewindCommand: React.FC<RewindCommandProps> = ({
35
35
  .map((msg, index) => ({ msg, index }))
36
36
  .filter(({ msg }) => msg.role === "user");
37
37
 
38
+ const MAX_VISIBLE_ITEMS = 3;
38
39
  const [selectedIndex, setSelectedIndex] = useState(checkpoints.length - 1);
39
40
 
40
41
  // Update selectedIndex when checkpoints change (after loading full thread)
@@ -42,6 +43,19 @@ export const RewindCommand: React.FC<RewindCommandProps> = ({
42
43
  setSelectedIndex(checkpoints.length - 1);
43
44
  }, [checkpoints.length]);
44
45
 
46
+ // Calculate visible window
47
+ const startIndex = Math.max(
48
+ 0,
49
+ Math.min(
50
+ selectedIndex - Math.floor(MAX_VISIBLE_ITEMS / 2),
51
+ Math.max(0, checkpoints.length - MAX_VISIBLE_ITEMS),
52
+ ),
53
+ );
54
+ const visibleCheckpoints = checkpoints.slice(
55
+ startIndex,
56
+ startIndex + MAX_VISIBLE_ITEMS,
57
+ );
58
+
45
59
  useInput((input, key) => {
46
60
  if (key.return) {
47
61
  if (checkpoints.length > 0 && selectedIndex >= 0) {
@@ -114,12 +128,14 @@ export const RewindCommand: React.FC<RewindCommandProps> = ({
114
128
  </Box>
115
129
 
116
130
  <Box flexDirection="column">
117
- {checkpoints.map((checkpoint, index) => {
118
- const isSelected = index === selectedIndex;
131
+ {visibleCheckpoints.map((checkpoint, index) => {
132
+ const actualIndex = startIndex + index;
133
+ const isSelected = actualIndex === selectedIndex;
119
134
  const content = checkpoint.msg.blocks
120
135
  .filter((b): b is TextBlock => b.type === "text")
121
136
  .map((b) => b.content)
122
137
  .join(" ")
138
+ .replace(/\n/g, "\\n")
123
139
  .substring(0, 60);
124
140
 
125
141
  return (
@@ -130,7 +146,7 @@ export const RewindCommand: React.FC<RewindCommandProps> = ({
130
146
  >
131
147
  {isSelected ? "▶ " : " "}[{checkpoint.index}]{" "}
132
148
  {content || "(No text content)"}
133
- {index === checkpoints.length - 1 ? " (Latest)" : ""}
149
+ {actualIndex === checkpoints.length - 1 ? " (Latest)" : ""}
134
150
  </Text>
135
151
  </Box>
136
152
  );
@@ -142,8 +158,8 @@ export const RewindCommand: React.FC<RewindCommandProps> = ({
142
158
  </Box>
143
159
  <Box>
144
160
  <Text color="red" dimColor>
145
- ⚠️ Warning: This will delete all subsequent messages and revert file
146
- and task list changes.
161
+ Warning: This will delete all subsequent messages and revert file and
162
+ task list changes.
147
163
  </Text>
148
164
  </Box>
149
165
  </Box>
@@ -129,8 +129,8 @@ export const ToolDisplay: React.FC<ToolDisplayProps> = ({
129
129
  </Box>
130
130
  )}
131
131
 
132
- {/* Diff display - only show after tool execution completes and was successful */}
133
- {stage === "end" && success && (
132
+ {/* Diff display - only show after tool execution completes and was successful, and NOT in expanded mode */}
133
+ {!isExpanded && stage === "end" && success && (
134
134
  <DiffDisplay
135
135
  toolName={name}
136
136
  parameters={parameters}
@@ -37,6 +37,10 @@ export interface ChatContextType {
37
37
  isExpanded: boolean;
38
38
  isTaskListVisible: boolean;
39
39
  setIsTaskListVisible: (visible: boolean) => void;
40
+ queuedMessages: Array<{
41
+ content: string;
42
+ images?: Array<{ path: string; mimeType: string }>;
43
+ }>;
40
44
  // AI functionality
41
45
  sessionId: string;
42
46
  sendMessage: (
@@ -139,6 +143,13 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
139
143
 
140
144
  const [isTaskListVisible, setIsTaskListVisible] = useState(true);
141
145
 
146
+ const [queuedMessages, setQueuedMessages] = useState<
147
+ Array<{
148
+ content: string;
149
+ images?: Array<{ path: string; mimeType: string }>;
150
+ }>
151
+ >([]);
152
+
142
153
  // AI State
143
154
  const [messages, setMessages] = useState<Message[]>([]);
144
155
 
@@ -393,6 +404,11 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
393
404
 
394
405
  if (!hasTextContent && !hasImageAttachments) return;
395
406
 
407
+ if (isLoading || isCommandRunning) {
408
+ setQueuedMessages((prev) => [...prev, { content, images }]);
409
+ return;
410
+ }
411
+
396
412
  try {
397
413
  // Handle bash mode - check if it's a bash command (starts with ! and only one line)
398
414
  if (content.startsWith("!") && !content.includes("\n")) {
@@ -432,15 +448,26 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
432
448
  // Loading state will be automatically updated by the useEffect that watches messages
433
449
  }
434
450
  },
435
- [],
451
+ [isLoading, isCommandRunning],
436
452
  );
437
453
 
454
+ // Process queued messages when idle
455
+ useEffect(() => {
456
+ if (!isLoading && !isCommandRunning && queuedMessages.length > 0) {
457
+ const nextMessage = queuedMessages[0];
458
+ setQueuedMessages((prev) => prev.slice(1));
459
+ sendMessage(nextMessage.content, nextMessage.images);
460
+ }
461
+ }, [isLoading, isCommandRunning, queuedMessages, sendMessage]);
462
+
438
463
  // Unified interrupt method, interrupt both AI messages and command execution
439
464
  const abortMessage = useCallback(() => {
465
+ setQueuedMessages([]);
440
466
  agentRef.current?.abortMessage();
441
467
  }, []);
442
468
 
443
469
  const clearMessages = useCallback(() => {
470
+ setQueuedMessages([]);
444
471
  agentRef.current?.clearMessages();
445
472
  }, []);
446
473
 
@@ -604,6 +631,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
604
631
  isExpanded,
605
632
  isTaskListVisible,
606
633
  setIsTaskListVisible,
634
+ queuedMessages,
607
635
  sessionId,
608
636
  sendMessage,
609
637
  abortMessage,
@@ -204,14 +204,16 @@ export const useInputManager = (
204
204
  const handleCommandInsert = useCallback((command: string) => {
205
205
  const currentState = stateRef.current;
206
206
  if (currentState.slashPosition >= 0) {
207
+ const wordEnd = handlers.getWordEnd(
208
+ currentState.inputText,
209
+ currentState.slashPosition,
210
+ );
207
211
  const beforeSlash = currentState.inputText.substring(
208
212
  0,
209
213
  currentState.slashPosition,
210
214
  );
211
- const afterQuery = currentState.inputText.substring(
212
- currentState.cursorPosition,
213
- );
214
- const newInput = beforeSlash + `/${command} ` + afterQuery;
215
+ const afterWord = currentState.inputText.substring(wordEnd);
216
+ const newInput = beforeSlash + `/${command} ` + afterWord;
215
217
  const newCursorPosition = beforeSlash.length + command.length + 2;
216
218
 
217
219
  dispatch({ type: "SET_INPUT_TEXT", payload: newInput });
@@ -255,14 +257,8 @@ export const useInputManager = (
255
257
  dispatch({ type: "CANCEL_HISTORY_SEARCH" });
256
258
  }, []);
257
259
 
258
- const handleSpecialCharInput = useCallback((char: string) => {
259
- handlers.handleSpecialCharInput(
260
- stateRef.current,
261
- dispatch,
262
- char,
263
- stateRef.current.cursorPosition,
264
- stateRef.current.inputText,
265
- );
260
+ const processSelectorInput = useCallback((char: string) => {
261
+ handlers.processSelectorInput(stateRef.current, dispatch, char);
266
262
  }, []);
267
263
 
268
264
  const setInputText = useCallback((text: string) => {
@@ -326,15 +322,11 @@ export const useInputManager = (
326
322
  const handleSubmit = useCallback(
327
323
  async (
328
324
  attachedImages: Array<{ id: number; path: string; mimeType: string }>,
329
- isLoading: boolean = false,
330
- isCommandRunning: boolean = false,
331
325
  ) => {
332
326
  await handlers.handleSubmit(
333
327
  stateRef.current,
334
328
  dispatch,
335
329
  callbacksRef.current,
336
- isLoading,
337
- isCommandRunning,
338
330
  attachedImages,
339
331
  );
340
332
  },
@@ -357,8 +349,6 @@ export const useInputManager = (
357
349
  input: string,
358
350
  key: Key,
359
351
  attachedImages: Array<{ id: number; path: string; mimeType: string }>,
360
- isLoading: boolean = false,
361
- isCommandRunning: boolean = false,
362
352
  clearImages?: () => void,
363
353
  ) => {
364
354
  return await handlers.handleInput(
@@ -367,8 +357,6 @@ export const useInputManager = (
367
357
  callbacksRef.current,
368
358
  input,
369
359
  key,
370
- isLoading,
371
- isCommandRunning,
372
360
  clearImages,
373
361
  );
374
362
  },
@@ -424,7 +412,7 @@ export const useInputManager = (
424
412
  handleCancelHistorySearch,
425
413
 
426
414
  // Special handling
427
- handleSpecialCharInput,
415
+ processSelectorInput,
428
416
 
429
417
  // Bash/MCP Manager
430
418
  setShowBackgroundTaskManager,
@@ -30,18 +30,12 @@ export const handleSubmit = async (
30
30
  state: InputState,
31
31
  dispatch: React.Dispatch<InputAction>,
32
32
  callbacks: Partial<InputManagerCallbacks>,
33
- isLoading: boolean = false,
34
- isCommandRunning: boolean = false,
35
33
  attachedImagesOverride?: Array<{
36
34
  id: number;
37
35
  path: string;
38
36
  mimeType: string;
39
37
  }>,
40
38
  ): Promise<void> => {
41
- if (isLoading || isCommandRunning) {
42
- return;
43
- }
44
-
45
39
  if (state.inputText.trim()) {
46
40
  const imageRegex = /\[Image #(\d+)\]/g;
47
41
  const matches = [...state.inputText.matchAll(imageRegex)];
@@ -114,6 +108,72 @@ export const cyclePermissionMode = (
114
108
  callbacks.onPermissionModeChange?.(nextMode);
115
109
  };
116
110
 
111
+ const SELECTOR_TRIGGERS = [
112
+ {
113
+ char: "@",
114
+ type: "ACTIVATE_FILE_SELECTOR",
115
+ shouldActivate: (char: string, pos: number, text: string) =>
116
+ char === "@" && (pos === 1 || /\s/.test(text[pos - 2])),
117
+ },
118
+ {
119
+ char: "/",
120
+ type: "ACTIVATE_COMMAND_SELECTOR",
121
+ shouldActivate: (
122
+ char: string,
123
+ pos: number,
124
+ text: string,
125
+ state: InputState,
126
+ ) =>
127
+ char === "/" &&
128
+ !state.showFileSelector &&
129
+ (pos === 1 || /\s/.test(text[pos - 2])),
130
+ },
131
+ ] as const;
132
+
133
+ const getProjectedState = (state: InputState, char: string) => {
134
+ const beforeCursor = state.inputText.substring(0, state.cursorPosition);
135
+ const afterCursor = state.inputText.substring(state.cursorPosition);
136
+ const newInputText = beforeCursor + char + afterCursor;
137
+ const newCursorPosition = state.cursorPosition + char.length;
138
+ return { newInputText, newCursorPosition };
139
+ };
140
+
141
+ export const getAtSelectorPosition = (
142
+ text: string,
143
+ cursorPosition: number,
144
+ ): number => {
145
+ let i = cursorPosition - 1;
146
+ while (i >= 0 && !/\s/.test(text[i])) {
147
+ if (text[i] === "@") {
148
+ // Check if this @ is at the start or preceded by whitespace
149
+ if (i === 0 || /\s/.test(text[i - 1])) {
150
+ return i;
151
+ }
152
+ break;
153
+ }
154
+ i--;
155
+ }
156
+ return -1;
157
+ };
158
+
159
+ export const getSlashSelectorPosition = (
160
+ text: string,
161
+ cursorPosition: number,
162
+ ): number => {
163
+ let i = cursorPosition - 1;
164
+ while (i >= 0 && !/\s/.test(text[i])) {
165
+ if (text[i] === "/") {
166
+ // Check if this / is at the start or preceded by whitespace
167
+ if (i === 0 || /\s/.test(text[i - 1])) {
168
+ return i;
169
+ }
170
+ break;
171
+ }
172
+ i--;
173
+ }
174
+ return -1;
175
+ };
176
+
117
177
  export const updateSearchQueriesForActiveSelectors = (
118
178
  state: InputState,
119
179
  dispatch: React.Dispatch<InputAction>,
@@ -133,26 +193,58 @@ export const updateSearchQueriesForActiveSelectors = (
133
193
  }
134
194
  };
135
195
 
136
- export const handleSpecialCharInput = (
196
+ export const processSelectorInput = (
137
197
  state: InputState,
138
198
  dispatch: React.Dispatch<InputAction>,
139
199
  char: string,
140
- cursorPosition: number,
141
- inputText: string,
142
200
  ): void => {
143
- if (char === "@") {
144
- dispatch({ type: "ACTIVATE_FILE_SELECTOR", payload: cursorPosition - 1 });
145
- } else if (char === "/" && !state.showFileSelector && cursorPosition === 1) {
201
+ const { newInputText, newCursorPosition } = getProjectedState(state, char);
202
+
203
+ const trigger = SELECTOR_TRIGGERS.find((t) =>
204
+ t.shouldActivate(char, newCursorPosition, newInputText, state),
205
+ );
206
+
207
+ if (trigger) {
146
208
  dispatch({
147
- type: "ACTIVATE_COMMAND_SELECTOR",
148
- payload: cursorPosition - 1,
149
- });
209
+ type: trigger.type,
210
+ payload: newCursorPosition - 1,
211
+ } as InputAction);
150
212
  } else {
213
+ const atPos = getAtSelectorPosition(newInputText, newCursorPosition);
214
+ let showFileSelector = state.showFileSelector;
215
+ let atPosition = state.atPosition;
216
+ if (atPos !== -1 && !state.showFileSelector) {
217
+ dispatch({
218
+ type: "ACTIVATE_FILE_SELECTOR",
219
+ payload: atPos,
220
+ });
221
+ showFileSelector = true;
222
+ atPosition = atPos;
223
+ }
224
+
225
+ const slashPos = getSlashSelectorPosition(newInputText, newCursorPosition);
226
+ let showCommandSelector = state.showCommandSelector;
227
+ let slashPosition = state.slashPosition;
228
+ if (slashPos !== -1 && !state.showCommandSelector) {
229
+ dispatch({
230
+ type: "ACTIVATE_COMMAND_SELECTOR",
231
+ payload: slashPos,
232
+ });
233
+ showCommandSelector = true;
234
+ slashPosition = slashPos;
235
+ }
236
+
151
237
  updateSearchQueriesForActiveSelectors(
152
- state,
238
+ {
239
+ ...state,
240
+ showFileSelector,
241
+ atPosition,
242
+ showCommandSelector,
243
+ slashPosition,
244
+ },
153
245
  dispatch,
154
- inputText,
155
- cursorPosition,
246
+ newInputText,
247
+ newCursorPosition,
156
248
  );
157
249
  }
158
250
  };
@@ -187,20 +279,16 @@ export const handlePasteInput = (
187
279
  callbacks.onResetHistoryNavigation?.();
188
280
  dispatch({ type: "INSERT_TEXT", payload: char });
189
281
 
190
- // Calculate new state for special char handling
191
- const newCursorPosition = state.cursorPosition + char.length;
192
- const beforeCursor = state.inputText.substring(0, state.cursorPosition);
193
- const afterCursor = state.inputText.substring(state.cursorPosition);
194
- const newInputText = beforeCursor + char + afterCursor;
282
+ processSelectorInput(state, dispatch, char);
283
+ }
284
+ };
195
285
 
196
- handleSpecialCharInput(
197
- state,
198
- dispatch,
199
- char,
200
- newCursorPosition,
201
- newInputText,
202
- );
286
+ export const getWordEnd = (text: string, startPos: number): number => {
287
+ let i = startPos;
288
+ while (i < text.length && !/\s/.test(text[i])) {
289
+ i++;
203
290
  }
291
+ return i;
204
292
  };
205
293
 
206
294
  export const handleCommandSelect = (
@@ -210,9 +298,10 @@ export const handleCommandSelect = (
210
298
  command: string,
211
299
  ) => {
212
300
  if (state.slashPosition >= 0) {
301
+ const wordEnd = getWordEnd(state.inputText, state.slashPosition);
213
302
  const beforeSlash = state.inputText.substring(0, state.slashPosition);
214
- const afterQuery = state.inputText.substring(state.cursorPosition);
215
- const newInput = beforeSlash + afterQuery;
303
+ const afterWord = state.inputText.substring(wordEnd);
304
+ const newInput = beforeSlash + afterWord;
216
305
  const newCursorPosition = beforeSlash.length;
217
306
 
218
307
  dispatch({ type: "SET_INPUT_TEXT", payload: newInput });
@@ -264,10 +353,11 @@ export const handleFileSelect = (
264
353
  filePath: string,
265
354
  ) => {
266
355
  if (state.atPosition >= 0) {
356
+ const wordEnd = getWordEnd(state.inputText, state.atPosition);
267
357
  const beforeAt = state.inputText.substring(0, state.atPosition);
268
- const afterQuery = state.inputText.substring(state.cursorPosition);
269
- const newInput = beforeAt + `${filePath} ` + afterQuery;
270
- const newCursorPosition = beforeAt.length + filePath.length + 1;
358
+ const afterWord = state.inputText.substring(wordEnd);
359
+ const newInput = beforeAt + `@${filePath} ` + afterWord;
360
+ const newCursorPosition = beforeAt.length + filePath.length + 2;
271
361
 
272
362
  dispatch({ type: "SET_INPUT_TEXT", payload: newInput });
273
363
  dispatch({ type: "SET_CURSOR_POSITION", payload: newCursorPosition });
@@ -343,6 +433,26 @@ export const handleSelectorInput = (
343
433
  return true;
344
434
  }
345
435
 
436
+ if (key.leftArrow) {
437
+ const newCursorPosition = state.cursorPosition - 1;
438
+ dispatch({ type: "MOVE_CURSOR", payload: -1 });
439
+ checkForAtDeletion(state, dispatch, newCursorPosition);
440
+ checkForSlashDeletion(state, dispatch, newCursorPosition);
441
+ return true;
442
+ }
443
+
444
+ if (key.rightArrow) {
445
+ const newCursorPosition = state.cursorPosition + 1;
446
+ dispatch({ type: "MOVE_CURSOR", payload: 1 });
447
+ checkForAtDeletion(state, dispatch, newCursorPosition);
448
+ checkForSlashDeletion(state, dispatch, newCursorPosition);
449
+ return true;
450
+ }
451
+
452
+ if (input === " " && state.showFileSelector) {
453
+ dispatch({ type: "CANCEL_FILE_SELECTOR" });
454
+ }
455
+
346
456
  if (
347
457
  input &&
348
458
  !key.ctrl &&
@@ -358,19 +468,7 @@ export const handleSelectorInput = (
358
468
  ) {
359
469
  dispatch({ type: "INSERT_TEXT", payload: input });
360
470
 
361
- // Calculate new state for special char handling
362
- const newCursorPosition = state.cursorPosition + input.length;
363
- const beforeCursor = state.inputText.substring(0, state.cursorPosition);
364
- const afterCursor = state.inputText.substring(state.cursorPosition);
365
- const newInputText = beforeCursor + input + afterCursor;
366
-
367
- handleSpecialCharInput(
368
- state,
369
- dispatch,
370
- input,
371
- newCursorPosition,
372
- newInputText,
373
- );
471
+ processSelectorInput(state, dispatch, input);
374
472
  return true;
375
473
  }
376
474
 
@@ -383,12 +481,10 @@ export const handleNormalInput = async (
383
481
  callbacks: Partial<InputManagerCallbacks>,
384
482
  input: string,
385
483
  key: Key,
386
- isLoading: boolean = false,
387
- isCommandRunning: boolean = false,
388
484
  clearImages?: () => void,
389
485
  ): Promise<boolean> => {
390
486
  if (key.return) {
391
- await handleSubmit(state, dispatch, callbacks, isLoading, isCommandRunning);
487
+ await handleSubmit(state, dispatch, callbacks);
392
488
  clearImages?.();
393
489
  return true;
394
490
  }
@@ -405,11 +501,61 @@ export const handleNormalInput = async (
405
501
  if (key.backspace || key.delete) {
406
502
  if (state.cursorPosition > 0) {
407
503
  const newCursorPosition = state.cursorPosition - 1;
504
+ const beforeCursor = state.inputText.substring(
505
+ 0,
506
+ state.cursorPosition - 1,
507
+ );
508
+ const afterCursor = state.inputText.substring(state.cursorPosition);
509
+ const newInputText = beforeCursor + afterCursor;
510
+
408
511
  dispatch({ type: "DELETE_CHAR" });
409
512
  callbacks.onResetHistoryNavigation?.();
410
513
 
411
514
  checkForAtDeletion(state, dispatch, newCursorPosition);
412
515
  checkForSlashDeletion(state, dispatch, newCursorPosition);
516
+
517
+ // Reactivate file selector if cursor is now within an @word
518
+ const atPos = getAtSelectorPosition(newInputText, newCursorPosition);
519
+ let showFileSelector = state.showFileSelector;
520
+ let atPosition = state.atPosition;
521
+ if (atPos !== -1 && !state.showFileSelector) {
522
+ dispatch({
523
+ type: "ACTIVATE_FILE_SELECTOR",
524
+ payload: atPos,
525
+ });
526
+ showFileSelector = true;
527
+ atPosition = atPos;
528
+ }
529
+
530
+ const slashPos = getSlashSelectorPosition(
531
+ newInputText,
532
+ newCursorPosition,
533
+ );
534
+ let showCommandSelector = state.showCommandSelector;
535
+ let slashPosition = state.slashPosition;
536
+ if (slashPos !== -1 && !state.showCommandSelector) {
537
+ dispatch({
538
+ type: "ACTIVATE_COMMAND_SELECTOR",
539
+ payload: slashPos,
540
+ });
541
+ showCommandSelector = true;
542
+ slashPosition = slashPos;
543
+ }
544
+
545
+ updateSearchQueriesForActiveSelectors(
546
+ {
547
+ ...state,
548
+ inputText: newInputText,
549
+ cursorPosition: newCursorPosition,
550
+ showFileSelector,
551
+ atPosition,
552
+ showCommandSelector,
553
+ slashPosition,
554
+ },
555
+ dispatch,
556
+ newInputText,
557
+ newCursorPosition,
558
+ );
413
559
  }
414
560
  return true;
415
561
  }
@@ -468,8 +614,6 @@ export const handleInput = async (
468
614
  callbacks: Partial<InputManagerCallbacks>,
469
615
  input: string,
470
616
  key: Key,
471
- isLoading: boolean = false,
472
- isCommandRunning: boolean = false,
473
617
  clearImages?: () => void,
474
618
  ): Promise<boolean> => {
475
619
  if (state.selectorJustUsed) {
@@ -478,7 +622,6 @@ export const handleInput = async (
478
622
 
479
623
  if (key.escape) {
480
624
  if (
481
- (isLoading || isCommandRunning) &&
482
625
  !(
483
626
  state.showFileSelector ||
484
627
  state.showCommandSelector ||
@@ -552,8 +695,6 @@ export const handleInput = async (
552
695
  callbacks,
553
696
  input,
554
697
  key,
555
- isLoading,
556
- isCommandRunning,
557
698
  clearImages,
558
699
  );
559
700
  }