Skip to content

Commit ede228e

Browse files
fix: prevent chatbox focus loss during automated file editing (#4574) (#5349)
* fix: prevent chatbox focus loss during automated file editing (#4574) - Add preserveFocus: true to DiffViewProvider openDiffEditor method - Implement comprehensive focus preservation during cursor positioning and scrolling - Make scrollToFirstDiff async with focus restoration capabilities - Update all tool files to use async scrollToFirstDiff - Add comprehensive unit and E2E tests for focus preservation Fixes #4574 * refactor: extract focus restoration logic and improve consistency - Created restoreEditorFocus() helper method to eliminate code duplication - Changed preserveFocus from false to true for consistent behavior - Added error handling with silent logging for focus restoration failures - Added null checks for undefined activeTextEditor cases * Delete apps/vscode-e2e/src/suite/tools/focus-preservation.test.ts It doesn't seem to be testing anything * refactor: remove focus restoration logic to simplify diff editor interactions * refactor: remove unnecessary await from scrollToFirstDiff calls --------- Co-authored-by: Daniel <[email protected]> Co-authored-by: Daniel Riccio <[email protected]>
1 parent e508eaf commit ede228e

File tree

4 files changed

+9
-9
lines changed

4 files changed

+9
-9
lines changed

src/core/tools/applyDiffTool.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ export async function applyDiffToolLegacy(
145145
cline.diffViewProvider.editType = "modify"
146146
await cline.diffViewProvider.open(relPath)
147147
await cline.diffViewProvider.update(diffResult.content, true)
148-
await cline.diffViewProvider.scrollToFirstDiff()
148+
cline.diffViewProvider.scrollToFirstDiff()
149149

150150
// Check if file is write-protected
151151
const isWriteProtected = cline.rooProtectedController?.isWriteProtected(relPath) || false

src/core/tools/multiApplyDiffTool.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ ${errorDetails ? `\nTechnical details:\n${errorDetails}\n` : ""}
505505
cline.diffViewProvider.editType = "modify"
506506
await cline.diffViewProvider.open(relPath)
507507
await cline.diffViewProvider.update(originalContent!, true)
508-
await cline.diffViewProvider.scrollToFirstDiff()
508+
cline.diffViewProvider.scrollToFirstDiff()
509509

510510
// For batch operations, we've already gotten approval
511511
const isWriteProtected = cline.rooProtectedController?.isWriteProtected(relPath) || false

src/integrations/editor/DiffViewProvider.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ export class DiffViewProvider {
122122
}
123123

124124
// Place cursor at the beginning of the diff editor to keep it out of
125-
// the way of the stream animation.
125+
// the way of the stream animation, but do this without stealing focus
126126
const beginningOfDocument = new vscode.Position(0, 0)
127127
diffEditor.selection = new vscode.Selection(beginningOfDocument, beginningOfDocument)
128128

@@ -137,7 +137,7 @@ export class DiffViewProvider {
137137
// Update decorations.
138138
this.activeLineController.setActiveLine(endLine)
139139
this.fadedOverlayController.updateOverlayAfterLine(endLine, document.lineCount)
140-
// Scroll to the current line.
140+
// Scroll to the current line without stealing focus.
141141
const ranges = this.activeDiffEditor?.visibleRanges
142142
if (ranges && ranges.length > 0 && ranges[0].start.line < endLine && ranges[0].end.line > endLine) {
143143
this.scrollEditorToLine(endLine)
@@ -504,7 +504,7 @@ export class DiffViewProvider {
504504
// Pre-open the file as a text document to ensure it doesn't open in preview mode
505505
// This fixes issues with files that have custom editor associations (like markdown preview)
506506
vscode.window
507-
.showTextDocument(uri, { preview: false, viewColumn: vscode.ViewColumn.Active })
507+
.showTextDocument(uri, { preview: false, viewColumn: vscode.ViewColumn.Active, preserveFocus: true })
508508
.then(() => {
509509
// Execute the diff command after ensuring the file is open as text
510510
return vscode.commands.executeCommand(
@@ -552,7 +552,7 @@ export class DiffViewProvider {
552552

553553
for (const part of diffs) {
554554
if (part.added || part.removed) {
555-
// Found the first diff, scroll to it.
555+
// Found the first diff, scroll to it without stealing focus.
556556
this.activeDiffEditor.revealRange(
557557
new vscode.Range(lineCount, 0, lineCount, 0),
558558
vscode.TextEditorRevealType.InCenter,

src/integrations/editor/__tests__/DiffViewProvider.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ describe("DiffViewProvider", () => {
176176
// Mock showTextDocument to track when it's called
177177
vi.mocked(vscode.window.showTextDocument).mockImplementation(async (uri, options) => {
178178
callOrder.push("showTextDocument")
179-
expect(options).toEqual({ preview: false, viewColumn: vscode.ViewColumn.Active })
179+
expect(options).toEqual({ preview: false, viewColumn: vscode.ViewColumn.Active, preserveFocus: true })
180180
return mockEditor as any
181181
})
182182

@@ -208,10 +208,10 @@ describe("DiffViewProvider", () => {
208208
// Verify that showTextDocument was called before executeCommand
209209
expect(callOrder).toEqual(["showTextDocument", "executeCommand"])
210210

211-
// Verify that showTextDocument was called with preview: false
211+
// Verify that showTextDocument was called with preview: false and preserveFocus: true
212212
expect(vscode.window.showTextDocument).toHaveBeenCalledWith(
213213
expect.objectContaining({ fsPath: `${mockCwd}/test.md` }),
214-
{ preview: false, viewColumn: vscode.ViewColumn.Active },
214+
{ preview: false, viewColumn: vscode.ViewColumn.Active, preserveFocus: true },
215215
)
216216

217217
// Verify that the diff command was executed

0 commit comments

Comments
 (0)