diff --git a/.changeset/disable-diff-visualization.md b/.changeset/disable-diff-visualization.md index 5f95e013bd..51828ddea5 100644 --- a/.changeset/disable-diff-visualization.md +++ b/.changeset/disable-diff-visualization.md @@ -2,6 +2,6 @@ "roo-cline": patch --- -Add setting to disable diff visualization to prevent LSP crashes +Add experimental setting to disable diff visualization for all edit tools -Added a new setting `disableDiffVisualization` that allows users to disable the diff view when editing files. When enabled, files will open directly in the editor instead of showing a side-by-side diff view. This helps prevent Language Server Protocol (LSP) crashes that can occur with very large files, particularly affecting C# developers. The changes made by Roo are still visible in the chat window. +Added a new experimental setting `disableDiffVisualization` that allows users to disable diff visualization for all edit tools (write_to_file, apply_diff, insert_content, search_and_replace). When enabled, files will open directly in the editor instead of showing a side-by-side diff view. This helps prevent Language Server Protocol (LSP) crashes that can occur with very large files, particularly affecting C# developers. The changes made by Roo are still visible in the chat window. diff --git a/packages/types/src/experiment.ts b/packages/types/src/experiment.ts index dfb7cca1d5..5c27b0e102 100644 --- a/packages/types/src/experiment.ts +++ b/packages/types/src/experiment.ts @@ -6,7 +6,13 @@ import type { Keys, Equals, AssertEqual } from "./type-fu.js" * ExperimentId */ -export const experimentIds = ["powerSteering", "disableCompletionCommand", "marketplace", "multiFileApplyDiff"] as const +export const experimentIds = [ + "powerSteering", + "disableCompletionCommand", + "marketplace", + "multiFileApplyDiff", + "disableDiffVisualization", +] as const export const experimentIdsSchema = z.enum(experimentIds) @@ -21,6 +27,7 @@ export const experimentsSchema = z.object({ disableCompletionCommand: z.boolean().optional(), marketplace: z.boolean().optional(), multiFileApplyDiff: z.boolean().optional(), + disableDiffVisualization: z.boolean().optional(), }) export type Experiments = z.infer diff --git a/packages/types/src/global-settings.ts b/packages/types/src/global-settings.ts index 4ca50a1200..5b729a125f 100644 --- a/packages/types/src/global-settings.ts +++ b/packages/types/src/global-settings.ts @@ -83,7 +83,6 @@ export const globalSettingsSchema = z.object({ rateLimitSeconds: z.number().optional(), diffEnabled: z.boolean().optional(), - disableDiffVisualization: z.boolean().optional(), fuzzyMatchThreshold: z.number().optional(), experiments: experimentsSchema.optional(), @@ -212,7 +211,6 @@ export const EVALS_SETTINGS: RooCodeSettings = { terminalShellIntegrationDisabled: true, diffEnabled: true, - disableDiffVisualization: false, fuzzyMatchThreshold: 1, enableCheckpoints: false, diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index f73bf1eef0..4a9eb70891 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -529,12 +529,13 @@ export class ClineProvider apiConfiguration, organizationAllowList, diffEnabled: enableDiff, - disableDiffVisualization, enableCheckpoints, fuzzyMatchThreshold, experiments, } = await this.getState() + const disableDiffVisualization = experiments.disableDiffVisualization ?? false + if (!ProfileValidator.isProfileAllowed(apiConfiguration, organizationAllowList)) { throw new OrganizationAllowListViolationError(t("common:errors.violated_organization_allowlist")) } @@ -571,12 +572,13 @@ export class ClineProvider const { apiConfiguration, diffEnabled: enableDiff, - disableDiffVisualization, enableCheckpoints, fuzzyMatchThreshold, experiments, } = await this.getState() + const disableDiffVisualization = experiments.disableDiffVisualization ?? false + const cline = new Task({ provider: this, apiConfiguration, @@ -1550,7 +1552,6 @@ export class ClineProvider ttsEnabled: stateValues.ttsEnabled ?? false, ttsSpeed: stateValues.ttsSpeed ?? 1.0, diffEnabled: stateValues.diffEnabled ?? true, - disableDiffVisualization: stateValues.disableDiffVisualization ?? false, enableCheckpoints: stateValues.enableCheckpoints ?? true, soundVolume: stateValues.soundVolume, browserViewportSize: stateValues.browserViewportSize ?? "900x600", diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index d5a0d9a116..a4d9dafecf 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -645,11 +645,6 @@ export const webviewMessageHandler = async ( await updateGlobalState("diffEnabled", diffEnabled) await provider.postStateToWebview() break - case "disableDiffVisualization": - const disableDiffVisualization = message.bool ?? false - await updateGlobalState("disableDiffVisualization", disableDiffVisualization) - await provider.postStateToWebview() - break case "enableCheckpoints": const enableCheckpoints = message.bool ?? true await updateGlobalState("enableCheckpoints", enableCheckpoints) diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index 2fad358bcc..ac19ba0ef2 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -188,7 +188,6 @@ export type ExtensionState = Pick< | "terminalZdotdir" | "terminalCompressProgressBar" | "diffEnabled" - | "disableDiffVisualization" | "fuzzyMatchThreshold" // | "experiments" // Optional in GlobalSettings, required here. | "language" diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index ea7fcd84ef..5186c716b9 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -82,7 +82,6 @@ export interface WebviewMessage { | "ttsSpeed" | "soundVolume" | "diffEnabled" - | "disableDiffVisualization" | "enableCheckpoints" | "browserViewportSize" | "screenshotQuality" diff --git a/src/shared/__tests__/experiments.test.ts b/src/shared/__tests__/experiments.test.ts index 96b970cf6e..e4dcbe71b0 100644 --- a/src/shared/__tests__/experiments.test.ts +++ b/src/shared/__tests__/experiments.test.ts @@ -30,6 +30,7 @@ describe("experiments", () => { marketplace: false, disableCompletionCommand: false, multiFileApplyDiff: false, + disableDiffVisualization: false, } expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(false) }) @@ -40,6 +41,7 @@ describe("experiments", () => { marketplace: false, disableCompletionCommand: false, multiFileApplyDiff: false, + disableDiffVisualization: false, } expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(true) }) @@ -50,6 +52,7 @@ describe("experiments", () => { marketplace: false, disableCompletionCommand: false, multiFileApplyDiff: false, + disableDiffVisualization: false, } expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(false) }) @@ -70,6 +73,7 @@ describe("experiments", () => { marketplace: false, disableCompletionCommand: false, multiFileApplyDiff: false, + disableDiffVisualization: false, } expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.MARKETPLACE)).toBe(false) }) @@ -80,6 +84,7 @@ describe("experiments", () => { marketplace: true, disableCompletionCommand: false, multiFileApplyDiff: false, + disableDiffVisualization: false, } expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.MARKETPLACE)).toBe(true) }) diff --git a/src/shared/experiments.ts b/src/shared/experiments.ts index 8e71e71ff0..9119bd000e 100644 --- a/src/shared/experiments.ts +++ b/src/shared/experiments.ts @@ -5,6 +5,7 @@ export const EXPERIMENT_IDS = { MULTI_FILE_APPLY_DIFF: "multiFileApplyDiff", DISABLE_COMPLETION_COMMAND: "disableCompletionCommand", POWER_STEERING: "powerSteering", + DISABLE_DIFF_VISUALIZATION: "disableDiffVisualization", } as const satisfies Record type _AssertExperimentIds = AssertEqual>> @@ -20,6 +21,7 @@ export const experimentConfigsMap: Record = { MULTI_FILE_APPLY_DIFF: { enabled: false }, DISABLE_COMPLETION_COMMAND: { enabled: false }, POWER_STEERING: { enabled: false }, + DISABLE_DIFF_VISUALIZATION: { enabled: false }, } export const experimentDefault = Object.fromEntries( diff --git a/webview-ui/src/components/settings/ApiOptions.tsx b/webview-ui/src/components/settings/ApiOptions.tsx index e64aad95e7..905f34a860 100644 --- a/webview-ui/src/components/settings/ApiOptions.tsx +++ b/webview-ui/src/components/settings/ApiOptions.tsx @@ -73,7 +73,7 @@ const ApiOptions = ({ setErrorMessage, }: ApiOptionsProps) => { const { t } = useAppTranslation() - const { organizationAllowList, disableDiffVisualization, setDisableDiffVisualization } = useExtensionState() + const { organizationAllowList } = useExtensionState() const [customHeaders, setCustomHeaders] = useState<[string, string][]>(() => { const headers = apiConfiguration?.openAiHeaders || {} @@ -476,19 +476,8 @@ const ApiOptions = ({ <> { - if (field === "disableDiffVisualization") { - setDisableDiffVisualization(value) - vscode.postMessage({ - type: "disableDiffVisualization", - bool: value, - }) - } else { - setApiConfigurationField(field, value) - } - }} + onChange={(field, value) => setApiConfigurationField(field, value)} /> void + onChange: (field: "diffEnabled" | "fuzzyMatchThreshold", value: any) => void } export const DiffSettingsControl: React.FC = ({ diffEnabled = true, - disableDiffVisualization = false, fuzzyMatchThreshold = 1.0, onChange, }) => { @@ -25,13 +23,6 @@ export const DiffSettingsControl: React.FC = ({ [onChange], ) - const handleDisableDiffVisualizationChange = useCallback( - (e: any) => { - onChange("disableDiffVisualization", e.target.checked) - }, - [onChange], - ) - const handleThresholdChange = useCallback( (newValue: number[]) => { onChange("fuzzyMatchThreshold", newValue[0]) @@ -70,19 +61,6 @@ export const DiffSettingsControl: React.FC = ({ {t("settings:advanced.diff.matchPrecision.description")} - -
- - - {t("settings:advanced.diff.disableVisualization.label")} - - -
- {t("settings:advanced.diff.disableVisualization.description")} -
-
)} diff --git a/webview-ui/src/components/settings/SettingsView.tsx b/webview-ui/src/components/settings/SettingsView.tsx index 71509f32a6..5a330c8996 100644 --- a/webview-ui/src/components/settings/SettingsView.tsx +++ b/webview-ui/src/components/settings/SettingsView.tsx @@ -139,7 +139,6 @@ const SettingsView = forwardRef(({ onDone, t browserViewportSize, enableCheckpoints, diffEnabled, - disableDiffVisualization, experiments, fuzzyMatchThreshold, maxOpenTabsContext, @@ -281,7 +280,6 @@ const SettingsView = forwardRef(({ onDone, t vscode.postMessage({ type: "ttsSpeed", value: ttsSpeed }) vscode.postMessage({ type: "soundVolume", value: soundVolume }) vscode.postMessage({ type: "diffEnabled", bool: diffEnabled }) - vscode.postMessage({ type: "disableDiffVisualization", bool: disableDiffVisualization }) vscode.postMessage({ type: "enableCheckpoints", bool: enableCheckpoints }) vscode.postMessage({ type: "browserViewportSize", text: browserViewportSize }) vscode.postMessage({ type: "remoteBrowserHost", text: remoteBrowserHost }) diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx index f18ce909bd..ab79f63df8 100644 --- a/webview-ui/src/context/ExtensionStateContext.tsx +++ b/webview-ui/src/context/ExtensionStateContext.tsx @@ -68,7 +68,6 @@ export interface ExtensionStateContextType extends ExtensionState { setTtsEnabled: (value: boolean) => void setTtsSpeed: (value: number) => void setDiffEnabled: (value: boolean) => void - setDisableDiffVisualization: (value: boolean) => void setEnableCheckpoints: (value: boolean) => void setBrowserViewportSize: (value: string) => void setFuzzyMatchThreshold: (value: number) => void @@ -155,7 +154,6 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode ttsEnabled: false, ttsSpeed: 1.0, diffEnabled: false, - disableDiffVisualization: false, enableCheckpoints: true, fuzzyMatchThreshold: 1.0, language: "en", // Default language code @@ -344,8 +342,6 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode setTtsEnabled: (value) => setState((prevState) => ({ ...prevState, ttsEnabled: value })), setTtsSpeed: (value) => setState((prevState) => ({ ...prevState, ttsSpeed: value })), setDiffEnabled: (value) => setState((prevState) => ({ ...prevState, diffEnabled: value })), - setDisableDiffVisualization: (value) => - setState((prevState) => ({ ...prevState, disableDiffVisualization: value })), setEnableCheckpoints: (value) => setState((prevState) => ({ ...prevState, enableCheckpoints: value })), setBrowserViewportSize: (value: string) => setState((prevState) => ({ ...prevState, browserViewportSize: value })), diff --git a/webview-ui/src/context/__tests__/ExtensionStateContext.test.tsx b/webview-ui/src/context/__tests__/ExtensionStateContext.test.tsx index b8a6cadf98..6f2ff25a13 100644 --- a/webview-ui/src/context/__tests__/ExtensionStateContext.test.tsx +++ b/webview-ui/src/context/__tests__/ExtensionStateContext.test.tsx @@ -223,9 +223,9 @@ describe("mergeExtensionState", () => { experiments: { powerSteering: true, marketplace: false, - concurrentFileReads: true, disableCompletionCommand: false, multiFileApplyDiff: true, + disableDiffVisualization: false, } as Record, } @@ -239,9 +239,9 @@ describe("mergeExtensionState", () => { expect(result.experiments).toEqual({ powerSteering: true, marketplace: false, - concurrentFileReads: true, disableCompletionCommand: false, multiFileApplyDiff: true, + disableDiffVisualization: false, }) }) }) diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index a4a2ce5a5b..9dd3d1f2b6 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -469,10 +469,6 @@ "matchPrecision": { "label": "Match precision", "description": "This slider controls how precisely code sections must match when applying diffs. Lower values allow more flexible matching but increase the risk of incorrect replacements. Use values below 100% with extreme caution." - }, - "disableVisualization": { - "label": "Disable diff visualization", - "description": "When enabled, files will open directly in the editor instead of showing a diff view. This can prevent LSP crashes with very large files. You can still see the changes in the chat window." } } }, @@ -512,6 +508,10 @@ "MULTI_FILE_APPLY_DIFF": { "name": "Enable concurrent file edits", "description": "When enabled, Roo can edit multiple files in a single request. When disabled, Roo must edit files one at a time. Disabling this can help when working with less capable models or when you want more control over file modifications." + }, + "DISABLE_DIFF_VISUALIZATION": { + "name": "Disable diff visualization for all edit tools", + "description": "When enabled, files will open directly in the editor instead of showing a diff view for all edit tools (write_to_file, apply_diff, insert_content, search_and_replace). This helps prevent LSP crashes with very large files. Changes are still visible in the chat window." } }, "promptCaching": {