feat: add setting to disable diff visualization to prevent LSP crashes

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.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
hannesrudolph 2025-06-16 13:10:31 -06:00
parent 2e2f83be60
commit 9e5c504c1c
13 changed files with 81 additions and 6 deletions

View file

@ -0,0 +1,7 @@
---
"roo-cline": patch
---
Add setting to disable diff visualization to prevent LSP crashes
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.

View file

@ -83,6 +83,7 @@ export const globalSettingsSchema = z.object({
rateLimitSeconds: z.number().optional(),
diffEnabled: z.boolean().optional(),
disableDiffVisualization: z.boolean().optional(),
fuzzyMatchThreshold: z.number().optional(),
experiments: experimentsSchema.optional(),
@ -211,6 +212,7 @@ export const EVALS_SETTINGS: RooCodeSettings = {
terminalShellIntegrationDisabled: true,
diffEnabled: true,
disableDiffVisualization: false,
fuzzyMatchThreshold: 1,
enableCheckpoints: false,

View file

@ -104,6 +104,7 @@ export type TaskOptions = {
provider: ClineProvider
apiConfiguration: ProviderSettings
enableDiff?: boolean
disableDiffVisualization?: boolean
enableCheckpoints?: boolean
fuzzyMatchThreshold?: number
consecutiveMistakeLimit?: number
@ -198,6 +199,7 @@ export class Task extends EventEmitter<ClineEvents> {
provider,
apiConfiguration,
enableDiff = false,
disableDiffVisualization = false,
enableCheckpoints = true,
fuzzyMatchThreshold = 1.0,
consecutiveMistakeLimit = 3,
@ -242,7 +244,7 @@ export class Task extends EventEmitter<ClineEvents> {
this.consecutiveMistakeLimit = consecutiveMistakeLimit
this.providerRef = new WeakRef(provider)
this.globalStoragePath = provider.context.globalStorageUri.fsPath
this.diffViewProvider = new DiffViewProvider(this.cwd)
this.diffViewProvider = new DiffViewProvider(this.cwd, disableDiffVisualization)
this.enableCheckpoints = enableCheckpoints
this.rootTask = rootTask

View file

@ -529,6 +529,7 @@ export class ClineProvider
apiConfiguration,
organizationAllowList,
diffEnabled: enableDiff,
disableDiffVisualization,
enableCheckpoints,
fuzzyMatchThreshold,
experiments,
@ -542,6 +543,7 @@ export class ClineProvider
provider: this,
apiConfiguration,
enableDiff,
disableDiffVisualization,
enableCheckpoints,
fuzzyMatchThreshold,
task,
@ -569,6 +571,7 @@ export class ClineProvider
const {
apiConfiguration,
diffEnabled: enableDiff,
disableDiffVisualization,
enableCheckpoints,
fuzzyMatchThreshold,
experiments,
@ -578,6 +581,7 @@ export class ClineProvider
provider: this,
apiConfiguration,
enableDiff,
disableDiffVisualization,
enableCheckpoints,
fuzzyMatchThreshold,
historyItem,
@ -1546,6 +1550,7 @@ 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",

View file

@ -645,6 +645,11 @@ 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)

View file

@ -34,7 +34,10 @@ export class DiffViewProvider {
private streamedLines: string[] = []
private preDiagnostics: [vscode.Uri, vscode.Diagnostic[]][] = []
constructor(private cwd: string) {}
constructor(
private cwd: string,
private disableDiffVisualization: boolean = false,
) {}
async open(relPath: string): Promise<void> {
this.relPath = relPath
@ -92,7 +95,13 @@ export class DiffViewProvider {
this.documentWasOpen = true
}
this.activeDiffEditor = await this.openDiffEditor()
// If diff visualization is disabled, open the file directly
if (this.disableDiffVisualization) {
const document = await vscode.workspace.openTextDocument(absolutePath)
this.activeDiffEditor = await vscode.window.showTextDocument(document, { preview: false })
} else {
this.activeDiffEditor = await this.openDiffEditor()
}
this.fadedOverlayController = new DecorationController("fadedOverlay", this.activeDiffEditor)
this.activeLineController = new DecorationController("activeLine", this.activeDiffEditor)
// Apply faded overlay to all lines initially.

View file

@ -188,6 +188,7 @@ export type ExtensionState = Pick<
| "terminalZdotdir"
| "terminalCompressProgressBar"
| "diffEnabled"
| "disableDiffVisualization"
| "fuzzyMatchThreshold"
// | "experiments" // Optional in GlobalSettings, required here.
| "language"

View file

@ -82,6 +82,7 @@ export interface WebviewMessage {
| "ttsSpeed"
| "soundVolume"
| "diffEnabled"
| "disableDiffVisualization"
| "enableCheckpoints"
| "browserViewportSize"
| "screenshotQuality"

View file

@ -73,7 +73,7 @@ const ApiOptions = ({
setErrorMessage,
}: ApiOptionsProps) => {
const { t } = useAppTranslation()
const { organizationAllowList } = useExtensionState()
const { organizationAllowList, disableDiffVisualization, setDisableDiffVisualization } = useExtensionState()
const [customHeaders, setCustomHeaders] = useState<[string, string][]>(() => {
const headers = apiConfiguration?.openAiHeaders || {}
@ -476,8 +476,19 @@ const ApiOptions = ({
<>
<DiffSettingsControl
diffEnabled={apiConfiguration.diffEnabled}
disableDiffVisualization={disableDiffVisualization}
fuzzyMatchThreshold={apiConfiguration.fuzzyMatchThreshold}
onChange={(field, value) => setApiConfigurationField(field, value)}
onChange={(field, value) => {
if (field === "disableDiffVisualization") {
setDisableDiffVisualization(value)
vscode.postMessage({
type: "disableDiffVisualization",
bool: value,
})
} else {
setApiConfigurationField(field, value)
}
}}
/>
<TemperatureControl
value={apiConfiguration.modelTemperature}

View file

@ -5,12 +5,14 @@ import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
interface DiffSettingsControlProps {
diffEnabled?: boolean
disableDiffVisualization?: boolean
fuzzyMatchThreshold?: number
onChange: (field: "diffEnabled" | "fuzzyMatchThreshold", value: any) => void
onChange: (field: "diffEnabled" | "disableDiffVisualization" | "fuzzyMatchThreshold", value: any) => void
}
export const DiffSettingsControl: React.FC<DiffSettingsControlProps> = ({
diffEnabled = true,
disableDiffVisualization = false,
fuzzyMatchThreshold = 1.0,
onChange,
}) => {
@ -23,6 +25,13 @@ export const DiffSettingsControl: React.FC<DiffSettingsControlProps> = ({
[onChange],
)
const handleDisableDiffVisualizationChange = useCallback(
(e: any) => {
onChange("disableDiffVisualization", e.target.checked)
},
[onChange],
)
const handleThresholdChange = useCallback(
(newValue: number[]) => {
onChange("fuzzyMatchThreshold", newValue[0])
@ -61,6 +70,19 @@ export const DiffSettingsControl: React.FC<DiffSettingsControlProps> = ({
{t("settings:advanced.diff.matchPrecision.description")}
</div>
</div>
<div>
<VSCodeCheckbox
checked={disableDiffVisualization}
onChange={handleDisableDiffVisualizationChange}>
<span className="font-medium">
{t("settings:advanced.diff.disableVisualization.label")}
</span>
</VSCodeCheckbox>
<div className="text-vscode-descriptionForeground text-sm">
{t("settings:advanced.diff.disableVisualization.description")}
</div>
</div>
</div>
)}
</div>

View file

@ -139,6 +139,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
browserViewportSize,
enableCheckpoints,
diffEnabled,
disableDiffVisualization,
experiments,
fuzzyMatchThreshold,
maxOpenTabsContext,
@ -280,6 +281,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ 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 })

View file

@ -68,6 +68,7 @@ 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
@ -154,6 +155,7 @@ 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
@ -342,6 +344,8 @@ 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 })),

View file

@ -469,6 +469,10 @@
"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."
}
}
},