33'use strict' ; 
44import  {  inject ,  injectable  }  from  'inversify' ; 
55import  *  as  path  from  'path' ; 
6- import  {  TextDocument ,  Uri  }  from  'vscode' ; 
6+ import  {  TextDocument ,  TextEditor ,   Uri  }  from  'vscode' ; 
77
88import  {  ICommandManager ,  IDocumentManager ,  IWorkspaceService  }  from  '../../common/application/types' ; 
99import  {  JUPYTER_LANGUAGE  }  from  '../../common/constants' ; 
@@ -21,7 +21,6 @@ export class NativeEditorProvider implements INotebookEditorProvider, IAsyncDisp
2121 private  executedEditors : Set < string >  =  new  Set < string > ( ) ; 
2222 private  notebookCount : number  =  0 ; 
2323 private  openedNotebookCount : number  =  0 ; 
24- 
2524 constructor ( 
2625 @inject ( IServiceContainer )  private  serviceContainer : IServiceContainer , 
2726 @inject ( IAsyncDisposableRegistry )  asyncRegistry : IAsyncDisposableRegistry , 
@@ -45,16 +44,14 @@ export class NativeEditorProvider implements INotebookEditorProvider, IAsyncDisp
4544 findFilesPromise . then ( r  =>  this . notebookCount  +=  r . length ) ; 
4645 } 
4746
48-  // Listen to document open commands. We use this to launch an ipynb editor 
49-  const  disposable  =  this . documentManager . onDidOpenTextDocument ( this . onOpenedDocument ) ; 
50-  this . disposables . push ( disposable ) ; 
47+  this . disposables . push ( this . documentManager . onDidChangeActiveTextEditor ( this . onDidChangeActiveTextEditorHandler . bind ( this ) ) ) ; 
5148
5249 // Since we may have activated after a document was opened, also run open document for all documents. 
5350 // This needs to be async though. Iterating over all of these in the .ctor is crashing the extension 
5451 // host, so postpone till after the ctor is finished. 
5552 setTimeout ( ( )  =>  { 
5653 if  ( this . documentManager . textDocuments  &&  this . documentManager . textDocuments . forEach )  { 
57-  this . documentManager . textDocuments . forEach ( this . onOpenedDocument ) ; 
54+  this . documentManager . textDocuments . forEach ( doc   =>   this . openNotebookAndCloseEditor ( doc ,   false ) ) ; 
5855 } 
5956 } ,  0 ) ; 
6057
@@ -132,6 +129,19 @@ export class NativeEditorProvider implements INotebookEditorProvider, IAsyncDisp
132129 purpose : Identifiers . HistoryPurpose  // Share the same one as the interactive window. Just need a new session 
133130 } ; 
134131 } 
132+  /** 
133+  * Open ipynb files when user opens an ipynb file. 
134+  * 
135+  * @private  
136+  * @memberof  NativeEditorProvider 
137+  */ 
138+  private  onDidChangeActiveTextEditorHandler ( editor ?: TextEditor ) { 
139+  // I we're a source control diff view, then ignore this editor. 
140+  if  ( ! editor  ||  this . isEditorPartOfDiffView ( editor ) ) { 
141+  return ; 
142+  } 
143+  this . openNotebookAndCloseEditor ( editor . document ,  true ) . ignoreErrors ( ) ; 
144+  } 
135145
136146 private  async  create ( file : Uri ,  contents : string ) : Promise < INotebookEditor >  { 
137147 const  editor  =  this . serviceContainer . get < INotebookEditor > ( INotebookEditor ) ; 
@@ -178,27 +188,79 @@ export class NativeEditorProvider implements INotebookEditorProvider, IAsyncDisp
178188 return  Uri . file ( `${ localize . DataScience . untitledNotebookFileName ( ) }  -${ number }  ` ) ; 
179189 } 
180190
181-  private  onOpenedDocument  =  async  ( document : TextDocument )  =>  { 
191+  private  openNotebookAndCloseEditor  =  async  ( document : TextDocument ,   closeDocumentBeforeOpeningNotebook :  boolean )  =>  { 
182192 // See if this is an ipynb file 
183-  if  ( this . isNotebook ( document )  &&  this . configuration . getSettings ( ) . datascience . useNotebookEditor )  { 
193+  if  ( this . isNotebook ( document )  &&  this . configuration . getSettings ( ) . datascience . useNotebookEditor  && 
194+  ! this . activeEditors . has ( document . uri . fsPath ) )  { 
184195 try  { 
185-  const  contents  =  document . getText ( ) ; 
196+  const  contents  =  document .   getText ( ) ; 
186197 const  uri  =  document . uri ; 
198+  const  closeActiveEditorCommand  =  'workbench.action.closeActiveEditor' ; 
199+ 
200+  if  ( closeDocumentBeforeOpeningNotebook )  { 
201+  if  ( ! this . documentManager . activeTextEditor  ||  this . documentManager . activeTextEditor . document  !==  document ) { 
202+  await  this . documentManager . showTextDocument ( document ) ; 
203+  } 
204+  await  this . cmdManager . executeCommand ( closeActiveEditorCommand ) ; 
205+  } 
187206
188207 // Open our own editor. 
189208 await  this . open ( uri ,  contents ) ; 
190209
191-  // Then switch back to the ipynb and close it. 
192-  // If we don't do it in this order, the close will switch to the wrong item 
193-  await  this . documentManager . showTextDocument ( document ) ; 
194-  const  command  =  'workbench.action.closeActiveEditor' ; 
195-  await  this . cmdManager . executeCommand ( command ) ; 
210+  if  ( ! closeDocumentBeforeOpeningNotebook ) { 
211+  // Then switch back to the ipynb and close it. 
212+  // If we don't do it in this order, the close will switch to the wrong item 
213+  await  this . documentManager . showTextDocument ( document ) ; 
214+  await  this . cmdManager . executeCommand ( closeActiveEditorCommand ) ; 
215+  } 
196216 }  catch  ( e )  { 
197217 return  this . dataScienceErrorHandler . handleError ( e ) ; 
198218 } 
199219 } 
200220 } 
221+  /** 
222+  * Check if user is attempting to compare two ipynb files. 
223+  * If yes, then return `true`, else `false`. 
224+  * 
225+  * @private  
226+  * @param  {TextEditor } editor 
227+  * @memberof  NativeEditorProvider 
228+  */ 
229+  private  isEditorPartOfDiffView ( editor ?: TextEditor ) { 
230+  if  ( ! editor ) { 
231+  return  false ; 
232+  } 
233+  // There's no easy way to determine if the user is openeing a diff view. 
234+  // One simple way is to check if there are 2 editor opened, and if both editors point to the same file 
235+  // One file with the `file` scheme and the other with the `git` scheme. 
236+  if  ( this . documentManager . visibleTextEditors . length  <=  1 ) { 
237+  return  false ; 
238+  } 
239+ 
240+  // If we have both `git` & `file` schemes for the same file, then we're most likely looking at a diff view. 
241+  // Also ensure both editors are in the same view column. 
242+  // Possible we have a git diff view (with two editors git and file scheme), and we open the file view 
243+  // on the side (different view column). 
244+  const  gitSchemeEditor  =  this . documentManager . visibleTextEditors . find ( editorUri  => 
245+  editorUri . document . uri . scheme  ===  'git'  && 
246+  this . fileSystem . arePathsSame ( editorUri . document . uri . fsPath ,  editor . document . uri . fsPath ) ) ; 
247+ 
248+  if  ( ! gitSchemeEditor ) { 
249+  return  false ; 
250+  } 
201251
252+  const  fileSchemeEditor  =  this . documentManager . visibleTextEditors . find ( editorUri  => 
253+  editorUri . document . uri . scheme  ===  'file'  && 
254+  this . fileSystem . arePathsSame ( editorUri . document . uri . fsPath ,  editor . document . uri . fsPath )  && 
255+  editorUri . viewColumn  ===  gitSchemeEditor . viewColumn ) ; 
256+  if  ( ! fileSchemeEditor ) { 
257+  return  false ; 
258+  } 
259+ 
260+  // Also confirm the document we have passed in, belongs to one of the editors. 
261+  // If its not, then its another document (that is not in the diff view). 
262+  return  gitSchemeEditor  ===  editor  ||  fileSchemeEditor  ===  editor ; 
263+  } 
202264 private  isNotebook ( document : TextDocument )  { 
203265 // Only support file uris (we don't want to automatically open any other ipynb file from another resource as a notebook). 
204266 // E.g. when opening a document for comparison, the scheme is `git`, in live share the scheme is `vsls`. 
0 commit comments