11// Native Repl class that holds instance of pythonServer and replController
22
3- import { NotebookController , NotebookControllerAffinity , NotebookDocument , TextEditor , workspace } from 'vscode' ;
3+ import {
4+ NotebookController ,
5+ NotebookControllerAffinity ,
6+ NotebookDocument ,
7+ QuickPickItem ,
8+ TextEditor ,
9+ workspace ,
10+ WorkspaceFolder ,
11+ } from 'vscode' ;
412import { Disposable } from 'vscode-jsonrpc' ;
513import { PVSC_EXTENSION_ID } from '../common/constants' ;
14+ import { showQuickPick } from '../common/vscodeApis/windowApis' ;
15+ import { getWorkspaceFolders } from '../common/vscodeApis/workspaceApis' ;
616import { PythonEnvironment } from '../pythonEnvironments/info' ;
717import { createPythonServer , PythonServer } from './pythonServer' ;
818import { executeNotebookCell , openInteractiveREPL , selectNotebookKernel } from './replCommandHandler' ;
919import { createReplController } from './replController' ;
1020
1121export class NativeRepl implements Disposable {
12- private pythonServer : PythonServer ;
22+ // Adding ! since it will get initialized in create method, not the constructor.
23+ private pythonServer ! : PythonServer ;
1324
14- private interpreter : PythonEnvironment ;
25+ private cwd : string | undefined ;
26+
27+ private interpreter ! : PythonEnvironment ;
1528
1629 private disposables : Disposable [ ] = [ ] ;
1730
18- private replController : NotebookController ;
31+ private replController ! : NotebookController ;
1932
2033 private notebookDocument : NotebookDocument | undefined ;
2134
2235 // TODO: In the future, could also have attribute of URI for file specific REPL.
23- constructor ( interpreter : PythonEnvironment ) {
24- this . interpreter = interpreter ;
36+ private constructor ( ) {
37+ this . watchNotebookClosed ( ) ;
38+ }
2539
26- this . pythonServer = createPythonServer ( [ interpreter . path as string ] ) ;
27- this . replController = this . setReplController ( ) ;
40+ // Static async factory method to handle asynchronous initialization
41+ public static async create ( interpreter : PythonEnvironment ) : Promise < NativeRepl > {
42+ const nativeRepl = new NativeRepl ( ) ;
43+ nativeRepl . interpreter = interpreter ;
44+ await nativeRepl . setReplDirectory ( ) ;
45+ nativeRepl . pythonServer = createPythonServer ( [ interpreter . path as string ] , nativeRepl . cwd ) ;
46+ nativeRepl . replController = nativeRepl . setReplController ( ) ;
2847
29- this . watchNotebookClosed ( ) ;
48+ return nativeRepl ;
3049 }
3150
3251 dispose ( ) : void {
@@ -47,13 +66,46 @@ export class NativeRepl implements Disposable {
4766 ) ;
4867 }
4968
69+ /**
70+ * Function that set up desired directory for REPL.
71+ * If there is multiple workspaces, prompt the user to choose
72+ * which directory we should set in context of native REPL.
73+ */
74+ private async setReplDirectory ( ) : Promise < void > {
75+ // Figure out uri via workspaceFolder as uri parameter always
76+ // seem to be undefined from parameter when trying to access from replCommands.ts
77+ const workspaces : readonly WorkspaceFolder [ ] | undefined = getWorkspaceFolders ( ) ;
78+
79+ if ( workspaces ) {
80+ // eslint-disable-next-line no-shadow
81+ const workspacesQuickPickItems : QuickPickItem [ ] = workspaces . map ( ( workspace ) => ( {
82+ label : workspace . name ,
83+ description : workspace . uri . fsPath ,
84+ } ) ) ;
85+
86+ if ( workspacesQuickPickItems . length === 0 ) {
87+ this . cwd = process . cwd ( ) ; // Yields '/' on no workspace scenario.
88+ } else if ( workspacesQuickPickItems . length === 1 ) {
89+ this . cwd = workspacesQuickPickItems [ 0 ] . description ;
90+ } else {
91+ // Show choices of workspaces for user to choose from.
92+ const selection = ( await showQuickPick ( workspacesQuickPickItems , {
93+ placeHolder : 'Select current working directory for new REPL' ,
94+ matchOnDescription : true ,
95+ ignoreFocusOut : true ,
96+ } ) ) as QuickPickItem ;
97+ this . cwd = selection ?. description ;
98+ }
99+ }
100+ }
101+
50102 /**
51103 * Function that check if NotebookController for REPL exists, and returns it in Singleton manner.
52104 * @returns NotebookController
53105 */
54106 public setReplController ( ) : NotebookController {
55107 if ( ! this . replController ) {
56- return createReplController ( this . interpreter . path , this . disposables ) ;
108+ return createReplController ( this . interpreter ! . path , this . disposables , this . cwd ) ;
57109 }
58110 return this . replController ;
59111 }
@@ -84,14 +136,16 @@ export class NativeRepl implements Disposable {
84136 * Function that opens interactive repl, selects kernel, and send/execute code to the native repl.
85137 * @param code
86138 */
87- public async sendToNativeRepl ( code : string ) : Promise < void > {
139+ public async sendToNativeRepl ( code ? : string ) : Promise < void > {
88140 const notebookEditor = await openInteractiveREPL ( this . replController , this . notebookDocument ) ;
89141 this . notebookDocument = notebookEditor . notebook ;
90142
91143 if ( this . notebookDocument ) {
92144 this . replController . updateNotebookAffinity ( this . notebookDocument , NotebookControllerAffinity . Default ) ;
93145 await selectNotebookKernel ( notebookEditor , this . replController . id , PVSC_EXTENSION_ID ) ;
94- await executeNotebookCell ( this . notebookDocument , code ) ;
146+ if ( code ) {
147+ await executeNotebookCell ( this . notebookDocument , code ) ;
148+ }
95149 }
96150 }
97151}
@@ -103,9 +157,9 @@ let nativeRepl: NativeRepl | undefined; // In multi REPL scenario, hashmap of UR
103157 * @param interpreter
104158 * @returns Native REPL instance
105159 */
106- export function getNativeRepl ( interpreter : PythonEnvironment , disposables : Disposable [ ] ) : NativeRepl {
160+ export async function getNativeRepl ( interpreter : PythonEnvironment , disposables : Disposable [ ] ) : Promise < NativeRepl > {
107161 if ( ! nativeRepl ) {
108- nativeRepl = new NativeRepl ( interpreter ) ;
162+ nativeRepl = await NativeRepl . create ( interpreter ) ;
109163 disposables . push ( nativeRepl ) ;
110164 }
111165 return nativeRepl ;
0 commit comments