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 pendingInterpreterChange ?: { resource ?: Uri } ;
46+
4047 // TODO: In the future, could also have attribute of URI for file specific REPL.
4148 private constructor ( ) {
4249 this . watchNotebookClosed ( ) ;
@@ -48,7 +55,9 @@ export class NativeRepl implements Disposable {
4855 nativeRepl . interpreter = interpreter ;
4956 await nativeRepl . setReplDirectory ( ) ;
5057 nativeRepl . pythonServer = createPythonServer ( [ interpreter . path as string ] , nativeRepl . cwd ) ;
58+ nativeRepl . disposables . push ( nativeRepl . pythonServer ) ;
5159 nativeRepl . setReplController ( ) ;
60+ nativeRepl . registerInterpreterChangeHandler ( ) ;
5261
5362 return nativeRepl ;
5463 }
@@ -116,8 +125,8 @@ export class NativeRepl implements Disposable {
116125 /**
117126 * Function that check if NotebookController for REPL exists, and returns it in Singleton manner.
118127 */
119- public setReplController ( ) : NotebookController {
120- if ( ! this . replController ) {
128+ public setReplController ( force : boolean = false ) : NotebookController {
129+ if ( ! this . replController || force ) {
121130 this . replController = createReplController ( this . interpreter ! . path , this . disposables , this . cwd ) ;
122131 this . replController . variableProvider = new VariablesProvider (
123132 new VariableRequester ( this . pythonServer ) ,
@@ -128,6 +137,64 @@ export class NativeRepl implements Disposable {
128137 return this . replController ;
129138 }
130139
140+ private registerInterpreterChangeHandler ( ) : void {
141+ if ( ! useEnvExtension ( ) || this . envChangeListenerRegistered ) {
142+ return ;
143+ }
144+ this . envChangeListenerRegistered = true ;
145+ this . disposables . push (
146+ onDidChangeEnvironmentEnvExt ( ( event ) => {
147+ this . updateInterpreterForChange ( event . uri ) . catch ( ( ) => undefined ) ;
148+ } ) ,
149+ ) ;
150+ this . disposables . push (
151+ this . pythonServer . onCodeExecuted ( ( ) => {
152+ if ( this . pendingInterpreterChange ) {
153+ const { resource } = this . pendingInterpreterChange ;
154+ this . pendingInterpreterChange = undefined ;
155+ this . updateInterpreterForChange ( resource ) . catch ( ( ) => undefined ) ;
156+ }
157+ } ) ,
158+ ) ;
159+ }
160+
161+ private async updateInterpreterForChange ( resource ?: Uri ) : Promise < void > {
162+ if ( this . pythonServer ?. isExecuting ) {
163+ this . pendingInterpreterChange = { resource } ;
164+ return ;
165+ }
166+ if ( ! this . shouldApplyInterpreterChange ( resource ) ) {
167+ return ;
168+ }
169+ const scope = resource ?? ( this . cwd ? Uri . file ( this . cwd ) : undefined ) ;
170+ const interpreter = await getActiveInterpreterLegacy ( scope ) ;
171+ if ( ! interpreter || interpreter . path === this . interpreter ?. path ) {
172+ return ;
173+ }
174+
175+ this . interpreter = interpreter ;
176+ this . pythonServer . dispose ( ) ;
177+ this . pythonServer = createPythonServer ( [ interpreter . path as string ] , this . cwd ) ;
178+ this . disposables . push ( this . pythonServer ) ;
179+ if ( this . replController ) {
180+ this . replController . dispose ( ) ;
181+ }
182+ this . setReplController ( true ) ;
183+
184+ if ( this . notebookDocument ) {
185+ const notebookEditor = await showNotebookDocument ( this . notebookDocument , { preserveFocus : true } ) ;
186+ await selectNotebookKernel ( notebookEditor , this . replController . id , PVSC_EXTENSION_ID ) ;
187+ }
188+ }
189+
190+ private shouldApplyInterpreterChange ( resource ?: Uri ) : boolean {
191+ if ( ! resource || ! this . cwd ) {
192+ return true ;
193+ }
194+ const relative = path . relative ( this . cwd , resource . fsPath ) ;
195+ return relative === '' || ( ! relative . startsWith ( '..' ) && ! path . isAbsolute ( relative ) ) ;
196+ }
197+
131198 /**
132199 * Function that checks if native REPL's text input box contains complete code.
133200 * @returns Promise<boolean> - True if complete/Valid code is present, False otherwise.
0 commit comments