@@ -119,7 +119,7 @@ export class DiffViewProvider {
119119 const diffEditor = this . activeDiffEditor
120120 const document = diffEditor ?. document
121121
122- if ( ! diffEditor || ! document ) {
122+ if ( ! diffEditor || ! document || ! this . isEditorValid ( diffEditor ) ) {
123123 throw new Error ( "User closed text editor, unable to edit file..." )
124124 }
125125
@@ -181,7 +181,10 @@ export class DiffViewProvider {
181181 }
182182 }
183183
184- async saveChanges ( diagnosticsEnabled : boolean = true , writeDelayMs : number = DEFAULT_WRITE_DELAY_MS ) : Promise < {
184+ async saveChanges (
185+ diagnosticsEnabled : boolean = true ,
186+ writeDelayMs : number = DEFAULT_WRITE_DELAY_MS ,
187+ ) : Promise < {
185188 newProblemsMessage : string | undefined
186189 userEdits : string | undefined
187190 finalContent : string | undefined
@@ -216,22 +219,22 @@ export class DiffViewProvider {
216219 // and can address them accordingly. If problems don't change immediately after
217220 // applying a fix, won't be notified, which is generally fine since the
218221 // initial fix is usually correct and it may just take time for linters to catch up.
219-
222+
220223 let newProblemsMessage = ""
221-
224+
222225 if ( diagnosticsEnabled ) {
223226 // Add configurable delay to allow linters time to process and clean up issues
224227 // like unused imports (especially important for Go and other languages)
225228 // Ensure delay is non-negative
226229 const safeDelayMs = Math . max ( 0 , writeDelayMs )
227-
230+
228231 try {
229232 await delay ( safeDelayMs )
230233 } catch ( error ) {
231234 // Log error but continue - delay failure shouldn't break the save operation
232235 console . warn ( `Failed to apply write delay: ${ error } ` )
233236 }
234-
237+
235238 const postDiagnostics = vscode . languages . getDiagnostics ( )
236239
237240 const newProblems = await diagnosticsToProblemsString (
@@ -549,7 +552,7 @@ export class DiffViewProvider {
549552 }
550553
551554 private scrollEditorToLine ( line : number ) {
552- if ( this . activeDiffEditor ) {
555+ if ( this . activeDiffEditor && this . isEditorValid ( this . activeDiffEditor ) ) {
553556 const scrollLine = line + 4
554557
555558 this . activeDiffEditor . revealRange (
@@ -560,7 +563,7 @@ export class DiffViewProvider {
560563 }
561564
562565 scrollToFirstDiff ( ) {
563- if ( ! this . activeDiffEditor ) {
566+ if ( ! this . activeDiffEditor || ! this . isEditorValid ( this . activeDiffEditor ) ) {
564567 return
565568 }
566569
@@ -599,6 +602,14 @@ export class DiffViewProvider {
599602 }
600603
601604 async reset ( ) : Promise < void > {
605+ // Dispose decoration controllers before clearing references
606+ if ( this . fadedOverlayController ) {
607+ this . fadedOverlayController . dispose ( )
608+ }
609+ if ( this . activeLineController ) {
610+ this . activeLineController . dispose ( )
611+ }
612+
602613 await this . closeAllDiffViews ( )
603614 this . editType = undefined
604615 this . isEditing = false
@@ -611,4 +622,25 @@ export class DiffViewProvider {
611622 this . streamedLines = [ ]
612623 this . preDiagnostics = [ ]
613624 }
625+
626+ private isEditorValid ( editor : vscode . TextEditor ) : boolean {
627+ // Check if the editor is still valid by verifying it exists in visible editors
628+ // and its document hasn't been closed
629+ try {
630+ // In test environments, visibleTextEditors might be empty, so also check if document exists
631+ const isInVisibleEditors = vscode . window . visibleTextEditors . includes ( editor )
632+ const hasValidDocument = editor . document && ! editor . document . isClosed
633+
634+ // If we're in a test environment (no visible editors), rely on document validity
635+ // Otherwise, check both conditions
636+ if ( vscode . window . visibleTextEditors . length === 0 ) {
637+ return hasValidDocument
638+ }
639+
640+ return isInVisibleEditors && hasValidDocument
641+ } catch {
642+ // If accessing editor properties throws, it's disposed
643+ return false
644+ }
645+ }
614646}
0 commit comments