diff --git a/packages/types/src/global-settings.ts b/packages/types/src/global-settings.ts index 6e61c3950f5..257bcb2645d 100644 --- a/packages/types/src/global-settings.ts +++ b/packages/types/src/global-settings.ts @@ -83,6 +83,7 @@ export const globalSettingsSchema = z.object({ alwaysAllowFollowupQuestions: z.boolean().optional(), followupAutoApproveTimeoutMs: z.number().optional(), alwaysAllowUpdateTodoList: z.boolean().optional(), + requireCtrlEnterToSend: z.boolean().optional(), allowedCommands: z.array(z.string()).optional(), deniedCommands: z.array(z.string()).optional(), commandExecutionTimeout: z.number().optional(), diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 3e054ce7d25..377f10bf64f 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -1905,6 +1905,7 @@ export class ClineProvider terminalCompressProgressBar, historyPreviewCollapsed, reasoningBlockCollapsed, + requireCtrlEnterToSend, cloudUserInfo, cloudIsAuthenticated, sharingEnabled, @@ -2058,6 +2059,7 @@ export class ClineProvider hasSystemPromptOverride, historyPreviewCollapsed: historyPreviewCollapsed ?? false, reasoningBlockCollapsed: reasoningBlockCollapsed ?? true, + requireCtrlEnterToSend: requireCtrlEnterToSend ?? false, cloudUserInfo, cloudIsAuthenticated: cloudIsAuthenticated ?? false, cloudOrganizations, @@ -2287,6 +2289,7 @@ export class ClineProvider maxConcurrentFileReads: stateValues.maxConcurrentFileReads ?? 5, historyPreviewCollapsed: stateValues.historyPreviewCollapsed ?? false, reasoningBlockCollapsed: stateValues.reasoningBlockCollapsed ?? true, + requireCtrlEnterToSend: stateValues.requireCtrlEnterToSend ?? false, cloudUserInfo, cloudIsAuthenticated, sharingEnabled, diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index 0d50f0ed487..e892c72075b 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -131,6 +131,7 @@ export interface ExtensionMessage { | "interactionRequired" | "browserSessionUpdate" | "browserSessionNavigate" + | "requireCtrlEnterToSend" text?: string payload?: any // Add a generic payload for now, can refine later // Checkpoint warning message @@ -138,6 +139,7 @@ export interface ExtensionMessage { type: "WAIT_TIMEOUT" | "INIT_TIMEOUT" timeout: number } + bool?: boolean action?: | "chatButtonClicked" | "settingsButtonClicked" @@ -288,6 +290,7 @@ export type ExtensionState = Pick< | "includeCurrentTime" | "includeCurrentCost" | "maxGitStatusFiles" + | "requireCtrlEnterToSend" > & { version: string clineMessages: ClineMessage[] diff --git a/webview-ui/src/components/chat/ChatTextArea.tsx b/webview-ui/src/components/chat/ChatTextArea.tsx index 58f42a367bc..194c9b27c7b 100644 --- a/webview-ui/src/components/chat/ChatTextArea.tsx +++ b/webview-ui/src/components/chat/ChatTextArea.tsx @@ -11,6 +11,7 @@ import { ExtensionMessage } from "@roo/ExtensionMessage" import { vscode } from "@src/utils/vscode" import { useExtensionState } from "@src/context/ExtensionStateContext" import { useAppTranslation } from "@src/i18n/TranslationContext" +import { getSendMessageKeyCombination } from "@src/utils/platform" import { ContextMenuOptionType, getContextMenuOptions, @@ -94,6 +95,7 @@ export const ChatTextArea = forwardRef( clineMessages, commands, cloudUserInfo, + requireCtrlEnterToSend, } = useExtensionState() // Find the ID and display text for the currently selected API configuration. @@ -473,6 +475,11 @@ export const ChatTextArea = forwardRef( } if (event.key === "Enter" && !event.shiftKey && !isComposing) { + // If Ctrl+Enter is required but neither Ctrl nor Meta (Cmd) key is pressed, don't send + if (requireCtrlEnterToSend && !event.ctrlKey && !event.metaKey) { + return + } + event.preventDefault() // Always call onSend - let ChatView handle queueing when disabled @@ -541,6 +548,7 @@ export const ChatTextArea = forwardRef( handleHistoryNavigation, resetHistoryNavigation, commands, + requireCtrlEnterToSend, ], ) @@ -1000,11 +1008,8 @@ export const ChatTextArea = forwardRef( "font-vscode-font-family", "text-vscode-editor-font-size", "leading-vscode-editor-line-height", - isFocused - ? "border border-vscode-focusBorder outline outline-vscode-focusBorder" - : isDraggingOver - ? "border-2 border-dashed border-vscode-focusBorder" - : "border border-transparent", + "border-none", + "outline-none", "pl-2", "py-2", isEditMode ? "pr-20" : "pr-9", @@ -1159,7 +1164,13 @@ export const ChatTextArea = forwardRef( )} - +