@@ -45,6 +45,7 @@ export class DiffViewProvider {
4545 private viewColumn : ViewColumn = - 1 // ViewColumn.Active
4646 private userInteractionListeners : vscode . Disposable [ ] = [ ]
4747 private suppressInteractionFlag : boolean = false
48+ private preDiffActiveEditor ?: vscode . TextEditor // Store active editor before diff operation
4849
4950 constructor ( private cwd : string ) { }
5051
@@ -185,6 +186,9 @@ export class DiffViewProvider {
185186 * @param viewColumn (Optional) The VSCode editor group to open the diff in.
186187 */
187188 async open ( relPath : string , viewColumn : ViewColumn ) : Promise < void > {
189+ // Store the pre-diff active editor for potential focus restoration
190+ this . preDiffActiveEditor = vscode . window . activeTextEditor
191+
188192 this . viewColumn = viewColumn
189193 this . disableAutoFocusAfterUserInteraction ( )
190194 // Set the edit type based on the file existence
@@ -253,6 +257,51 @@ export class DiffViewProvider {
253257 this . streamedLines = [ ]
254258 }
255259
260+ /**
261+ * Prepares the optimal view column and placement for the diff view.
262+ * For existing open files: Places diff beside the original tab in the same group.
263+ * For new/unopened files: Places at the end of the currently active editor group.
264+ */
265+ private async prepareDiffViewPlacement ( absolutePath : string ) : Promise < void > {
266+ if ( ! this . documentWasOpen ) {
267+ return Promise . resolve ( )
268+ }
269+ // For existing files that are currently open, find the original tab
270+ const originalTab = this . findTabForFile ( absolutePath )
271+ if ( originalTab ) {
272+ // Find the tab group containing the original tab
273+ const tabGroup = vscode . window . tabGroups . all . find ( ( group ) => group . tabs . some ( ( tab ) => tab === originalTab ) )
274+
275+ if ( tabGroup ) {
276+ const viewColumn = this . viewColumn !== ViewColumn . Active ? tabGroup . viewColumn : this . viewColumn
277+ // Ensure the original tab is active within its group to place diff beside it
278+ await this . showTextDocumentSafe ( {
279+ uri : vscode . Uri . file ( absolutePath ) ,
280+ options : {
281+ viewColumn : viewColumn ,
282+ preserveFocus : true ,
283+ preview : false ,
284+ } ,
285+ } )
286+ // Update viewColumn to match the original file's group
287+ this . viewColumn = viewColumn
288+ }
289+ }
290+ // For new files or unopened files, keep the original viewColumn (active group)
291+ // No additional preparation needed as it will default to end of active group
292+ }
293+
294+ /**
295+ * Finds the VS Code tab for a given file path.
296+ */
297+ private findTabForFile ( absolutePath : string ) : vscode . Tab | undefined {
298+ return vscode . window . tabGroups . all
299+ . flatMap ( ( group ) => group . tabs )
300+ . find (
301+ ( tab ) => tab . input instanceof vscode . TabInputText && arePathsEqual ( tab . input . uri . fsPath , absolutePath ) ,
302+ )
303+ }
304+
256305 /**
257306 * Opens a file editor and tracks it as opened by Roo if not already open.
258307 */
@@ -384,6 +433,9 @@ export class DiffViewProvider {
384433
385434 await this . closeAllRooOpenedViews ( )
386435
436+ // Implement post-diff focus behavior
437+ await this . handlePostDiffFocus ( )
438+
387439 // If no auto-close settings are enabled and the document was not open before,
388440 // open the file after the diff is complete.
389441
@@ -502,11 +554,98 @@ export class DiffViewProvider {
502554 await this . closeAllRooOpenedViews ( )
503555 }
504556
557+ // Implement post-diff focus behavior
558+ await this . handlePostDiffFocus ( )
559+
505560 // Edit is done.
506561 this . resetWithListeners ( )
507562 }
508563
509- private filterTabsToClose ( tab : vscode . Tab , settings : DiffSettings ) : boolean {
564+ /**
565+ * Handles post-diff focus behavior.
566+ * Currently defaults to focusing the edited file (Behavior A).
567+ * Future implementation will support configurable focus behavior.
568+ */
569+ private async handlePostDiffFocus ( ) : Promise < void > {
570+ if ( ! this . relPath ) {
571+ return
572+ }
573+
574+ if ( this . autoCloseAllRooTabs ) {
575+ // Focus on the pre-diff active tab
576+ await this . focusOnPreDiffActiveTab ( )
577+ return
578+ }
579+ // Focus on the edited file (temporary default)
580+ await this . focusOnEditedFile ( )
581+ }
582+
583+ /**
584+ * Focuses on the tab of the file that was just edited.
585+ */
586+ private async focusOnEditedFile ( ) : Promise < void > {
587+ if ( ! this . relPath ) {
588+ return
589+ }
590+
591+ try {
592+ const absolutePath = path . resolve ( this . cwd , this . relPath )
593+ const fileUri = vscode . Uri . file ( absolutePath )
594+
595+ // Check if the file still exists as a tab
596+ const editedFileTab = this . findTabForFile ( absolutePath )
597+ if ( editedFileTab ) {
598+ // Find the tab group containing the edited file
599+ const tabGroup = vscode . window . tabGroups . all . find ( ( group ) =>
600+ group . tabs . some ( ( tab ) => tab === editedFileTab ) ,
601+ )
602+
603+ if ( tabGroup ) {
604+ // Make the edited file's tab active
605+ await this . showTextDocumentSafe ( {
606+ uri : fileUri ,
607+ options : {
608+ viewColumn : tabGroup . viewColumn ,
609+ preserveFocus : false ,
610+ preview : false ,
611+ } ,
612+ } )
613+ }
614+ }
615+ } catch ( error ) {
616+ console . error ( "Roo Debug: Error focusing on edited file:" , error )
617+ }
618+ }
619+
620+ /**
621+ * Restores focus to the tab that was active before the diff operation.
622+ * This method is prepared for future use when configurable focus behavior is implemented.
623+ */
624+ private async focusOnPreDiffActiveTab ( ) : Promise < void > {
625+ if ( ! this . preDiffActiveEditor || ! this . preDiffActiveEditor . document ) {
626+ return
627+ }
628+
629+ try {
630+ // Check if the pre-diff active editor is still valid and its document is still open
631+ const isDocumentStillOpen = vscode . workspace . textDocuments . some (
632+ ( doc ) => doc === this . preDiffActiveEditor ! . document ,
633+ )
634+
635+ if ( isDocumentStillOpen ) {
636+ // Restore focus to the pre-diff active editor
637+ await vscode . window . showTextDocument ( this . preDiffActiveEditor . document . uri , {
638+ viewColumn : this . preDiffActiveEditor . viewColumn ,
639+ preserveFocus : false ,
640+ preview : false ,
641+ } )
642+ }
643+ } catch ( error ) {
644+ console . error ( "Roo Debug: Error restoring focus to pre-diff active tab:" , error )
645+ }
646+ }
647+
648+ private tabToCloseFilter ( tab : vscode . Tab , settings : DiffSettings ) : boolean {
510649 // Always close DiffView tabs opened by Roo
511650 if ( tab . input instanceof vscode . TabInputTextDiff && tab . input ?. original ?. scheme === DIFF_VIEW_URI_SCHEME ) {
512651 return true
@@ -622,7 +761,7 @@ export class DiffViewProvider {
622761
623762 const closeOps = vscode . window . tabGroups . all
624763 . flatMap ( ( tg ) => tg . tabs )
625- . filter ( ( tab ) => this . filterTabsToClose ( tab , settings ) )
764+ . filter ( ( tab ) => this . tabToCloseFilter ( tab , settings ) )
626765 . map ( this . closeTab )
627766
628767 await Promise . all ( closeOps )
@@ -640,7 +779,6 @@ export class DiffViewProvider {
640779
641780 // right uri = the file path
642781 const rightUri = vscode . Uri . file ( path . resolve ( this . cwd , this . relPath ) )
643-
644782 // Open new diff editor.
645783 return new Promise < vscode . TextEditor > ( ( resolve , reject ) => {
646784 const fileName = path . basename ( rightUri . fsPath )
@@ -657,44 +795,61 @@ export class DiffViewProvider {
657795 }
658796 // set interaction flag to true to prevent autoFocus from being triggered
659797 this . suppressInteractionFlag = true
660- vscode . commands
661- . executeCommand ( "vscode.diff" , leftUri , rightUri , title , textDocumentShowOptions )
662- . then ( async ( ) => {
663- // set interaction flag to false to allow autoFocus to be triggered
664- this . suppressInteractionFlag = false
665-
666- // Get the active text editor, which should be the diff editor opened by vscode.diff
667- const diffEditor = vscode . window . activeTextEditor
668-
669- // Ensure we have a valid editor and it's the one we expect (the right side of the diff)
670- if ( ! diffEditor || ! arePathsEqual ( diffEditor . document . uri . fsPath , rightUri . fsPath ) ) {
671- reject ( new Error ( "Failed to get diff editor after opening." ) )
672- return
673- }
798+ // Implement improved diff view placement logic
799+ const previousEditor = vscode . window . activeTextEditor
800+ this . prepareDiffViewPlacement ( rightUri . fsPath ) . then ( ( ) => {
801+ vscode . commands
802+ . executeCommand ( "vscode.diff" , leftUri , rightUri , title , textDocumentShowOptions )
803+ . then ( async ( ) => {
804+ // set interaction flag to false to allow autoFocus to be triggered
805+ this . suppressInteractionFlag = false
806+
807+ // Get the active text editor, which should be the diff editor opened by vscode.diff
808+ const diffEditor = vscode . window . activeTextEditor
809+
810+ // Ensure we have a valid editor and it's the one we expect (the right side of the diff)
811+ if ( ! diffEditor || ! arePathsEqual ( diffEditor . document . uri . fsPath , rightUri . fsPath ) ) {
812+ reject ( new Error ( "Failed to get diff editor after opening." ) )
813+ return
814+ }
674815
675- this . activeDiffEditor = diffEditor // Assign to activeDiffEditor
816+ this . activeDiffEditor = diffEditor // Assign to activeDiffEditor
676817
677- // Ensure rightUri is tracked even if not explicitly shown again
678- this . rooOpenedTabs . add ( rightUri . toString ( ) )
818+ // Ensure rightUri is tracked even if not explicitly shown again
819+ this . rooOpenedTabs . add ( rightUri . toString ( ) )
679820
680- // If autoFocus is disabled, explicitly clear the selection to prevent cursor focus.
681- if ( ! settings . autoFocus ) {
682- // Use dynamically read autoFocus
683- // Add a small delay to allow VS Code to potentially set focus first,
684- // then clear it.
685- await new Promise ( ( resolve ) => setTimeout ( resolve , 50 ) )
686- const beginningOfDocument = new vscode . Position ( 0 , 0 )
687- diffEditor . selection = new vscode . Selection ( beginningOfDocument , beginningOfDocument )
688- }
821+ // If autoFocus is disabled, explicitly clear the selection to prevent cursor focus.
822+ if ( ! settings . autoFocus ) {
823+ // Use dynamically read autoFocus
824+ // Add a small delay to allow VS Code to potentially set focus first,
825+ // then clear it.
826+ await new Promise ( ( resolve ) => setTimeout ( resolve , 50 ) )
827+ const beginningOfDocument = new vscode . Position ( 0 , 0 )
828+ diffEditor . selection = new vscode . Selection ( beginningOfDocument , beginningOfDocument )
829+ }
689830
690- // Resolve the promise with the diff editor
691- resolve ( diffEditor )
692- } )
693- // Removed the second .then block that called getEditorFromDiffTab
694- // This may happen on very slow machines ie project idx
695- setTimeout ( ( ) => {
696- reject ( new Error ( "Failed to open diff editor, please try again..." ) )
697- } , 10_000 )
831+ // if this happens in a window different from the active one, we need to show the document
832+ if ( previousEditor ) {
833+ await this . showTextDocumentSafe ( {
834+ textDocument : previousEditor . document ,
835+ options : {
836+ preview : false ,
837+ preserveFocus : false ,
838+ selection : previousEditor . selection ,
839+ viewColumn : previousEditor . viewColumn ,
840+ } ,
841+ } )
842+ }
843+
844+ // Resolve the promise with the diff editor
845+ resolve ( diffEditor )
846+ } )
847+ // Removed the second .then block that called getEditorFromDiffTab
848+ // This may happen on very slow machines ie project idx
849+ setTimeout ( ( ) => {
850+ reject ( new Error ( "Failed to open diff editor, please try again..." ) )
851+ } , 10_000 )
852+ } )
698853 } )
699854 }
700855
@@ -768,6 +923,7 @@ export class DiffViewProvider {
768923 this . streamedLines = [ ]
769924 this . preDiagnostics = [ ]
770925 this . rooOpenedTabs . clear ( )
926+ this . preDiffActiveEditor = undefined
771927 }
772928
773929 resetWithListeners ( ) {
0 commit comments