44// Native Repl class that holds instance of pythonServer and replController
55
66import { NotebookController , NotebookDocument , QuickPickItem , TextEditor , Uri , WorkspaceFolder } from 'vscode' ;
7+ import * as path from 'path' ;
78import { Disposable } from 'vscode-jsonrpc' ;
89import { PVSC_EXTENSION_ID } from '../common/constants' ;
9- import { showQuickPick } from '../common/vscodeApis/windowApis' ;
10+ import { showNotebookDocument , showQuickPick } from '../common/vscodeApis/windowApis' ;
1011import { getWorkspaceFolders , onDidCloseNotebookDocument } from '../common/vscodeApis/workspaceApis' ;
1112import { PythonEnvironment } from '../pythonEnvironments/info' ;
1213import { createPythonServer , PythonServer } from './pythonServer' ;
@@ -18,6 +19,8 @@ import { VariablesProvider } from './variables/variablesProvider';
1819import { VariableRequester } from './variables/variableRequester' ;
1920import { getTabNameForUri } from './replUtils' ;
2021import { getWorkspaceStateValue , updateWorkspaceStateValue } from '../common/persistentState' ;
22+ import { onDidChangeEnvironmentEnvExt , useEnvExtension } from '../envExt/api.internal' ;
23+ import { getActiveInterpreterLegacy } from '../envExt/api.legacy' ;
2124
2225export const NATIVE_REPL_URI_MEMENTO = 'nativeReplUri' ;
2326let nativeRepl : NativeRepl | undefined ;
@@ -37,6 +40,10 @@ export class NativeRepl implements Disposable {
3740
3841 public newReplSession : boolean | undefined = true ;
3942
43+ private envChangeListenerRegistered = false ;
44+
45+ private pendingInterpreterChangeTimer ?: NodeJS . Timeout ;
46+
4047 // TODO: In the future, could also have attribute of URI for file specific REPL.
4148 private constructor ( ) {
4249 this . watchNotebookClosed ( ) ;
@@ -49,6 +56,7 @@ export class NativeRepl implements Disposable {
4956 await nativeRepl . setReplDirectory ( ) ;
5057 nativeRepl . pythonServer = createPythonServer ( [ interpreter . path as string ] , nativeRepl . cwd ) ;
5158 nativeRepl . setReplController ( ) ;
59+ nativeRepl . registerInterpreterChangeHandler ( ) ;
5260
5361 return nativeRepl ;
5462 }
@@ -116,8 +124,8 @@ export class NativeRepl implements Disposable {
116124 /**
117125 * Function that check if NotebookController for REPL exists, and returns it in Singleton manner.
118126 */
119- public setReplController ( ) : NotebookController {
120- if ( ! this . replController ) {
127+ public setReplController ( force : boolean = false ) : NotebookController {
128+ if ( ! this . replController || force ) {
121129 this . replController = createReplController ( this . interpreter ! . path , this . disposables , this . cwd ) ;
122130 this . replController . variableProvider = new VariablesProvider (
123131 new VariableRequester ( this . pythonServer ) ,
@@ -128,6 +136,64 @@ export class NativeRepl implements Disposable {
128136 return this . replController ;
129137 }
130138
139+ private registerInterpreterChangeHandler ( ) : void {
140+ if ( ! useEnvExtension ( ) || this . envChangeListenerRegistered ) {
141+ return ;
142+ }
143+ this . envChangeListenerRegistered = true ;
144+ this . disposables . push (
145+ onDidChangeEnvironmentEnvExt ( ( event ) => {
146+ this . updateInterpreterForChange ( event . uri ) . catch ( ( ) => undefined ) ;
147+ } ) ,
148+ ) ;
149+ }
150+
151+ private async updateInterpreterForChange ( resource ?: Uri ) : Promise < void > {
152+ if ( this . pythonServer ?. isExecuting ) {
153+ this . scheduleInterpreterUpdate ( resource ) ;
154+ return ;
155+ }
156+ if ( ! this . shouldApplyInterpreterChange ( resource ) ) {
157+ return ;
158+ }
159+ const scope = resource ?? ( this . cwd ? Uri . file ( this . cwd ) : undefined ) ;
160+ const interpreter = await getActiveInterpreterLegacy ( scope ) ;
161+ if ( ! interpreter || interpreter . path === this . interpreter ?. path ) {
162+ return ;
163+ }
164+
165+ this . interpreter = interpreter ;
166+ this . pythonServer . dispose ( ) ;
167+ this . pythonServer = createPythonServer ( [ interpreter . path as string ] , this . cwd ) ;
168+ if ( this . replController ) {
169+ this . replController . dispose ( ) ;
170+ }
171+ this . setReplController ( true ) ;
172+
173+ if ( this . notebookDocument ) {
174+ const notebookEditor = await showNotebookDocument ( this . notebookDocument , { preserveFocus : true } ) ;
175+ await selectNotebookKernel ( notebookEditor , this . replController . id , PVSC_EXTENSION_ID ) ;
176+ }
177+ }
178+
179+ private scheduleInterpreterUpdate ( resource ?: Uri ) : void {
180+ if ( this . pendingInterpreterChangeTimer ) {
181+ clearTimeout ( this . pendingInterpreterChangeTimer ) ;
182+ }
183+ this . pendingInterpreterChangeTimer = setTimeout ( ( ) => {
184+ this . pendingInterpreterChangeTimer = undefined ;
185+ this . updateInterpreterForChange ( resource ) . catch ( ( ) => undefined ) ;
186+ } , 200 ) ;
187+ }
188+
189+ private shouldApplyInterpreterChange ( resource ?: Uri ) : boolean {
190+ if ( ! resource || ! this . cwd ) {
191+ return true ;
192+ }
193+ const relative = path . relative ( this . cwd , resource . fsPath ) ;
194+ return relative === '' || ( ! relative . startsWith ( '..' ) && ! path . isAbsolute ( relative ) ) ;
195+ }
196+
131197 /**
132198 * Function that checks if native REPL's text input box contains complete code.
133199 * @returns Promise<boolean> - True if complete/Valid code is present, False otherwise.
0 commit comments