Skip to content

Commit f9bb1f1

Browse files
authored
Use new REPL notebook API (#24029)
1 parent 63280be commit f9bb1f1

File tree

9 files changed

+103
-52
lines changed

9 files changed

+103
-52
lines changed

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@
2525
"terminalDataWriteEvent",
2626
"terminalExecuteCommandEvent",
2727
"contribIssueReporter",
28-
"notebookVariableProvider",
29-
"codeActionAI"
28+
"codeActionAI",
29+
"notebookReplDocument",
30+
"notebookVariableProvider"
3031
],
3132
"author": {
3233
"name": "Microsoft Corporation"
@@ -47,7 +48,7 @@
4748
"theme": "dark"
4849
},
4950
"engines": {
50-
"vscode": "^1.94.0-20240913"
51+
"vscode": "^1.94.0-20240918"
5152
},
5253
"enableTelemetry": false,
5354
"keywords": [
@@ -1168,6 +1169,11 @@
11681169
{
11691170
"command": "python.execInREPLEnter",
11701171
"key": "enter",
1172+
"when": "!config.interactiveWindow.executeWithShiftEnter && activeEditor == 'workbench.editor.repl' && !inlineChatFocused"
1173+
},
1174+
{
1175+
"command": "python.execInInteractiveWindowEnter",
1176+
"key": "enter",
11711177
"when": "!config.interactiveWindow.executeWithShiftEnter && activeEditor == 'workbench.editor.interactive' && !inlineChatFocused"
11721178
},
11731179
{

src/client/common/application/commands.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ export interface ICommandNameArgumentTypeMapping extends ICommandNameWithoutArgu
9999
[Commands.Start_Native_REPL]: [undefined | Uri];
100100
[Commands.Exec_In_REPL]: [undefined | Uri];
101101
[Commands.Exec_In_REPL_Enter]: [undefined | Uri];
102+
[Commands.Exec_In_IW_Enter]: [undefined | Uri];
102103
[Commands.Exec_In_Terminal]: [undefined, Uri];
103104
[Commands.Exec_In_Terminal_Icon]: [undefined, Uri];
104105
[Commands.Debug_In_Terminal]: [Uri];

src/client/common/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export namespace Commands {
4949
export const Exec_In_REPL = 'python.execInREPL';
5050
export const Exec_Selection_In_Django_Shell = 'python.execSelectionInDjangoShell';
5151
export const Exec_In_REPL_Enter = 'python.execInREPLEnter';
52+
export const Exec_In_IW_Enter = 'python.execInInteractiveWindowEnter';
5253
export const Exec_Selection_In_Terminal = 'python.execSelectionInTerminal';
5354
export const GetSelectedInterpreterPath = 'python.interpreterPath';
5455
export const InstallJupyter = 'python.installJupyter';

src/client/repl/nativeRepl.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ export class NativeRepl implements Disposable {
157157
this.replController.updateNotebookAffinity(this.notebookDocument, NotebookControllerAffinity.Default);
158158
await selectNotebookKernel(notebookEditor, this.replController.id, PVSC_EXTENSION_ID);
159159
if (code) {
160-
await executeNotebookCell(this.notebookDocument, code);
160+
await executeNotebookCell(notebookEditor, code);
161161
}
162162
}
163163
}

src/client/repl/replCommandHandler.ts

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
workspace,
1313
} from 'vscode';
1414
import { getExistingReplViewColumn } from './replUtils';
15+
import { PVSC_EXTENSION_ID } from '../common/constants';
1516

1617
/**
1718
* Function that opens/show REPL using IW UI.
@@ -23,29 +24,24 @@ export async function openInteractiveREPL(
2324
notebookController: NotebookController,
2425
notebookDocument: NotebookDocument | undefined,
2526
): Promise<NotebookEditor> {
26-
let notebookEditor: NotebookEditor | undefined;
27+
let viewColumn = ViewColumn.Beside;
2728

2829
// Case where NotebookDocument (REPL document already exists in the tab)
2930
if (notebookDocument) {
3031
const existingReplViewColumn = getExistingReplViewColumn(notebookDocument);
31-
const replViewColumn = existingReplViewColumn ?? ViewColumn.Beside;
32-
notebookEditor = await window.showNotebookDocument(notebookDocument!, { viewColumn: replViewColumn });
32+
viewColumn = existingReplViewColumn ?? viewColumn;
3333
} else if (!notebookDocument) {
34-
// Case where NotebookDocument doesnt exist, open new REPL tab
35-
const interactiveWindowObject = (await commands.executeCommand(
36-
'interactive.open',
37-
{
38-
preserveFocus: true,
39-
viewColumn: ViewColumn.Beside,
40-
},
41-
undefined,
42-
notebookController.id,
43-
'Python REPL',
44-
)) as { notebookEditor: NotebookEditor };
45-
notebookEditor = interactiveWindowObject.notebookEditor;
46-
notebookDocument = interactiveWindowObject.notebookEditor.notebook;
34+
// Case where NotebookDocument doesnt exist, create a blank one.
35+
notebookDocument = await workspace.openNotebookDocument('jupyter-notebook');
4736
}
48-
return notebookEditor!;
37+
const editor = window.showNotebookDocument(notebookDocument!, { viewColumn, asRepl: 'Python REPL' });
38+
await commands.executeCommand('notebook.selectKernel', {
39+
editor,
40+
id: notebookController.id,
41+
extension: PVSC_EXTENSION_ID,
42+
});
43+
44+
return editor;
4945
}
5046

5147
/**
@@ -73,13 +69,14 @@ export async function selectNotebookKernel(
7369
* @param code
7470
* @return Promise<void>
7571
*/
76-
export async function executeNotebookCell(notebookDocument: NotebookDocument, code: string): Promise<void> {
77-
const { cellCount } = notebookDocument;
78-
await addCellToNotebook(notebookDocument, code);
72+
export async function executeNotebookCell(notebookEditor: NotebookEditor, code: string): Promise<void> {
73+
const { notebook, replOptions } = notebookEditor;
74+
const cellIndex = replOptions?.appendIndex ?? notebook.cellCount;
75+
await addCellToNotebook(notebook, cellIndex, code);
7976
// Execute the cell
8077
commands.executeCommand('notebook.cell.execute', {
81-
ranges: [{ start: cellCount, end: cellCount + 1 }],
82-
document: notebookDocument.uri,
78+
ranges: [{ start: cellIndex, end: cellIndex + 1 }],
79+
document: notebook.uri,
8380
});
8481
}
8582

@@ -89,11 +86,10 @@ export async function executeNotebookCell(notebookDocument: NotebookDocument, co
8986
* @param code
9087
*
9188
*/
92-
async function addCellToNotebook(notebookDocument: NotebookDocument, code: string): Promise<void> {
89+
async function addCellToNotebook(notebookDocument: NotebookDocument, index: number, code: string): Promise<void> {
9390
const notebookCellData = new NotebookCellData(NotebookCellKind.Code, code as string, 'python');
94-
const { cellCount } = notebookDocument!;
9591
// Add new cell to interactive window document
96-
const notebookEdit = NotebookEdit.insertCells(cellCount, [notebookCellData]);
92+
const notebookEdit = NotebookEdit.insertCells(index, [notebookCellData]);
9793
const workspaceEdit = new WorkspaceEdit();
9894
workspaceEdit.set(notebookDocument!.uri, [notebookEdit]);
9995
await workspace.applyEdit(workspaceEdit);

src/client/repl/replCommands.ts

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -98,29 +98,43 @@ export async function registerReplExecuteOnEnter(
9898
): Promise<void> {
9999
disposables.push(
100100
commandManager.registerCommand(Commands.Exec_In_REPL_Enter, async (uri: Uri) => {
101-
const interpreter = await interpreterService.getActiveInterpreter(uri);
102-
if (!interpreter) {
103-
commands.executeCommand(Commands.TriggerEnvironmentSelection, uri).then(noop, noop);
104-
return;
105-
}
101+
await onInputEnter(uri, 'repl.execute', interpreterService, disposables);
102+
}),
103+
);
104+
disposables.push(
105+
commandManager.registerCommand(Commands.Exec_In_IW_Enter, async (uri: Uri) => {
106+
await onInputEnter(uri, 'interactive.execute', interpreterService, disposables);
107+
}),
108+
);
109+
}
106110

107-
const nativeRepl = await getNativeRepl(interpreter, disposables);
108-
const completeCode = await nativeRepl?.checkUserInputCompleteCode(window.activeTextEditor);
109-
const editor = window.activeTextEditor;
111+
async function onInputEnter(
112+
uri: Uri,
113+
commandName: string,
114+
interpreterService: IInterpreterService,
115+
disposables: Disposable[],
116+
): Promise<void> {
117+
const interpreter = await interpreterService.getActiveInterpreter(uri);
118+
if (!interpreter) {
119+
commands.executeCommand(Commands.TriggerEnvironmentSelection, uri).then(noop, noop);
120+
return;
121+
}
110122

111-
if (editor) {
112-
// Execute right away when complete code and Not multi-line
113-
if (completeCode && !isMultiLineText(editor)) {
114-
await commands.executeCommand('interactive.execute');
115-
} else {
116-
insertNewLineToREPLInput(editor);
123+
const nativeRepl = await getNativeRepl(interpreter, disposables);
124+
const completeCode = await nativeRepl?.checkUserInputCompleteCode(window.activeTextEditor);
125+
const editor = window.activeTextEditor;
117126

118-
// Handle case when user enters on blank line, just trigger interactive.execute
119-
if (editor && editor.document.lineAt(editor.selection.active.line).text === '') {
120-
await commands.executeCommand('interactive.execute');
121-
}
122-
}
127+
if (editor) {
128+
// Execute right away when complete code and Not multi-line
129+
if (completeCode && !isMultiLineText(editor)) {
130+
await commands.executeCommand(commandName);
131+
} else {
132+
insertNewLineToREPLInput(editor);
133+
134+
// Handle case when user enters on blank line, just trigger interactive.execute
135+
if (editor && editor.document.lineAt(editor.selection.active.line).text === '') {
136+
await commands.executeCommand(commandName);
123137
}
124-
}),
125-
);
138+
}
139+
}
126140
}

src/client/repl/replController.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export function createReplController(
99
const server = createPythonServer([interpreterPath], cwd);
1010
disposables.push(server);
1111

12-
const controller = vscode.notebooks.createNotebookController('pythonREPL', 'interactive', 'Python REPL');
12+
const controller = vscode.notebooks.createNotebookController('pythonREPL', 'jupyter-notebook', 'Python REPL');
1313
controller.supportedLanguages = ['python'];
1414
controller.supportsExecutionOrder = true;
1515

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
declare module 'vscode' {
7+
8+
export interface NotebookDocumentShowOptions {
9+
/**
10+
* The notebook should be opened in a REPL editor,
11+
* where the last cell of the notebook is an input box and the other cells are the read-only history.
12+
* When the value is a string, it will be used as the label for the editor tab.
13+
*/
14+
readonly asRepl?: boolean | string | {
15+
/**
16+
* The label to be used for the editor tab.
17+
*/
18+
readonly label: string;
19+
};
20+
}
21+
22+
export interface NotebookEditor {
23+
/**
24+
* Information about the REPL editor if the notebook was opened as a repl.
25+
*/
26+
replOptions?: {
27+
/**
28+
* The index where new cells should be appended.
29+
*/
30+
appendIndex: number;
31+
};
32+
}
33+
}

0 commit comments

Comments
 (0)