Skip to content

Commit 164d732

Browse files
committed
feat: Add global setting and keyboard shortcut for reasoning blocks
- Add reasoningBlockCollapsed setting to global state - Add backend message handler for persisting collapsed state - Add keyboard shortcut (Ctrl/Cmd+Shift+T) to toggle all reasoning blocks - Default to collapsed state for better UX
1 parent e42dbe9 commit 164d732

File tree

4 files changed

+31
-2
lines changed

4 files changed

+31
-2
lines changed

packages/types/src/global-settings.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ export const globalSettingsSchema = z.object({
147147
enhancementApiConfigId: z.string().optional(),
148148
includeTaskHistoryInEnhance: z.boolean().optional(),
149149
historyPreviewCollapsed: z.boolean().optional(),
150+
reasoningBlockCollapsed: z.boolean().optional(),
150151
profileThresholds: z.record(z.string(), z.number()).optional(),
151152
hasOpenedModeSelector: z.boolean().optional(),
152153
lastModeExportPath: z.string().optional(),

src/core/webview/webviewMessageHandler.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,6 +1617,10 @@ export const webviewMessageHandler = async (
16171617
await updateGlobalState("historyPreviewCollapsed", message.bool ?? false)
16181618
// No need to call postStateToWebview here as the UI already updated optimistically
16191619
break
1620+
case "setReasoningBlockCollapsed":
1621+
await updateGlobalState("reasoningBlockCollapsed", message.bool ?? true)
1622+
// No need to call postStateToWebview here as the UI already updated optimistically
1623+
break
16201624
case "toggleApiConfigPin":
16211625
if (message.text) {
16221626
const currentPinned = getGlobalState("pinnedApiConfigs") ?? {}

src/shared/WebviewMessage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ export interface WebviewMessage {
193193
| "focusPanelRequest"
194194
| "profileThresholds"
195195
| "setHistoryPreviewCollapsed"
196+
| "setReasoningBlockCollapsed"
196197
| "openExternal"
197198
| "filterMarketplaceItems"
198199
| "marketplaceButtonClicked"

webview-ui/src/components/chat/ReasoningBlock.tsx

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import React, { useEffect, useRef, useState } from "react"
1+
import React, { useEffect, useRef, useState, useCallback } from "react"
22
import { useTranslation } from "react-i18next"
33
import { useExtensionState } from "@src/context/ExtensionStateContext"
4+
import { vscode } from "@src/utils/vscode"
45

56
import MarkdownBlock from "../common/MarkdownBlock"
67
import { Lightbulb, ChevronDown, ChevronRight } from "lucide-react"
@@ -22,7 +23,7 @@ interface ReasoningBlockProps {
2223
*/
2324
export const ReasoningBlock = ({ content, isStreaming, isLast }: ReasoningBlockProps) => {
2425
const { t } = useTranslation()
25-
const { reasoningBlockCollapsed } = useExtensionState()
26+
const { reasoningBlockCollapsed, setReasoningBlockCollapsed } = useExtensionState()
2627

2728
// Initialize collapsed state based on global setting (default to collapsed)
2829
const [isCollapsed, setIsCollapsed] = useState(reasoningBlockCollapsed !== false)
@@ -36,6 +37,28 @@ export const ReasoningBlock = ({ content, isStreaming, isLast }: ReasoningBlockP
3637
setIsCollapsed(reasoningBlockCollapsed !== false)
3738
}, [reasoningBlockCollapsed])
3839

40+
// Handle keyboard shortcut for toggling collapsed state
41+
const handleKeyDown = useCallback(
42+
(e: KeyboardEvent) => {
43+
// Ctrl/Cmd + Shift + T to toggle reasoning blocks
44+
if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === "T") {
45+
e.preventDefault()
46+
const newState = !isCollapsed
47+
setIsCollapsed(newState)
48+
// Update global setting
49+
setReasoningBlockCollapsed(!newState)
50+
// Persist to backend
51+
vscode.postMessage({ type: "setReasoningBlockCollapsed", bool: !newState })
52+
}
53+
},
54+
[isCollapsed, setReasoningBlockCollapsed],
55+
)
56+
57+
useEffect(() => {
58+
window.addEventListener("keydown", handleKeyDown)
59+
return () => window.removeEventListener("keydown", handleKeyDown)
60+
}, [handleKeyDown])
61+
3962
// Simple timer that runs while streaming
4063
useEffect(() => {
4164
if (isLast && isStreaming) {

0 commit comments

Comments
 (0)