1
1
// Native Repl class that holds instance of pythonServer and replController
2
2
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' ;
4
12
import { Disposable } from 'vscode-jsonrpc' ;
5
13
import { PVSC_EXTENSION_ID } from '../common/constants' ;
14
+ import { showQuickPick } from '../common/vscodeApis/windowApis' ;
15
+ import { getWorkspaceFolders } from '../common/vscodeApis/workspaceApis' ;
6
16
import { PythonEnvironment } from '../pythonEnvironments/info' ;
7
17
import { createPythonServer , PythonServer } from './pythonServer' ;
8
18
import { executeNotebookCell , openInteractiveREPL , selectNotebookKernel } from './replCommandHandler' ;
9
19
import { createReplController } from './replController' ;
10
20
11
21
export 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 ;
13
24
14
- private interpreter : PythonEnvironment ;
25
+ private cwd : string | undefined ;
26
+
27
+ private interpreter ! : PythonEnvironment ;
15
28
16
29
private disposables : Disposable [ ] = [ ] ;
17
30
18
- private replController : NotebookController ;
31
+ private replController ! : NotebookController ;
19
32
20
33
private notebookDocument : NotebookDocument | undefined ;
21
34
22
35
// 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
+ }
25
39
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 ( ) ;
28
47
29
- this . watchNotebookClosed ( ) ;
48
+ return nativeRepl ;
30
49
}
31
50
32
51
dispose ( ) : void {
@@ -47,13 +66,46 @@ export class NativeRepl implements Disposable {
47
66
) ;
48
67
}
49
68
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
+
50
102
/**
51
103
* Function that check if NotebookController for REPL exists, and returns it in Singleton manner.
52
104
* @returns NotebookController
53
105
*/
54
106
public setReplController ( ) : NotebookController {
55
107
if ( ! this . replController ) {
56
- return createReplController ( this . interpreter . path , this . disposables ) ;
108
+ return createReplController ( this . interpreter ! . path , this . disposables , this . cwd ) ;
57
109
}
58
110
return this . replController ;
59
111
}
@@ -84,14 +136,16 @@ export class NativeRepl implements Disposable {
84
136
* Function that opens interactive repl, selects kernel, and send/execute code to the native repl.
85
137
* @param code
86
138
*/
87
- public async sendToNativeRepl ( code : string ) : Promise < void > {
139
+ public async sendToNativeRepl ( code ? : string ) : Promise < void > {
88
140
const notebookEditor = await openInteractiveREPL ( this . replController , this . notebookDocument ) ;
89
141
this . notebookDocument = notebookEditor . notebook ;
90
142
91
143
if ( this . notebookDocument ) {
92
144
this . replController . updateNotebookAffinity ( this . notebookDocument , NotebookControllerAffinity . Default ) ;
93
145
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
+ }
95
149
}
96
150
}
97
151
}
@@ -103,9 +157,9 @@ let nativeRepl: NativeRepl | undefined; // In multi REPL scenario, hashmap of UR
103
157
* @param interpreter
104
158
* @returns Native REPL instance
105
159
*/
106
- export function getNativeRepl ( interpreter : PythonEnvironment , disposables : Disposable [ ] ) : NativeRepl {
160
+ export async function getNativeRepl ( interpreter : PythonEnvironment , disposables : Disposable [ ] ) : Promise < NativeRepl > {
107
161
if ( ! nativeRepl ) {
108
- nativeRepl = new NativeRepl ( interpreter ) ;
162
+ nativeRepl = await NativeRepl . create ( interpreter ) ;
109
163
disposables . push ( nativeRepl ) ;
110
164
}
111
165
return nativeRepl ;
0 commit comments