mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-04-30 04:30:48 +00:00
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> - In ACP mode: allow ask_user_question in YOLO mode (user must respond) - In ACP mode: allow ask_user_question in plan mode for clarifications - Hide footer when confirmation dialog is active - Fix tab index overflow with functional state updates - Fix ask_user_question detection in VSCode companion (use rawInput) - Add cleanup for pending ACP promises on panel/provider dispose - Use theme.text.accent consistently for highlighted elements - Remove unused 'answers' param from AskUserQuestionParams This ensures users can always respond to clarification questions in ACP mode regardless of approval mode, and improves dialog UX.
116 lines
4.3 KiB
TypeScript
116 lines
4.3 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2025 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import { Box, useIsScreenReaderEnabled } from 'ink';
|
|
import { useCallback, useState } from 'react';
|
|
import { LoadingIndicator } from './LoadingIndicator.js';
|
|
import { InputPrompt } from './InputPrompt.js';
|
|
import { Footer } from './Footer.js';
|
|
import { QueuedMessageDisplay } from './QueuedMessageDisplay.js';
|
|
import { KeyboardShortcuts } from './KeyboardShortcuts.js';
|
|
import { useUIState } from '../contexts/UIStateContext.js';
|
|
import { useUIActions } from '../contexts/UIActionsContext.js';
|
|
import { useVimMode } from '../contexts/VimModeContext.js';
|
|
import { useConfig } from '../contexts/ConfigContext.js';
|
|
import { StreamingState } from '../types.js';
|
|
import { ConfigInitDisplay } from '../components/ConfigInitDisplay.js';
|
|
import { FeedbackDialog } from '../FeedbackDialog.js';
|
|
import { t } from '../../i18n/index.js';
|
|
|
|
export const Composer = () => {
|
|
const config = useConfig();
|
|
const isScreenReaderEnabled = useIsScreenReaderEnabled();
|
|
const uiState = useUIState();
|
|
const uiActions = useUIActions();
|
|
const { vimEnabled } = useVimMode();
|
|
|
|
const { showAutoAcceptIndicator } = uiState;
|
|
|
|
// State for keyboard shortcuts display toggle
|
|
const [showShortcuts, setShowShortcuts] = useState(false);
|
|
const handleToggleShortcuts = useCallback(() => {
|
|
setShowShortcuts((prev) => !prev);
|
|
}, []);
|
|
|
|
// State for suggestions visibility
|
|
const [showSuggestions, setShowSuggestions] = useState(false);
|
|
const handleSuggestionsVisibilityChange = useCallback(
|
|
(visible: boolean) => {
|
|
setShowSuggestions(visible);
|
|
// Also notify AppContainer for Tab key handling
|
|
uiActions.onSuggestionsVisibilityChange(visible);
|
|
},
|
|
[uiActions],
|
|
);
|
|
|
|
return (
|
|
<Box flexDirection="column" marginTop={1}>
|
|
{!uiState.embeddedShellFocused && (
|
|
<LoadingIndicator
|
|
// Hide loading phrases when enableLoadingPhrases is explicitly false.
|
|
// Using === false ensures phrases show by default when undefined.
|
|
thought={
|
|
uiState.streamingState === StreamingState.WaitingForConfirmation ||
|
|
config.getAccessibility()?.enableLoadingPhrases === false
|
|
? undefined
|
|
: uiState.thought
|
|
}
|
|
currentLoadingPhrase={
|
|
config.getAccessibility()?.enableLoadingPhrases === false
|
|
? undefined
|
|
: uiState.currentLoadingPhrase
|
|
}
|
|
elapsedTime={uiState.elapsedTime}
|
|
/>
|
|
)}
|
|
|
|
{!uiState.isConfigInitialized && <ConfigInitDisplay />}
|
|
|
|
<QueuedMessageDisplay messageQueue={uiState.messageQueue} />
|
|
|
|
{uiState.isFeedbackDialogOpen && <FeedbackDialog />}
|
|
|
|
{uiState.isInputActive && (
|
|
<InputPrompt
|
|
buffer={uiState.buffer}
|
|
inputWidth={uiState.inputWidth}
|
|
suggestionsWidth={uiState.suggestionsWidth}
|
|
onSubmit={uiActions.handleFinalSubmit}
|
|
userMessages={uiState.userMessages}
|
|
onClearScreen={uiActions.handleClearScreen}
|
|
config={config}
|
|
slashCommands={uiState.slashCommands}
|
|
commandContext={uiState.commandContext}
|
|
shellModeActive={uiState.shellModeActive}
|
|
setShellModeActive={uiActions.setShellModeActive}
|
|
approvalMode={showAutoAcceptIndicator}
|
|
onEscapePromptChange={uiActions.onEscapePromptChange}
|
|
onToggleShortcuts={handleToggleShortcuts}
|
|
showShortcuts={showShortcuts}
|
|
onSuggestionsVisibilityChange={handleSuggestionsVisibilityChange}
|
|
focus={true}
|
|
vimHandleInput={uiActions.vimHandleInput}
|
|
isEmbeddedShellFocused={uiState.embeddedShellFocused}
|
|
placeholder={
|
|
vimEnabled
|
|
? ' ' + t("Press 'i' for INSERT mode and 'Esc' for NORMAL mode.")
|
|
: ' ' + t('Type your message or @path/to/file')
|
|
}
|
|
/>
|
|
)}
|
|
|
|
{/* Exclusive area: only one component visible at a time */}
|
|
{/* Hide footer when a confirmation dialog (e.g. ask_user_question) is active */}
|
|
{!showSuggestions &&
|
|
uiState.streamingState !== StreamingState.WaitingForConfirmation &&
|
|
(showShortcuts ? (
|
|
<KeyboardShortcuts />
|
|
) : (
|
|
!isScreenReaderEnabled && <Footer />
|
|
))}
|
|
</Box>
|
|
);
|
|
};
|