mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-04-29 20:20:57 +00:00
Merge branch 'main' into fix/shift-tab-windows-powershell
This commit is contained in:
commit
86ba86e297
352 changed files with 38309 additions and 6463 deletions
|
|
@ -6,22 +6,21 @@
|
|||
|
||||
import { Text } from 'ink';
|
||||
import { theme } from '../semantic-colors.js';
|
||||
import { tokenLimit } from '@qwen-code/qwen-code-core';
|
||||
|
||||
export const ContextUsageDisplay = ({
|
||||
promptTokenCount,
|
||||
model,
|
||||
terminalWidth,
|
||||
contextWindowSize,
|
||||
}: {
|
||||
promptTokenCount: number;
|
||||
model: string;
|
||||
terminalWidth: number;
|
||||
contextWindowSize: number;
|
||||
}) => {
|
||||
if (promptTokenCount === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const percentage = promptTokenCount / tokenLimit(model);
|
||||
const percentage = promptTokenCount / contextWindowSize;
|
||||
const percentageUsed = (percentage * 100).toFixed(1);
|
||||
|
||||
const label = terminalWidth < 100 ? '% used' : '% context used';
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ const defaultProps = {
|
|||
const createMockConfig = (overrides = {}) => ({
|
||||
getModel: vi.fn(() => defaultProps.model),
|
||||
getDebugMode: vi.fn(() => false),
|
||||
getContentGeneratorConfig: vi.fn(() => ({ contextWindowSize: 131072 })),
|
||||
getMcpServers: vi.fn(() => ({})),
|
||||
getBlockedMcpServers: vi.fn(() => []),
|
||||
...overrides,
|
||||
|
|
|
|||
|
|
@ -26,13 +26,11 @@ export const Footer: React.FC = () => {
|
|||
const { vimEnabled, vimMode } = useVimMode();
|
||||
|
||||
const {
|
||||
model,
|
||||
errorCount,
|
||||
showErrorDetails,
|
||||
promptTokenCount,
|
||||
showAutoAcceptIndicator,
|
||||
} = {
|
||||
model: config.getModel(),
|
||||
errorCount: uiState.errorCount,
|
||||
showErrorDetails: uiState.showErrorDetails,
|
||||
promptTokenCount: uiState.sessionStats.lastPromptTokenCount,
|
||||
|
|
@ -57,6 +55,9 @@ export const Footer: React.FC = () => {
|
|||
// Check if debug mode is enabled
|
||||
const debugMode = config.getDebugMode();
|
||||
|
||||
const contextWindowSize =
|
||||
config.getContentGeneratorConfig()?.contextWindowSize;
|
||||
|
||||
// Left section should show exactly ONE thing at any time, in priority order.
|
||||
const leftContent = uiState.ctrlCPressedOnce ? (
|
||||
<Text color={theme.status.warning}>{t('Press Ctrl+C again to exit.')}</Text>
|
||||
|
|
@ -88,15 +89,15 @@ export const Footer: React.FC = () => {
|
|||
node: <Text color={theme.status.warning}>Debug Mode</Text>,
|
||||
});
|
||||
}
|
||||
if (promptTokenCount > 0) {
|
||||
if (promptTokenCount > 0 && contextWindowSize) {
|
||||
rightItems.push({
|
||||
key: 'context',
|
||||
node: (
|
||||
<Text color={theme.text.accent}>
|
||||
<ContextUsageDisplay
|
||||
promptTokenCount={promptTokenCount}
|
||||
model={model}
|
||||
terminalWidth={terminalWidth}
|
||||
contextWindowSize={contextWindowSize}
|
||||
/>
|
||||
</Text>
|
||||
),
|
||||
|
|
|
|||
|
|
@ -36,6 +36,11 @@ vi.mock('../utils/clipboardUtils.js');
|
|||
vi.mock('../contexts/UIStateContext.js', () => ({
|
||||
useUIState: vi.fn(() => ({ isFeedbackDialogOpen: false })),
|
||||
}));
|
||||
vi.mock('../contexts/UIActionsContext.js', () => ({
|
||||
useUIActions: vi.fn(() => ({
|
||||
temporaryCloseFeedbackDialog: vi.fn(),
|
||||
})),
|
||||
}));
|
||||
|
||||
const mockSlashCommands: SlashCommand[] = [
|
||||
{
|
||||
|
|
@ -376,7 +381,7 @@ describe('InputPrompt', () => {
|
|||
it('should handle Ctrl+V when clipboard has an image', async () => {
|
||||
vi.mocked(clipboardUtils.clipboardHasImage).mockResolvedValue(true);
|
||||
vi.mocked(clipboardUtils.saveClipboardImage).mockResolvedValue(
|
||||
'/test/.gemini-clipboard/clipboard-123.png',
|
||||
'/test/.qwen-clipboard/clipboard-123.png',
|
||||
);
|
||||
|
||||
const { stdin, unmount } = renderWithProviders(
|
||||
|
|
@ -436,7 +441,7 @@ describe('InputPrompt', () => {
|
|||
it('should insert image path at cursor position with proper spacing', async () => {
|
||||
const imagePath = path.join(
|
||||
'test',
|
||||
'.gemini-clipboard',
|
||||
'.qwen-clipboard',
|
||||
'clipboard-456.png',
|
||||
);
|
||||
vi.mocked(clipboardUtils.clipboardHasImage).mockResolvedValue(true);
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import * as path from 'node:path';
|
|||
import { SCREEN_READER_USER_PREFIX } from '../textConstants.js';
|
||||
import { useShellFocusState } from '../contexts/ShellFocusContext.js';
|
||||
import { useUIState } from '../contexts/UIStateContext.js';
|
||||
import { useUIActions } from '../contexts/UIActionsContext.js';
|
||||
import { FEEDBACK_DIALOG_KEYS } from '../FeedbackDialog.js';
|
||||
export interface InputPromptProps {
|
||||
buffer: TextBuffer;
|
||||
|
|
@ -109,6 +110,7 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
|
|||
}) => {
|
||||
const isShellFocused = useShellFocusState();
|
||||
const uiState = useUIState();
|
||||
const uiActions = useUIActions();
|
||||
const [justNavigatedHistory, setJustNavigatedHistory] = useState(false);
|
||||
const [escPressCount, setEscPressCount] = useState(0);
|
||||
const [showEscapePrompt, setShowEscapePrompt] = useState(false);
|
||||
|
|
@ -337,12 +339,16 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
|
|||
return;
|
||||
}
|
||||
|
||||
// Intercept feedback dialog option keys (1, 2) when dialog is open
|
||||
if (
|
||||
uiState.isFeedbackDialogOpen &&
|
||||
(FEEDBACK_DIALOG_KEYS as readonly string[]).includes(key.name)
|
||||
) {
|
||||
return;
|
||||
// Handle feedback dialog keyboard interactions when dialog is open
|
||||
if (uiState.isFeedbackDialogOpen) {
|
||||
// If it's one of the feedback option keys (1-4), let FeedbackDialog handle it
|
||||
if ((FEEDBACK_DIALOG_KEYS as readonly string[]).includes(key.name)) {
|
||||
return;
|
||||
} else {
|
||||
// For any other key, close feedback dialog temporarily and continue with normal processing
|
||||
uiActions.temporaryCloseFeedbackDialog();
|
||||
// Continue processing the key for normal input handling
|
||||
}
|
||||
}
|
||||
|
||||
// Reset ESC count and hide prompt on any non-ESC key
|
||||
|
|
@ -712,6 +718,7 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
|
|||
onToggleShortcuts,
|
||||
showShortcuts,
|
||||
uiState,
|
||||
uiActions,
|
||||
],
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1368,7 +1368,7 @@ describe('SettingsDialog', () => {
|
|||
enabled: true,
|
||||
},
|
||||
context: {
|
||||
loadMemoryFromIncludeDirectories: true,
|
||||
loadFromIncludeDirectories: true,
|
||||
fileFiltering: {
|
||||
respectGitIgnore: true,
|
||||
respectQwenIgnore: true,
|
||||
|
|
@ -1540,7 +1540,7 @@ describe('SettingsDialog', () => {
|
|||
enableRecursiveFileSearch: false,
|
||||
disableFuzzySearch: true,
|
||||
},
|
||||
loadMemoryFromIncludeDirectories: true,
|
||||
loadFromIncludeDirectories: true,
|
||||
},
|
||||
});
|
||||
const onSelect = vi.fn();
|
||||
|
|
@ -1605,7 +1605,7 @@ describe('SettingsDialog', () => {
|
|||
enabled: false,
|
||||
},
|
||||
context: {
|
||||
loadMemoryFromIncludeDirectories: false,
|
||||
loadFromIncludeDirectories: false,
|
||||
fileFiltering: {
|
||||
respectGitIgnore: false,
|
||||
respectQwenIgnore: false,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue