Skip to content
This repository was archived by the owner on May 15, 2026. It is now read-only.

Commit d1bddd3

Browse files
committed
feat: add autoExpandDiffs setting to auto-expand diffs in chat messages
Adds a new boolean setting `autoExpandDiffs` (default: false) that automatically expands diff views in "Roo wants to edit this file" chat messages. Diffs are still constrained to max-h-[300px] with scrollbar. Changes: - Add autoExpandDiffs to GlobalSettings schema (packages/types) - Add autoExpandDiffs to ExtensionState type (packages/types) - Wire setting through ClineProvider state to webview - Add auto-expand logic in ChatView for diff tool messages - Add UI toggle in Settings > UI section - Add English i18n translations - Update test fixtures Closes #10955
1 parent 12cddc9 commit d1bddd3

11 files changed

Lines changed: 83 additions & 0 deletions

File tree

packages/types/src/global-settings.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,11 @@ export const globalSettingsSchema = z.object({
208208
includeTaskHistoryInEnhance: z.boolean().optional(),
209209
historyPreviewCollapsed: z.boolean().optional(),
210210
reasoningBlockCollapsed: z.boolean().optional(),
211+
/**
212+
* Whether to auto-expand diffs in "Roo wants to edit this file" chat messages.
213+
* @default false
214+
*/
215+
autoExpandDiffs: z.boolean().optional(),
211216
/**
212217
* Controls the keyboard behavior for sending messages in the chat input.
213218
* - "send": Enter sends message, Shift+Enter creates newline (default)

packages/types/src/vscode-extension-host.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ export type ExtensionState = Pick<
328328
| "openRouterImageGenerationSelectedModel"
329329
| "includeTaskHistoryInEnhance"
330330
| "reasoningBlockCollapsed"
331+
| "autoExpandDiffs"
331332
| "enterBehavior"
332333
| "includeCurrentTime"
333334
| "includeCurrentCost"

src/core/webview/ClineProvider.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2063,6 +2063,7 @@ export class ClineProvider
20632063
maxTotalImageSize,
20642064
historyPreviewCollapsed,
20652065
reasoningBlockCollapsed,
2066+
autoExpandDiffs,
20662067
enterBehavior,
20672068
cloudUserInfo,
20682069
cloudIsAuthenticated,
@@ -2207,6 +2208,7 @@ export class ClineProvider
22072208
hasSystemPromptOverride,
22082209
historyPreviewCollapsed: historyPreviewCollapsed ?? false,
22092210
reasoningBlockCollapsed: reasoningBlockCollapsed ?? true,
2211+
autoExpandDiffs: autoExpandDiffs ?? false,
22102212
enterBehavior: enterBehavior ?? "send",
22112213
cloudUserInfo,
22122214
cloudIsAuthenticated: cloudIsAuthenticated ?? false,
@@ -2445,6 +2447,7 @@ export class ClineProvider
24452447
maxTotalImageSize: stateValues.maxTotalImageSize ?? 20,
24462448
historyPreviewCollapsed: stateValues.historyPreviewCollapsed ?? false,
24472449
reasoningBlockCollapsed: stateValues.reasoningBlockCollapsed ?? true,
2450+
autoExpandDiffs: stateValues.autoExpandDiffs ?? false,
24482451
enterBehavior: stateValues.enterBehavior ?? "send",
24492452
cloudUserInfo,
24502453
cloudIsAuthenticated,

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
9797
messageQueue = [],
9898
isBrowserSessionActive,
9999
showWorktreesInHomeScreen,
100+
autoExpandDiffs,
100101
} = useExtensionState()
101102

102103
const messagesRef = useRef(messages)
@@ -527,6 +528,43 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
527528
prevExpandedRowsRef.current = expandedRows // Store current state for next comparison
528529
}, [expandedRows])
529530

531+
// Auto-expand diff rows when autoExpandDiffs setting is enabled
532+
const DIFF_TOOL_TYPES = useMemo(
533+
() => new Set(["editedExistingFile", "appliedDiff", "insertContent", "searchAndReplace", "newFileCreated"]),
534+
[],
535+
)
536+
537+
useEffect(() => {
538+
if (!autoExpandDiffs) {
539+
return
540+
}
541+
542+
const newExpansions: Record<number, boolean> = {}
543+
544+
for (const msg of modifiedMessages) {
545+
// Skip messages already tracked in expandedRows
546+
if (expandedRows[msg.ts] !== undefined) {
547+
continue
548+
}
549+
550+
// Check if this message contains a diff tool
551+
if (msg.text) {
552+
try {
553+
const tool = JSON.parse(msg.text)
554+
if (tool.tool && DIFF_TOOL_TYPES.has(tool.tool)) {
555+
newExpansions[msg.ts] = true
556+
}
557+
} catch {
558+
// Not valid JSON, skip
559+
}
560+
}
561+
}
562+
563+
if (Object.keys(newExpansions).length > 0) {
564+
setExpandedRows((prev) => ({ ...prev, ...newExpansions }))
565+
}
566+
}, [modifiedMessages, autoExpandDiffs, expandedRows, DIFF_TOOL_TYPES])
567+
530568
const isStreaming = useMemo(() => {
531569
// Checking clineAsk isn't enough since messages effect may be called
532570
// again for a tool for example, set clineAsk to its value, and if the

webview-ui/src/components/settings/SettingsView.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
208208
openRouterImageApiKey,
209209
openRouterImageGenerationSelectedModel,
210210
reasoningBlockCollapsed,
211+
autoExpandDiffs,
211212
enterBehavior,
212213
includeCurrentTime,
213214
includeCurrentCost,
@@ -414,6 +415,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
414415
followupAutoApproveTimeoutMs,
415416
includeTaskHistoryInEnhance: includeTaskHistoryInEnhance ?? true,
416417
reasoningBlockCollapsed: reasoningBlockCollapsed ?? true,
418+
autoExpandDiffs: autoExpandDiffs ?? false,
417419
enterBehavior: enterBehavior ?? "send",
418420
includeCurrentTime: includeCurrentTime ?? true,
419421
includeCurrentCost: includeCurrentCost ?? true,
@@ -907,6 +909,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
907909
{renderTab === "ui" && (
908910
<UISettings
909911
reasoningBlockCollapsed={reasoningBlockCollapsed ?? true}
912+
autoExpandDiffs={autoExpandDiffs ?? false}
910913
enterBehavior={enterBehavior ?? "send"}
911914
setCachedStateField={setCachedStateField}
912915
/>

webview-ui/src/components/settings/UISettings.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ import { ExtensionStateContextType } from "@/context/ExtensionStateContext"
1111

1212
interface UISettingsProps extends HTMLAttributes<HTMLDivElement> {
1313
reasoningBlockCollapsed: boolean
14+
autoExpandDiffs: boolean
1415
enterBehavior: "send" | "newline"
1516
setCachedStateField: SetCachedStateField<keyof ExtensionStateContextType>
1617
}
1718

1819
export const UISettings = ({
1920
reasoningBlockCollapsed,
21+
autoExpandDiffs,
2022
enterBehavior,
2123
setCachedStateField,
2224
...props
@@ -38,6 +40,10 @@ export const UISettings = ({
3840
})
3941
}
4042

43+
const handleAutoExpandDiffsChange = (value: boolean) => {
44+
setCachedStateField("autoExpandDiffs", value)
45+
}
46+
4147
const handleEnterBehaviorChange = (requireCtrlEnter: boolean) => {
4248
const newBehavior = requireCtrlEnter ? "newline" : "send"
4349
setCachedStateField("enterBehavior", newBehavior)
@@ -72,6 +78,24 @@ export const UISettings = ({
7278
</div>
7379
</SearchableSetting>
7480

81+
{/* Auto-Expand Diffs Setting */}
82+
<SearchableSetting
83+
settingId="ui-auto-expand-diffs"
84+
section="ui"
85+
label={t("settings:ui.autoExpandDiffs.label")}>
86+
<div className="flex flex-col gap-1">
87+
<VSCodeCheckbox
88+
checked={autoExpandDiffs}
89+
onChange={(e: any) => handleAutoExpandDiffsChange(e.target.checked)}
90+
data-testid="auto-expand-diffs-checkbox">
91+
<span className="font-medium">{t("settings:ui.autoExpandDiffs.label")}</span>
92+
</VSCodeCheckbox>
93+
<div className="text-vscode-descriptionForeground text-sm ml-5 mt-1">
94+
{t("settings:ui.autoExpandDiffs.description")}
95+
</div>
96+
</div>
97+
</SearchableSetting>
98+
7599
{/* Enter Key Behavior Setting */}
76100
<SearchableSetting
77101
settingId="ui-enter-behavior"

webview-ui/src/components/settings/__tests__/SettingsView.change-detection.spec.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ describe("SettingsView - Change Detection Fix", () => {
260260
openRouterImageApiKey: undefined,
261261
openRouterImageGenerationSelectedModel: undefined,
262262
reasoningBlockCollapsed: true,
263+
autoExpandDiffs: false,
263264
...overrides,
264265
})
265266

webview-ui/src/components/settings/__tests__/SettingsView.unsaved-changes.spec.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ describe("SettingsView - Unsaved Changes Detection", () => {
265265
openRouterImageApiKey: undefined,
266266
openRouterImageGenerationSelectedModel: undefined,
267267
reasoningBlockCollapsed: true,
268+
autoExpandDiffs: false,
268269
}
269270

270271
beforeEach(() => {

webview-ui/src/components/settings/__tests__/UISettings.spec.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { UISettings } from "../UISettings"
55
describe("UISettings", () => {
66
const defaultProps = {
77
reasoningBlockCollapsed: false,
8+
autoExpandDiffs: false,
89
enterBehavior: "send" as const,
910
setCachedStateField: vi.fn(),
1011
}

webview-ui/src/context/ExtensionStateContext.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
237237
terminalZdotdir: false, // Default ZDOTDIR handling setting
238238
historyPreviewCollapsed: false, // Initialize the new state (default to expanded)
239239
reasoningBlockCollapsed: true, // Default to collapsed
240+
autoExpandDiffs: false, // Default to collapsed diffs
240241
enterBehavior: "send", // Default: Enter sends, Shift+Enter creates newline
241242
cloudUserInfo: null,
242243
cloudIsAuthenticated: false,
@@ -480,6 +481,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
480481
const contextValue: ExtensionStateContextType = {
481482
...state,
482483
reasoningBlockCollapsed: state.reasoningBlockCollapsed ?? true,
484+
autoExpandDiffs: state.autoExpandDiffs ?? false,
483485
didHydrateState,
484486
showWelcome,
485487
theme,

0 commit comments

Comments
 (0)