-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Feat/improve-tab-focus #2908
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat/improve-tab-focus #2908
Conversation
- Maintains editor view column state when closing and reopening files during diff operations, ensuring tabs stay opened in their original position. - Prevents closing the original editor tab when opening the diff view, preserving pinned status when applying changes via write_to_file or apply_diff. - Updates VSCode workspace launch flag from -n to -W for compatibility.
Enhances focus management when opening and closing diff views by: - Tracking the user's initially focused editor - Adding proper focus restoration logic with fallbacks - Implementing better handling for new files Introduces a more robust focus restoration system that prioritizes returning to the originally focused editor while maintaining fallback behavior for edge cases.
|
|
FYI, I started on this but haven't gotten to making a PR. Since you have, thanks for taking this on! Notes: viewColumn: vscode.ViewColumn.Active,This keeps roo tabs that are pulled off in another window together w/ the editor tabs preserveFocus: trueUseful when auto-approve write is enabled to keep from stealing focus Here is my diff if its usefuldiff --git a/src/integrations/editor/DiffViewProvider.ts b/src/integrations/editor/DiffViewProvider.ts
index 0bf49485..7634a0cd 100644
--- a/src/integrations/editor/DiffViewProvider.ts
+++ b/src/integrations/editor/DiffViewProvider.ts
@@ -8,6 +8,7 @@ import { DecorationController } from "./DecorationController"
import * as diff from "diff"
import { diagnosticsToProblemsString, getNewDiagnostics } from "../diagnostics"
import stripBom from "strip-bom"
+import { ClineProvider } from "../../core/webview/ClineProvider"
export const DIFF_VIEW_URI_SCHEME = "cline-diff"
@@ -20,6 +21,7 @@ export class DiffViewProvider {
private relPath?: string
private newContent?: string
private activeDiffEditor?: vscode.TextEditor
+ private savedEditor?: { editor: vscode.TextEditor; selection: vscode.Selection }
private fadedOverlayController?: DecorationController
private activeLineController?: DecorationController
private streamedLines: string[] = []
@@ -156,9 +158,21 @@ export class DiffViewProvider {
await updatedDocument.save()
}
- await vscode.window.showTextDocument(vscode.Uri.file(absolutePath), { preview: false })
- await this.closeAllDiffViews()
+ await vscode.window.showTextDocument(vscode.Uri.file(absolutePath), {
+ preview: false,
+ viewColumn: vscode.ViewColumn.Active,
+ preserveFocus: true,
+ })
+ // Restore the editor that was active when diff was opened
+ if (this.savedEditor) {
+ await vscode.window.showTextDocument(this.savedEditor.editor.document, {
+ selection: this.savedEditor.selection
+ })
+ // Clear saved editor after restoring
+ this.savedEditor = undefined
+ }
+ await this.closeAllDiffViews()
/*
Getting diagnostics before and after the file edit is a better approach than
automatically tracking problems in real-time. This method ensures we only
@@ -269,6 +283,15 @@ export class DiffViewProvider {
if (!this.relPath) {
throw new Error("No file path set")
}
+ const provider = ClineProvider.getVisibleInstance()
+ const preserveFocus = provider?.getValue("autoApprovalEnabled") && provider?.getValue("alwaysAllowWrite")
+ // Store current editor before opening diff
+ if (vscode.window.activeTextEditor) {
+ this.savedEditor = {
+ editor: vscode.window.activeTextEditor,
+ selection: vscode.window.activeTextEditor.selection
+ }
+ }
const uri = vscode.Uri.file(path.resolve(this.cwd, this.relPath))
// If this diff editor is already open (ie if a previous write file was interrupted) then we should activate that instead of opening a new diff
const diffTab = vscode.window.tabGroups.all
@@ -280,15 +303,25 @@ export class DiffViewProvider {
arePathsEqual(tab.input.modified.fsPath, uri.fsPath),
)
if (diffTab && diffTab.input instanceof vscode.TabInputTextDiff) {
- const editor = await vscode.window.showTextDocument(diffTab.input.modified)
+ const currentEditor = vscode.window.activeTextEditor
+ const editor = await vscode.window.showTextDocument(diffTab.input.modified, {
+ viewColumn: vscode.ViewColumn.Active,
+ preserveFocus,
+ })
+ if (currentEditor) {
+ await vscode.window.showTextDocument(currentEditor.document, {
+ selection: currentEditor.selection,
+ })
+ }
return editor
}
// Open new diff editor
return new Promise<vscode.TextEditor>((resolve, reject) => {
const fileName = path.basename(uri.fsPath)
const fileExists = this.editType === "modify"
- const disposable = vscode.window.onDidChangeActiveTextEditor((editor) => {
- if (editor && arePathsEqual(editor.document.uri.fsPath, uri.fsPath)) {
+ const disposable = vscode.window.onDidChangeVisibleTextEditors((editors) => {
+ const editor = editors.find((e) => arePathsEqual(e.document.uri.fsPath, uri.fsPath))
+ if (editor) {
disposable.dispose()
resolve(editor)
}
@@ -300,6 +333,7 @@ export class DiffViewProvider {
}),
uri,
`${fileName}: ${fileExists ? "Original ↔ Roo's Changes" : "New File"} (Editable)`,
+ { preserveFocus: true, viewColumn: vscode.ViewColumn.Active },
)
// This may happen on very slow machines ie project idx
setTimeout(() => { |
|
there is another PR that addresses that focus behaviour |
|
This may duplicate #2122 |
Enhance Diff View Focus and Tab State Management
Enhances focus and tab state management when opening and closing diff views by:
Introduces a more robust focus and state restoration system that prioritizes returning to the originally focused editor and restoring the original tab's state (pinning/position), while maintaining fallback behavior for edge cases and ensuring stability.
Context
When Roo opens a diff view to apply changes (
apply_diff,write_to_file), the focus management and tab handling could be disruptive. Previously, the focus would always jump to the diff editor and, upon completion, often land on the modified file's tab, even if the user was focused elsewhere initially. Furthermore, if the original file tab was pinned, it would lose its pinned status and its position within the tab group after the diff operation. Additionally, newly created files were not reliably opened or focused after the diff was accepted. This PR aims to improve the user experience by making focus transitions more predictable, preserving the original tab's state (pinning and position), and ensuring newly created files are handled correctly.Implementation
The core changes were made within
src/integrations/editor/DiffViewProvider.ts:openmethod, before the diff editor is opened:uriandviewColumnof thevscode.window.activeTextEditor(if one exists) are stored inuserFocusedEditorInfo.uri,isPinnedstatus,viewColumn, andindex(position within the group) are stored inoriginalTabStatebefore the tab is closed.openDiffEditor:viewColumnstored inoriginalTabState(or a fallback).originalTabStateindicates the original tab was pinned, the commandworkbench.action.pinEditoris executed to pin the diff view itself. Then, the commandmoveActiveEditoris executed to move the (potentially newly pinned) diff view to theindexstored inoriginalTabState.saveChangesandrevertChanges, after closing the diff view, a new method_restoreOriginalTabStateis called iforiginalTabStateexists._restoreOriginalTabState: This method re-opens the original document in the correctviewColumn. It then usesworkbench.action.pinEditorto restore the pinned status andmoveActiveEditorto restore the originalindex(position). Finally, it handles restoring focus either to the originally focused editor (if different) or keeps focus on the restored tab._focusOriginalDocument): This method is now primarily used as a fallback whenoriginalTabStatedoes not exist (e.g., for new files or files not previously open).userFocusedEditorInfoif available.!this.documentWasOpen).originalTabStatewasn't set, which shouldn't happen anymore for open files) was removed as_restoreOriginalTabStatecovers this.userFocusedEditorInforemainsundefined. In this case, after the diff, VS Code's default behavior takes over (typically focusing the last active editor).These changes build upon the structural improvements made in the separate
refactor/extract-focus-logicbranch and incorporate the fix for preserving tab state.Screenshots
Changes are behavioral regarding editor focus and tab state.
How to Test
Setup: Ensure
"workbench.editor.pinnedTabsOnSeparateRow": trueis set in VS Code settings for easier observation of pinning.Test the following scenarios:
Get in Touch
Discord:
seed92(via https://discord.com/users/201009672675786752)Important
Enhance focus management in
DiffViewProvider.tsby prioritizing original editor focus restoration and handling new files, with a command update inindex.ts.DiffViewProvider.ts:open()method usinguserFocusedEditorInfo._focusOriginalDocument().This description was created by