mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 09:08:48 +01:00
Merge branch 'notebook/dev' into main
This commit is contained in:
@@ -139,7 +139,7 @@ suite('Notebook Document', function () {
|
|||||||
// inserting two new cells
|
// inserting two new cells
|
||||||
{
|
{
|
||||||
const edit = new vscode.WorkspaceEdit();
|
const edit = new vscode.WorkspaceEdit();
|
||||||
edit.replaceNotebookCells(document.uri, 0, 0, [{
|
edit.replaceNotebookCells(document.uri, new vscode.NotebookRange(0, 0), [{
|
||||||
kind: vscode.NotebookCellKind.Markdown,
|
kind: vscode.NotebookCellKind.Markdown,
|
||||||
language: 'markdown',
|
language: 'markdown',
|
||||||
metadata: undefined,
|
metadata: undefined,
|
||||||
@@ -164,8 +164,8 @@ suite('Notebook Document', function () {
|
|||||||
// deleting cell 1 and 3
|
// deleting cell 1 and 3
|
||||||
{
|
{
|
||||||
const edit = new vscode.WorkspaceEdit();
|
const edit = new vscode.WorkspaceEdit();
|
||||||
edit.replaceNotebookCells(document.uri, 0, 1, []);
|
edit.replaceNotebookCells(document.uri, new vscode.NotebookRange(0, 1), []);
|
||||||
edit.replaceNotebookCells(document.uri, 2, 3, []);
|
edit.replaceNotebookCells(document.uri, new vscode.NotebookRange(2, 3), []);
|
||||||
const success = await vscode.workspace.applyEdit(edit);
|
const success = await vscode.workspace.applyEdit(edit);
|
||||||
assert.strictEqual(success, true);
|
assert.strictEqual(success, true);
|
||||||
}
|
}
|
||||||
@@ -176,7 +176,7 @@ suite('Notebook Document', function () {
|
|||||||
// replacing all cells
|
// replacing all cells
|
||||||
{
|
{
|
||||||
const edit = new vscode.WorkspaceEdit();
|
const edit = new vscode.WorkspaceEdit();
|
||||||
edit.replaceNotebookCells(document.uri, 0, 1, [{
|
edit.replaceNotebookCells(document.uri, new vscode.NotebookRange(0, 1), [{
|
||||||
kind: vscode.NotebookCellKind.Markdown,
|
kind: vscode.NotebookCellKind.Markdown,
|
||||||
language: 'markdown',
|
language: 'markdown',
|
||||||
metadata: undefined,
|
metadata: undefined,
|
||||||
@@ -199,7 +199,7 @@ suite('Notebook Document', function () {
|
|||||||
// remove all cells
|
// remove all cells
|
||||||
{
|
{
|
||||||
const edit = new vscode.WorkspaceEdit();
|
const edit = new vscode.WorkspaceEdit();
|
||||||
edit.replaceNotebookCells(document.uri, 0, document.cellCount, []);
|
edit.replaceNotebookCells(document.uri, new vscode.NotebookRange(0, document.cellCount), []);
|
||||||
const success = await vscode.workspace.applyEdit(edit);
|
const success = await vscode.workspace.applyEdit(edit);
|
||||||
assert.strictEqual(success, true);
|
assert.strictEqual(success, true);
|
||||||
}
|
}
|
||||||
@@ -212,7 +212,7 @@ suite('Notebook Document', function () {
|
|||||||
assert.strictEqual(document.cellCount, 1);
|
assert.strictEqual(document.cellCount, 1);
|
||||||
|
|
||||||
const edit = new vscode.WorkspaceEdit();
|
const edit = new vscode.WorkspaceEdit();
|
||||||
edit.replaceNotebookCells(document.uri, 0, 0, [{
|
edit.replaceNotebookCells(document.uri, new vscode.NotebookRange(0, 0), [{
|
||||||
kind: vscode.NotebookCellKind.Markdown,
|
kind: vscode.NotebookCellKind.Markdown,
|
||||||
language: 'markdown',
|
language: 'markdown',
|
||||||
metadata: undefined,
|
metadata: undefined,
|
||||||
@@ -320,7 +320,7 @@ suite('Notebook Document', function () {
|
|||||||
assert.strictEqual(notebook.viewType, 'notebook.nbdtest');
|
assert.strictEqual(notebook.viewType, 'notebook.nbdtest');
|
||||||
|
|
||||||
const edit = new vscode.WorkspaceEdit();
|
const edit = new vscode.WorkspaceEdit();
|
||||||
edit.replaceNotebookCells(notebook.uri, 0, 0, [{
|
edit.replaceNotebookCells(notebook.uri, new vscode.NotebookRange(0, 0), [{
|
||||||
kind: vscode.NotebookCellKind.Markdown,
|
kind: vscode.NotebookCellKind.Markdown,
|
||||||
language: 'markdown',
|
language: 'markdown',
|
||||||
metadata: undefined,
|
metadata: undefined,
|
||||||
@@ -364,6 +364,16 @@ suite('Notebook Document', function () {
|
|||||||
assert.strictEqual(opened === closed, true);
|
assert.strictEqual(opened === closed, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('setTextDocumentLanguage when notebook editor is not open', async function () {
|
||||||
|
const uri = await utils.createRandomFile('', undefined, '.nbdtest');
|
||||||
|
const notebook = await vscode.notebook.openNotebookDocument(uri);
|
||||||
|
const firstCelUri = notebook.cellAt(0).document.uri;
|
||||||
|
await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
|
||||||
|
|
||||||
|
let cellDoc = await vscode.workspace.openTextDocument(firstCelUri);
|
||||||
|
cellDoc = await vscode.languages.setTextDocumentLanguage(cellDoc, 'css');
|
||||||
|
assert.strictEqual(cellDoc.languageId, 'css');
|
||||||
|
});
|
||||||
|
|
||||||
test('#117273, Add multiple outputs', async function () {
|
test('#117273, Add multiple outputs', async function () {
|
||||||
|
|
||||||
@@ -410,7 +420,7 @@ suite('Notebook Document', function () {
|
|||||||
assert.strictEqual(document.isDirty, false);
|
assert.strictEqual(document.isDirty, false);
|
||||||
|
|
||||||
const edit = new vscode.WorkspaceEdit();
|
const edit = new vscode.WorkspaceEdit();
|
||||||
edit.replaceNotebookCells(document.uri, 0, document.getCells().length, []);
|
edit.replaceNotebookCells(document.uri, new vscode.NotebookRange(0, document.cellCount), []);
|
||||||
assert.ok(await vscode.workspace.applyEdit(edit));
|
assert.ok(await vscode.workspace.applyEdit(edit));
|
||||||
|
|
||||||
assert.strictEqual(document.isDirty, true);
|
assert.strictEqual(document.isDirty, true);
|
||||||
@@ -425,7 +435,7 @@ suite('Notebook Document', function () {
|
|||||||
assert.strictEqual(document.isDirty, false);
|
assert.strictEqual(document.isDirty, false);
|
||||||
|
|
||||||
const edit = new vscode.WorkspaceEdit();
|
const edit = new vscode.WorkspaceEdit();
|
||||||
edit.replaceNotebookCells(document.uri, 0, document.getCells().length, []);
|
edit.replaceNotebookCells(document.uri, new vscode.NotebookRange(0, document.cellCount), []);
|
||||||
assert.ok(await vscode.workspace.applyEdit(edit));
|
assert.ok(await vscode.workspace.applyEdit(edit));
|
||||||
|
|
||||||
assert.strictEqual(document.isDirty, true);
|
assert.strictEqual(document.isDirty, true);
|
||||||
|
|||||||
@@ -8,6 +8,10 @@ import * as assert from 'assert';
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { createRandomFile, asPromise, disposeAll, closeAllEditors, revertAllDirty, saveAllEditors, assertNoRpc } from '../utils';
|
import { createRandomFile, asPromise, disposeAll, closeAllEditors, revertAllDirty, saveAllEditors, assertNoRpc } from '../utils';
|
||||||
|
|
||||||
|
async function createRandomNotebookFile() {
|
||||||
|
return createRandomFile('', undefined, '.vsctestnb');
|
||||||
|
}
|
||||||
|
|
||||||
// Since `workbench.action.splitEditor` command does await properly
|
// Since `workbench.action.splitEditor` command does await properly
|
||||||
// Notebook editor/document events are not guaranteed to be sent to the ext host when promise resolves
|
// Notebook editor/document events are not guaranteed to be sent to the ext host when promise resolves
|
||||||
// The workaround here is waiting for the first visible notebook editor change event.
|
// The workaround here is waiting for the first visible notebook editor change event.
|
||||||
@@ -53,44 +57,30 @@ async function withEvent<T>(event: vscode.Event<T>, callback: (e: Promise<T>) =>
|
|||||||
await callback(e);
|
await callback(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
const kernel1 = new class implements vscode.NotebookKernel {
|
|
||||||
readonly id = 'mainKernel';
|
|
||||||
readonly label = 'Notebook Test Kernel';
|
|
||||||
readonly isPreferred = true;
|
|
||||||
readonly supportedLanguages = ['typescript', 'javascript'];
|
|
||||||
|
|
||||||
async executeCellsRequest(document: vscode.NotebookDocument, ranges: vscode.NotebookRange[]) {
|
class Kernel {
|
||||||
if (ranges.length > 1 || ranges[0].start + 1 < ranges[0].end) {
|
|
||||||
// Keeping same behavior... if the full notebook is executed, just execute the first cell
|
|
||||||
const task = vscode.notebook.createNotebookCellExecutionTask(document.uri, 0, 'mainKernel');
|
|
||||||
if (!task) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
task.start();
|
readonly controller: vscode.NotebookController;
|
||||||
await task.replaceOutput(new vscode.NotebookCellOutput([
|
|
||||||
new vscode.NotebookCellOutputItem('text/plain', ['my output'], undefined)
|
|
||||||
]));
|
|
||||||
task.end({ success: true });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let range of ranges) {
|
constructor(id: string, label: string) {
|
||||||
for (let i = range.start; i < range.end; i++) {
|
this.controller = vscode.notebook.createNotebookController(id, 'notebookCoreTest', label);
|
||||||
await this.runCell(document, i);
|
this.controller.executeHandler = this._execute.bind(this);
|
||||||
}
|
this.controller.isPreferred = true;
|
||||||
|
this.controller.hasExecutionOrder = true;
|
||||||
|
this.controller.supportedLanguages = ['typescript', 'javascript'];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async _execute(cells: vscode.NotebookCell[]): Promise<void> {
|
||||||
|
for (let cell of cells) {
|
||||||
|
await this._runCell(cell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async runCell(document: vscode.NotebookDocument, idx: number) {
|
protected async _runCell(cell: vscode.NotebookCell) {
|
||||||
const task = vscode.notebook.createNotebookCellExecutionTask(document.uri, idx, 'mainKernel');
|
const task = this.controller.createNotebookCellExecutionTask(cell);
|
||||||
if (!task) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
task.start();
|
task.start();
|
||||||
task.executionOrder = 1;
|
task.executionOrder = 1;
|
||||||
if (document.uri.path.endsWith('customRenderer.vsctestnb')) {
|
if (cell.notebook.uri.path.endsWith('customRenderer.vsctestnb')) {
|
||||||
await task.replaceOutput([new vscode.NotebookCellOutput([
|
await task.replaceOutput([new vscode.NotebookCellOutput([
|
||||||
new vscode.NotebookCellOutputItem('text/custom', ['test'], undefined)
|
new vscode.NotebookCellOutputItem('text/custom', ['test'], undefined)
|
||||||
])]);
|
])]);
|
||||||
@@ -102,82 +92,8 @@ const kernel1 = new class implements vscode.NotebookKernel {
|
|||||||
])]);
|
])]);
|
||||||
task.end({ success: true });
|
task.end({ success: true });
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const kernel2 = new class implements vscode.NotebookKernel {
|
|
||||||
readonly id = 'secondaryKernel';
|
|
||||||
readonly label = 'Notebook Secondary Test Kernel';
|
|
||||||
readonly isPreferred = false;
|
|
||||||
readonly supportedLanguages = ['typescript', 'javascript'];
|
|
||||||
|
|
||||||
async executeCellsRequest(document: vscode.NotebookDocument, ranges: vscode.NotebookRange[]) {
|
|
||||||
if (ranges.length > 1 || ranges[0].start + 1 < ranges[0].end) {
|
|
||||||
// Keeping same behavior... if the full notebook is executed, just execute the first cell
|
|
||||||
const task = vscode.notebook.createNotebookCellExecutionTask(document.uri, 0, 'secondaryKernel');
|
|
||||||
if (!task) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
task.start();
|
|
||||||
await task.replaceOutput([new vscode.NotebookCellOutput([
|
|
||||||
new vscode.NotebookCellOutputItem('text/plain', ['my second output'], undefined)
|
|
||||||
])]);
|
|
||||||
task.end({ success: true });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let range of ranges) {
|
|
||||||
for (let i = range.start; i < range.end; i++) {
|
|
||||||
await this.runCell(document, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async runCell(document: vscode.NotebookDocument, idx: number) {
|
|
||||||
const task = vscode.notebook.createNotebookCellExecutionTask(document.uri, idx, 'mainKernel');
|
|
||||||
if (!task) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
task.start();
|
|
||||||
if (document.uri.path.endsWith('customRenderer.vsctestnb')) {
|
|
||||||
task.replaceOutput([new vscode.NotebookCellOutput([
|
|
||||||
new vscode.NotebookCellOutputItem('text/custom', ['test 2'], undefined)
|
|
||||||
])]);
|
|
||||||
task.end({ success: true });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await task.replaceOutput([new vscode.NotebookCellOutput([
|
|
||||||
new vscode.NotebookCellOutputItem('text/plain', ['my second output'], undefined)
|
|
||||||
])]);
|
|
||||||
task.end({ success: true });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class KernelProvider implements vscode.NotebookKernelProvider {
|
|
||||||
private _onDidChangeKernels = new vscode.EventEmitter<undefined>();
|
|
||||||
onDidChangeKernels = this._onDidChangeKernels.event;
|
|
||||||
|
|
||||||
private _hasKernels = true;
|
|
||||||
private readonly _kernels: vscode.NotebookKernel[] = [kernel1, kernel2];
|
|
||||||
|
|
||||||
addKernel(kernel: vscode.NotebookKernel): void {
|
|
||||||
this._kernels.push(kernel);
|
|
||||||
this._onDidChangeKernels.fire(undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
provideKernels(): vscode.ProviderResult<vscode.NotebookKernel[]> {
|
|
||||||
return this._hasKernels ? this._kernels : [];
|
|
||||||
}
|
|
||||||
|
|
||||||
setHasKernels(hasKernels: boolean): void {
|
|
||||||
this._hasKernels = hasKernels;
|
|
||||||
this._onDidChangeKernels.fire(undefined);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let currentKernelProvider: KernelProvider;
|
|
||||||
|
|
||||||
function getFocusedCell(editor?: vscode.NotebookEditor) {
|
function getFocusedCell(editor?: vscode.NotebookEditor) {
|
||||||
return editor ? editor.document.cellAt(editor.selections[0].start) : undefined;
|
return editor ? editor.document.cellAt(editor.selections[0].start) : undefined;
|
||||||
@@ -253,8 +169,27 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
setup(() => {
|
setup(() => {
|
||||||
currentKernelProvider = new KernelProvider();
|
|
||||||
testDisposables.push(vscode.notebook.registerNotebookKernelProvider({ filenamePattern: '*.vsctestnb' }, currentKernelProvider));
|
const kernel1 = new Kernel('mainKernel', 'Notebook Test Kernel');
|
||||||
|
|
||||||
|
const kernel2 = new class extends Kernel {
|
||||||
|
constructor() {
|
||||||
|
super('secondaryKernel', 'Notebook Secondary Test Kernel');
|
||||||
|
this.controller.isPreferred = false;
|
||||||
|
this.controller.hasExecutionOrder = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
override async _runCell(cell: vscode.NotebookCell) {
|
||||||
|
const task = this.controller.createNotebookCellExecutionTask(cell);
|
||||||
|
task.start();
|
||||||
|
await task.replaceOutput([new vscode.NotebookCellOutput([
|
||||||
|
new vscode.NotebookCellOutputItem('text/plain', ['my second output'], undefined)
|
||||||
|
])]);
|
||||||
|
task.end({ success: true });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
testDisposables.push(kernel1.controller, kernel2.controller);
|
||||||
});
|
});
|
||||||
|
|
||||||
teardown(() => {
|
teardown(() => {
|
||||||
@@ -263,7 +198,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('shared document in notebook editors', async function () {
|
test('shared document in notebook editors', async function () {
|
||||||
const resource = await createRandomFile(undefined, undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
let counter = 0;
|
let counter = 0;
|
||||||
const disposables: vscode.Disposable[] = [];
|
const disposables: vscode.Disposable[] = [];
|
||||||
disposables.push(vscode.notebook.onDidOpenNotebookDocument(() => {
|
disposables.push(vscode.notebook.onDidOpenNotebookDocument(() => {
|
||||||
@@ -284,7 +219,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('editor open/close event', async function () {
|
test('editor open/close event', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
const firstEditorOpen = asPromise(vscode.window.onDidChangeVisibleNotebookEditors);
|
const firstEditorOpen = asPromise(vscode.window.onDidChangeVisibleNotebookEditors);
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
await firstEditorOpen;
|
await firstEditorOpen;
|
||||||
@@ -295,7 +230,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('editor open/close event 2', async function () {
|
test('editor open/close event 2', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
let count = 0;
|
let count = 0;
|
||||||
const disposables: vscode.Disposable[] = [];
|
const disposables: vscode.Disposable[] = [];
|
||||||
disposables.push(vscode.window.onDidChangeVisibleNotebookEditors(() => {
|
disposables.push(vscode.window.onDidChangeVisibleNotebookEditors(() => {
|
||||||
@@ -313,7 +248,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('correct cell selection on undo/redo of cell creation', async function () {
|
test('correct cell selection on undo/redo of cell creation', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
|
await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
|
||||||
await vscode.commands.executeCommand('undo');
|
await vscode.commands.executeCommand('undo');
|
||||||
@@ -332,7 +267,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('editor editing event 2', async function () {
|
test('editor editing event 2', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
|
|
||||||
const cellsChangeEvent = asPromise<vscode.NotebookCellsChangeEvent>(vscode.notebook.onDidChangeNotebookCells);
|
const cellsChangeEvent = asPromise<vscode.NotebookCellsChangeEvent>(vscode.notebook.onDidChangeNotebookCells);
|
||||||
@@ -384,7 +319,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('editor move cell event', async function () {
|
test('editor move cell event', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
|
await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
|
||||||
await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
|
await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
|
||||||
@@ -405,7 +340,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('notebook editor active/visible', async function () {
|
test('notebook editor active/visible', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
const firstEditor = vscode.window.activeNotebookEditor;
|
const firstEditor = vscode.window.activeNotebookEditor;
|
||||||
assert.strictEqual(firstEditor && vscode.window.visibleNotebookEditors.indexOf(firstEditor) >= 0, true);
|
assert.strictEqual(firstEditor && vscode.window.visibleNotebookEditors.indexOf(firstEditor) >= 0, true);
|
||||||
@@ -437,7 +372,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('notebook active editor change', async function () {
|
test('notebook active editor change', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
const firstEditorOpen = asPromise(vscode.window.onDidChangeActiveNotebookEditor);
|
const firstEditorOpen = asPromise(vscode.window.onDidChangeActiveNotebookEditor);
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
await firstEditorOpen;
|
await firstEditorOpen;
|
||||||
@@ -450,7 +385,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('edit API (replaceMetadata)', async function () {
|
test('edit API (replaceMetadata)', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
|
|
||||||
await vscode.window.activeNotebookEditor!.edit(editBuilder => {
|
await vscode.window.activeNotebookEditor!.edit(editBuilder => {
|
||||||
@@ -466,7 +401,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('edit API (replaceMetadata, event)', async function () {
|
test('edit API (replaceMetadata, event)', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
|
|
||||||
const event = asPromise<vscode.NotebookCellMetadataChangeEvent>(vscode.notebook.onDidChangeCellMetadata);
|
const event = asPromise<vscode.NotebookCellMetadataChangeEvent>(vscode.notebook.onDidChangeCellMetadata);
|
||||||
@@ -484,7 +419,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('edit API batch edits', async function () {
|
test('edit API batch edits', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
|
|
||||||
const cellsChangeEvent = asPromise<vscode.NotebookCellsChangeEvent>(vscode.notebook.onDidChangeNotebookCells);
|
const cellsChangeEvent = asPromise<vscode.NotebookCellsChangeEvent>(vscode.notebook.onDidChangeNotebookCells);
|
||||||
@@ -502,7 +437,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('edit API batch edits undo/redo', async function () {
|
test('edit API batch edits undo/redo', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
|
|
||||||
const cellsChangeEvent = asPromise<vscode.NotebookCellsChangeEvent>(vscode.notebook.onDidChangeNotebookCells);
|
const cellsChangeEvent = asPromise<vscode.NotebookCellsChangeEvent>(vscode.notebook.onDidChangeNotebookCells);
|
||||||
@@ -528,7 +463,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('initialzation should not emit cell change events.', async function () {
|
test('initialzation should not emit cell change events.', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
let count = 0;
|
let count = 0;
|
||||||
const disposables: vscode.Disposable[] = [];
|
const disposables: vscode.Disposable[] = [];
|
||||||
disposables.push(vscode.notebook.onDidChangeNotebookCells(() => {
|
disposables.push(vscode.notebook.onDidChangeNotebookCells(() => {
|
||||||
@@ -547,7 +482,7 @@ suite('Notebook API tests', function () {
|
|||||||
// suite('notebook workflow', () => {
|
// suite('notebook workflow', () => {
|
||||||
|
|
||||||
test('notebook open', async function () {
|
test('notebook open', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
||||||
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), 'test');
|
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), 'test');
|
||||||
@@ -578,7 +513,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('notebook cell actions', async function () {
|
test('notebook cell actions', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
||||||
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), 'test');
|
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), 'test');
|
||||||
@@ -651,7 +586,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('notebook join cells', async function () {
|
test('notebook join cells', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
||||||
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), 'test');
|
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), 'test');
|
||||||
@@ -674,7 +609,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('move cells will not recreate cells in ExtHost', async function () {
|
test('move cells will not recreate cells in ExtHost', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
|
await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
|
||||||
await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
|
await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove');
|
||||||
@@ -691,34 +626,34 @@ suite('Notebook API tests', function () {
|
|||||||
await saveFileAndCloseAll(resource);
|
await saveFileAndCloseAll(resource);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('document runnable based on kernel count', async () => {
|
// test('document runnable based on kernel count', async () => {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
// const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
// await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
// assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
||||||
const editor = vscode.window.activeNotebookEditor!;
|
// const editor = vscode.window.activeNotebookEditor!;
|
||||||
|
|
||||||
const cell = editor.document.cellAt(0);
|
// const cell = editor.document.cellAt(0);
|
||||||
assert.strictEqual(cell.outputs.length, 0);
|
// assert.strictEqual(cell.outputs.length, 0);
|
||||||
|
|
||||||
currentKernelProvider.setHasKernels(false);
|
// currentKernelProvider.setHasKernels(false);
|
||||||
await vscode.commands.executeCommand('notebook.execute');
|
// await vscode.commands.executeCommand('notebook.execute');
|
||||||
assert.strictEqual(cell.outputs.length, 0, 'should not execute'); // not runnable, didn't work
|
// assert.strictEqual(cell.outputs.length, 0, 'should not execute'); // not runnable, didn't work
|
||||||
|
|
||||||
currentKernelProvider.setHasKernels(true);
|
// currentKernelProvider.setHasKernels(true);
|
||||||
|
|
||||||
await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs, async (event) => {
|
// await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs, async (event) => {
|
||||||
await vscode.commands.executeCommand('notebook.execute');
|
// await vscode.commands.executeCommand('notebook.execute');
|
||||||
await event;
|
// await event;
|
||||||
assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked
|
// assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked
|
||||||
});
|
// });
|
||||||
|
|
||||||
await saveAllFilesAndCloseAll(undefined);
|
// await saveAllFilesAndCloseAll(undefined);
|
||||||
});
|
// });
|
||||||
|
|
||||||
|
|
||||||
// TODO@rebornix this is wrong, `await vscode.commands.executeCommand('notebook.execute');` doesn't wait until the workspace edit is applied
|
// TODO@rebornix this is wrong, `await vscode.commands.executeCommand('notebook.execute');` doesn't wait until the workspace edit is applied
|
||||||
test.skip('cell execute command takes arguments', async () => {
|
test.skip('cell execute command takes arguments', async () => {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
||||||
const editor = vscode.window.activeNotebookEditor!;
|
const editor = vscode.window.activeNotebookEditor!;
|
||||||
@@ -731,7 +666,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('cell execute command takes arguments 2', async () => {
|
test('cell execute command takes arguments 2', async () => {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
||||||
const editor = vscode.window.activeNotebookEditor!;
|
const editor = vscode.window.activeNotebookEditor!;
|
||||||
@@ -749,7 +684,7 @@ suite('Notebook API tests', function () {
|
|||||||
assert.strictEqual(cell.outputs.length, 0, 'should clear');
|
assert.strictEqual(cell.outputs.length, 0, 'should clear');
|
||||||
});
|
});
|
||||||
|
|
||||||
const secondResource = await createRandomFile('', undefined, '.vsctestnb');
|
const secondResource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest');
|
||||||
|
|
||||||
await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs, async (event) => {
|
await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs, async (event) => {
|
||||||
@@ -763,7 +698,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('document execute command takes arguments', async () => {
|
test('document execute command takes arguments', async () => {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
||||||
const editor = vscode.window.activeNotebookEditor!;
|
const editor = vscode.window.activeNotebookEditor!;
|
||||||
@@ -780,7 +715,7 @@ suite('Notebook API tests', function () {
|
|||||||
await clearChangeEvent;
|
await clearChangeEvent;
|
||||||
assert.strictEqual(cell.outputs.length, 0, 'should clear');
|
assert.strictEqual(cell.outputs.length, 0, 'should clear');
|
||||||
|
|
||||||
const secondResource = await createRandomFile('', undefined, '.vsctestnb');
|
const secondResource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest');
|
||||||
|
|
||||||
await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs, async (event) => {
|
await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs, async (event) => {
|
||||||
@@ -793,15 +728,15 @@ suite('Notebook API tests', function () {
|
|||||||
await saveAllFilesAndCloseAll(undefined);
|
await saveAllFilesAndCloseAll(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('cell execute and select kernel', async () => {
|
test('cell execute and select kernel', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
||||||
const editor = vscode.window.activeNotebookEditor!;
|
const editor = vscode.window.activeNotebookEditor!;
|
||||||
const cell = editor.document.cellAt(0);
|
const cell = editor.document.cellAt(0);
|
||||||
|
|
||||||
vscode.commands.executeCommand('notebook.cell.execute');
|
|
||||||
await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs, async (event) => {
|
await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs, async (event) => {
|
||||||
|
await vscode.commands.executeCommand('notebook.cell.execute');
|
||||||
await event;
|
await event;
|
||||||
assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked
|
assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked
|
||||||
assert.strictEqual(cell.outputs[0].outputs.length, 1);
|
assert.strictEqual(cell.outputs[0].outputs.length, 1);
|
||||||
@@ -811,9 +746,9 @@ suite('Notebook API tests', function () {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
await vscode.commands.executeCommand('notebook.selectKernel', { extension: 'vscode.vscode-api-tests', id: 'secondaryKernel' });
|
|
||||||
vscode.commands.executeCommand('notebook.cell.execute');
|
|
||||||
await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs, async (event) => {
|
await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs, async (event) => {
|
||||||
|
await vscode.commands.executeCommand('notebook.selectKernel', { extension: 'vscode.vscode-api-tests', id: 'secondaryKernel' });
|
||||||
|
await vscode.commands.executeCommand('notebook.cell.execute');
|
||||||
await event;
|
await event;
|
||||||
assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked
|
assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked
|
||||||
assert.strictEqual(cell.outputs[0].outputs.length, 1);
|
assert.strictEqual(cell.outputs[0].outputs.length, 1);
|
||||||
@@ -827,37 +762,35 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('set outputs on cancel', async () => {
|
test('set outputs on cancel', async () => {
|
||||||
const cancelableKernel = new class implements vscode.NotebookKernel {
|
|
||||||
readonly id = 'cancelableKernel';
|
|
||||||
readonly label = 'Notebook Cancelable Test Kernel';
|
|
||||||
readonly isPreferred = false;
|
|
||||||
readonly supportedLanguages = ['typescript', 'javascript'];
|
|
||||||
|
|
||||||
async executeCellsRequest(document: vscode.NotebookDocument, ranges: vscode.NotebookRange[]) {
|
const cancelableKernel = new class extends Kernel {
|
||||||
const idx = ranges[0].start;
|
|
||||||
|
constructor() {
|
||||||
|
super('cancelableKernel', 'Notebook Cancelable Test Kernel');
|
||||||
|
this.controller.isPreferred = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async override _execute(cells: vscode.NotebookCell[]) {
|
||||||
|
for (const cell of cells) {
|
||||||
|
const task = this.controller.createNotebookCellExecutionTask(cell);
|
||||||
|
task.start();
|
||||||
|
task.token.onCancellationRequested(async () => {
|
||||||
|
await task.replaceOutput([new vscode.NotebookCellOutput([
|
||||||
|
new vscode.NotebookCellOutputItem('text/plain', ['Canceled'], undefined)
|
||||||
|
])]);
|
||||||
|
task.end({});
|
||||||
|
});
|
||||||
|
|
||||||
const task = vscode.notebook.createNotebookCellExecutionTask(document.uri, idx, 'cancelableKernel');
|
|
||||||
if (!task) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
task.start();
|
|
||||||
task.token.onCancellationRequested(async () => {
|
|
||||||
await task.replaceOutput([new vscode.NotebookCellOutput([
|
|
||||||
new vscode.NotebookCellOutputItem('text/plain', ['Canceled'], undefined)
|
|
||||||
])]);
|
|
||||||
task.end({});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
currentKernelProvider.addKernel(cancelableKernel);
|
const resource = await createRandomNotebookFile();
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
const editor = vscode.window.activeNotebookEditor!;
|
const editor = vscode.window.activeNotebookEditor!;
|
||||||
const cell = editor.document.cellAt(0);
|
const cell = editor.document.cellAt(0);
|
||||||
|
|
||||||
await vscode.commands.executeCommand('notebook.selectKernel', { extension: 'vscode.vscode-api-tests', id: cancelableKernel.id });
|
await vscode.commands.executeCommand('notebook.selectKernel', { extension: 'vscode.vscode-api-tests', id: cancelableKernel.controller.id });
|
||||||
await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs, async (event) => {
|
await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs, async (event) => {
|
||||||
await vscode.commands.executeCommand('notebook.cell.execute');
|
await vscode.commands.executeCommand('notebook.cell.execute');
|
||||||
await vscode.commands.executeCommand('notebook.cell.cancelExecution');
|
await vscode.commands.executeCommand('notebook.cell.cancelExecution');
|
||||||
@@ -870,30 +803,29 @@ suite('Notebook API tests', function () {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
cancelableKernel.controller.dispose();
|
||||||
await saveAllFilesAndCloseAll(undefined);
|
await saveAllFilesAndCloseAll(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('set outputs on interrupt', async () => {
|
test('set outputs on interrupt', async () => {
|
||||||
const interruptableKernel = new class implements vscode.NotebookKernel {
|
const interruptableKernel = new class extends Kernel {
|
||||||
readonly id = 'interruptableKernel';
|
|
||||||
readonly label = 'Notebook Interruptable Test Kernel';
|
|
||||||
readonly isPreferred = false;
|
constructor() {
|
||||||
readonly supportedLanguages = ['typescript', 'javascript'];
|
super('interruptableKernel', 'Notebook Interruptable Test Kernel');
|
||||||
|
this.controller.isPreferred = false;
|
||||||
|
this.controller.interruptHandler = this.interrupt.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
private _task: vscode.NotebookCellExecutionTask | undefined;
|
private _task: vscode.NotebookCellExecutionTask | undefined;
|
||||||
|
|
||||||
async executeCellsRequest(document: vscode.NotebookDocument, ranges: vscode.NotebookRange[]) {
|
async override _execute(cells: vscode.NotebookCell[]) {
|
||||||
const idx = ranges[0].start;
|
this._task = this.controller.createNotebookCellExecutionTask(cells[0]);
|
||||||
|
|
||||||
this._task = vscode.notebook.createNotebookCellExecutionTask(document.uri, idx, 'interruptableKernel');
|
|
||||||
if (!this._task) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._task.start();
|
this._task.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
async interrupt(_document: vscode.NotebookDocument) {
|
|
||||||
|
async interrupt() {
|
||||||
await this._task!.replaceOutput([new vscode.NotebookCellOutput([
|
await this._task!.replaceOutput([new vscode.NotebookCellOutput([
|
||||||
new vscode.NotebookCellOutputItem('text/plain', ['Interrupted'], undefined)
|
new vscode.NotebookCellOutputItem('text/plain', ['Interrupted'], undefined)
|
||||||
])]);
|
])]);
|
||||||
@@ -901,13 +833,12 @@ suite('Notebook API tests', function () {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
currentKernelProvider.addKernel(interruptableKernel);
|
const resource = await createRandomNotebookFile();
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
const editor = vscode.window.activeNotebookEditor!;
|
const editor = vscode.window.activeNotebookEditor!;
|
||||||
const cell = editor.document.cellAt(0);
|
const cell = editor.document.cellAt(0);
|
||||||
|
|
||||||
await vscode.commands.executeCommand('notebook.selectKernel', { extension: 'vscode.vscode-api-tests', id: interruptableKernel.id });
|
await vscode.commands.executeCommand('notebook.selectKernel', { extension: 'vscode.vscode-api-tests', id: interruptableKernel.controller.id });
|
||||||
await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs, async (event) => {
|
await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs, async (event) => {
|
||||||
await vscode.commands.executeCommand('notebook.cell.execute');
|
await vscode.commands.executeCommand('notebook.cell.execute');
|
||||||
await vscode.commands.executeCommand('notebook.cell.cancelExecution');
|
await vscode.commands.executeCommand('notebook.cell.cancelExecution');
|
||||||
@@ -920,11 +851,12 @@ suite('Notebook API tests', function () {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
interruptableKernel.controller.dispose();
|
||||||
await saveAllFilesAndCloseAll(undefined);
|
await saveAllFilesAndCloseAll(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('onDidChangeCellExecutionState is fired', async () => {
|
test('onDidChangeCellExecutionState is fired', async () => {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
const editor = vscode.window.activeNotebookEditor!;
|
const editor = vscode.window.activeNotebookEditor!;
|
||||||
const cell = editor.document.cellAt(0);
|
const cell = editor.document.cellAt(0);
|
||||||
@@ -955,7 +887,7 @@ suite('Notebook API tests', function () {
|
|||||||
|
|
||||||
// suite('notebook dirty state', () => {
|
// suite('notebook dirty state', () => {
|
||||||
test('notebook open', async function () {
|
test('notebook open', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
||||||
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), 'test');
|
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), 'test');
|
||||||
@@ -987,7 +919,7 @@ suite('Notebook API tests', function () {
|
|||||||
|
|
||||||
// suite('notebook undo redo', () => {
|
// suite('notebook undo redo', () => {
|
||||||
test('notebook open', async function () {
|
test('notebook open', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
||||||
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), 'test');
|
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), 'test');
|
||||||
@@ -1028,29 +960,8 @@ suite('Notebook API tests', function () {
|
|||||||
await saveFileAndCloseAll(resource);
|
await saveFileAndCloseAll(resource);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('change cell language when notebook editor is not open', async function () {
|
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
|
||||||
const firstCell = vscode.window.activeNotebookEditor!.document.cellAt(0);
|
|
||||||
const cellUri = firstCell.document.uri;
|
|
||||||
await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
|
|
||||||
|
|
||||||
let cellDoc = await vscode.workspace.openTextDocument(cellUri);
|
|
||||||
cellDoc = await vscode.languages.setTextDocumentLanguage(cellDoc, 'css');
|
|
||||||
assert.strictEqual(cellDoc.languageId, 'css');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('change cell language when notebook editor is open', async function () {
|
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
|
||||||
|
|
||||||
const firstCell = vscode.window.activeNotebookEditor!.document.cellAt(0);
|
|
||||||
const cellDoc = await vscode.languages.setTextDocumentLanguage(firstCell.document, 'css');
|
|
||||||
assert.strictEqual(cellDoc.languageId, 'css');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('multiple tabs: dirty + clean', async function () {
|
test('multiple tabs: dirty + clean', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
|
await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
|
||||||
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), '');
|
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), '');
|
||||||
@@ -1060,7 +971,7 @@ suite('Notebook API tests', function () {
|
|||||||
edit.insert(getFocusedCell(vscode.window.activeNotebookEditor)!.document.uri, new vscode.Position(0, 0), 'var abc = 0;');
|
edit.insert(getFocusedCell(vscode.window.activeNotebookEditor)!.document.uri, new vscode.Position(0, 0), 'var abc = 0;');
|
||||||
await vscode.workspace.applyEdit(edit);
|
await vscode.workspace.applyEdit(edit);
|
||||||
|
|
||||||
const secondResource = await createRandomFile('', undefined, '.vsctestnb');
|
const secondResource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest');
|
||||||
await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
|
await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
|
||||||
|
|
||||||
@@ -1074,7 +985,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('multiple tabs: two dirty tabs and switching', async function () {
|
test('multiple tabs: two dirty tabs and switching', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
|
await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
|
||||||
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), '');
|
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), '');
|
||||||
@@ -1084,7 +995,7 @@ suite('Notebook API tests', function () {
|
|||||||
edit.insert(getFocusedCell(vscode.window.activeNotebookEditor)!.document.uri, new vscode.Position(0, 0), 'var abc = 0;');
|
edit.insert(getFocusedCell(vscode.window.activeNotebookEditor)!.document.uri, new vscode.Position(0, 0), 'var abc = 0;');
|
||||||
await vscode.workspace.applyEdit(edit);
|
await vscode.workspace.applyEdit(edit);
|
||||||
|
|
||||||
const secondResource = await createRandomFile('', undefined, '.vsctestnb');
|
const secondResource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest');
|
||||||
await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
|
await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
|
||||||
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), '');
|
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), '');
|
||||||
@@ -1107,7 +1018,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test.skip('multiple tabs: different editors with same document', async function () {
|
test.skip('multiple tabs: different editors with same document', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
const firstNotebookEditor = vscode.window.activeNotebookEditor;
|
const firstNotebookEditor = vscode.window.activeNotebookEditor;
|
||||||
assert.strictEqual(firstNotebookEditor !== undefined, true, 'notebook first');
|
assert.strictEqual(firstNotebookEditor !== undefined, true, 'notebook first');
|
||||||
@@ -1127,7 +1038,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('custom metadata should be supported', async function () {
|
test('custom metadata should be supported', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
||||||
assert.strictEqual(vscode.window.activeNotebookEditor!.document.metadata.custom!['testMetadata'] as boolean, false);
|
assert.strictEqual(vscode.window.activeNotebookEditor!.document.metadata.custom!['testMetadata'] as boolean, false);
|
||||||
@@ -1140,7 +1051,7 @@ suite('Notebook API tests', function () {
|
|||||||
|
|
||||||
// TODO@rebornix skip as it crashes the process all the time
|
// TODO@rebornix skip as it crashes the process all the time
|
||||||
test.skip('custom metadata should be supported 2', async function () {
|
test.skip('custom metadata should be supported 2', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
||||||
assert.strictEqual(vscode.window.activeNotebookEditor!.document.metadata.custom!['testMetadata'] as boolean, false);
|
assert.strictEqual(vscode.window.activeNotebookEditor!.document.metadata.custom!['testMetadata'] as boolean, false);
|
||||||
@@ -1158,7 +1069,7 @@ suite('Notebook API tests', function () {
|
|||||||
|
|
||||||
|
|
||||||
test('#106657. Opening a notebook from markers view is broken ', async function () {
|
test('#106657. Opening a notebook from markers view is broken ', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
|
|
||||||
const document = vscode.window.activeNotebookEditor?.document!;
|
const document = vscode.window.activeNotebookEditor?.document!;
|
||||||
@@ -1175,7 +1086,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test.skip('Cannot open notebook from cell-uri with vscode.open-command', async function () {
|
test.skip('Cannot open notebook from cell-uri with vscode.open-command', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
|
|
||||||
const document = vscode.window.activeNotebookEditor?.document!;
|
const document = vscode.window.activeNotebookEditor?.document!;
|
||||||
@@ -1192,7 +1103,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('#97830, #97764. Support switch to other editor types', async function () {
|
test('#97830, #97764. Support switch to other editor types', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
|
await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
|
||||||
const edit = new vscode.WorkspaceEdit();
|
const edit = new vscode.WorkspaceEdit();
|
||||||
@@ -1214,7 +1125,7 @@ suite('Notebook API tests', function () {
|
|||||||
|
|
||||||
// open text editor, pin, and then open a notebook
|
// open text editor, pin, and then open a notebook
|
||||||
test('#96105 - dirty editors', async function () {
|
test('#96105 - dirty editors', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'default');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'default');
|
||||||
const edit = new vscode.WorkspaceEdit();
|
const edit = new vscode.WorkspaceEdit();
|
||||||
edit.insert(resource, new vscode.Position(0, 0), 'var abc = 0;');
|
edit.insert(resource, new vscode.Position(0, 0), 'var abc = 0;');
|
||||||
@@ -1236,7 +1147,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('#102423 - copy/paste shares the same text buffer', async function () {
|
test('#102423 - copy/paste shares the same text buffer', async function () {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
|
|
||||||
let activeCell = getFocusedCell(vscode.window.activeNotebookEditor);
|
let activeCell = getFocusedCell(vscode.window.activeNotebookEditor);
|
||||||
@@ -1260,7 +1171,7 @@ suite('Notebook API tests', function () {
|
|||||||
|
|
||||||
test('#116598, output items change event.', async function () {
|
test('#116598, output items change event.', async function () {
|
||||||
|
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
|
|
||||||
const edit = new vscode.WorkspaceEdit();
|
const edit = new vscode.WorkspaceEdit();
|
||||||
@@ -1286,7 +1197,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('#115855 onDidSaveNotebookDocument', async function () {
|
test('#115855 onDidSaveNotebookDocument', async function () {
|
||||||
const resource = await createRandomFile(undefined, undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
const notebook = await vscode.notebook.openNotebookDocument(resource);
|
const notebook = await vscode.notebook.openNotebookDocument(resource);
|
||||||
const editor = await vscode.window.showNotebookDocument(notebook);
|
const editor = await vscode.window.showNotebookDocument(notebook);
|
||||||
|
|
||||||
@@ -1307,56 +1218,38 @@ suite('Notebook API tests', function () {
|
|||||||
assert.strictEqual(notebook.isDirty, false);
|
assert.strictEqual(notebook.isDirty, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('#116808, active kernel should not be undefined', async function () {
|
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
|
||||||
|
|
||||||
await withEvent(vscode.notebook.onDidChangeActiveNotebookKernel, async event => {
|
|
||||||
await event;
|
|
||||||
assert.notStrictEqual(vscode.window.activeNotebookEditor?.kernel, undefined);
|
|
||||||
assert.strictEqual(vscode.window.activeNotebookEditor?.kernel?.id, 'mainKernel');
|
|
||||||
});
|
|
||||||
|
|
||||||
await saveAllFilesAndCloseAll(resource);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Output changes are applied once the promise resolves', async function () {
|
test('Output changes are applied once the promise resolves', async function () {
|
||||||
const verifyOutputSyncKernel = new class implements vscode.NotebookKernel {
|
const verifyOutputSyncKernel = new class extends Kernel {
|
||||||
readonly id = 'verifyOutputSyncKernel';
|
|
||||||
readonly label = '';
|
|
||||||
readonly isPreferred = false;
|
|
||||||
readonly supportedLanguages = ['typescript', 'javascript'];
|
|
||||||
|
|
||||||
async executeCellsRequest(document: vscode.NotebookDocument, ranges: vscode.NotebookRange[]) {
|
constructor() {
|
||||||
const idx = ranges[0].start;
|
super('verifyOutputSyncKernel', '');
|
||||||
|
this.controller.isPreferred = false;
|
||||||
const task = vscode.notebook.createNotebookCellExecutionTask(document.uri, idx, this.id);
|
}
|
||||||
if (!task) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
override async _execute(cells: vscode.NotebookCell[]) {
|
||||||
|
const [cell] = cells;
|
||||||
|
const task = this.controller.createNotebookCellExecutionTask(cell);
|
||||||
task.start();
|
task.start();
|
||||||
await task.replaceOutput([new vscode.NotebookCellOutput([
|
await task.replaceOutput([new vscode.NotebookCellOutput([
|
||||||
new vscode.NotebookCellOutputItem('text/plain', ['Some output'], undefined)
|
new vscode.NotebookCellOutputItem('text/plain', ['Some output'], undefined)
|
||||||
])]);
|
])]);
|
||||||
assert.strictEqual(document.cellAt(0).outputs.length, 1);
|
assert.strictEqual(cell.notebook.cellAt(0).outputs.length, 1);
|
||||||
assert.deepStrictEqual(document.cellAt(0).outputs[0].outputs[0].value, ['Some output']);
|
assert.deepStrictEqual(cell.notebook.cellAt(0).outputs[0].outputs[0].value, ['Some output']);
|
||||||
task.end({});
|
task.end({});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
currentKernelProvider.addKernel(verifyOutputSyncKernel);
|
const resource = await createRandomNotebookFile();
|
||||||
|
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
await vscode.commands.executeCommand('notebook.selectKernel', { extension: 'vscode.vscode-api-tests', id: verifyOutputSyncKernel.id });
|
await vscode.commands.executeCommand('notebook.selectKernel', { extension: 'vscode.vscode-api-tests', id: verifyOutputSyncKernel.controller.id });
|
||||||
await vscode.commands.executeCommand('notebook.cell.execute');
|
await vscode.commands.executeCommand('notebook.cell.execute');
|
||||||
|
|
||||||
await saveAllFilesAndCloseAll(undefined);
|
await saveAllFilesAndCloseAll(undefined);
|
||||||
|
verifyOutputSyncKernel.controller.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('latestExecutionSummary', async () => {
|
test('latestExecutionSummary', async () => {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
const editor = vscode.window.activeNotebookEditor!;
|
const editor = vscode.window.activeNotebookEditor!;
|
||||||
const cell = editor.document.cellAt(0);
|
const cell = editor.document.cellAt(0);
|
||||||
@@ -1373,7 +1266,7 @@ suite('Notebook API tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('initialize latestExecutionSummary', async () => {
|
test('initialize latestExecutionSummary', async () => {
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
const resource = await createRandomNotebookFile();
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
const editor = vscode.window.activeNotebookEditor!;
|
const editor = vscode.window.activeNotebookEditor!;
|
||||||
const cell = editor.document.cellAt(0);
|
const cell = editor.document.cellAt(0);
|
||||||
@@ -1385,40 +1278,30 @@ suite('Notebook API tests', function () {
|
|||||||
await saveAllFilesAndCloseAll(undefined);
|
await saveAllFilesAndCloseAll(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Throws errors for invalid execution tasks', async function () {
|
|
||||||
let missedError: string | undefined;
|
|
||||||
|
|
||||||
const invalidKernel = new class implements vscode.NotebookKernel {
|
suite('statusbar', () => {
|
||||||
readonly id = 'invalidKernel';
|
const emitter = new vscode.EventEmitter<vscode.NotebookCell>();
|
||||||
readonly label = '';
|
const onDidCallProvide = emitter.event;
|
||||||
readonly isPreferred = false;
|
suiteSetup(() => {
|
||||||
readonly supportedLanguages = ['typescript', 'javascript'];
|
vscode.notebook.registerNotebookCellStatusBarItemProvider({ viewType: 'notebookCoreTest' }, {
|
||||||
|
async provideCellStatusBarItems(cell: vscode.NotebookCell, _token: vscode.CancellationToken): Promise<vscode.NotebookCellStatusBarItem[]> {
|
||||||
|
emitter.fire(cell);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
async executeCellsRequest(document: vscode.NotebookDocument, _ranges: vscode.NotebookRange[]) {
|
test('provideCellStatusBarItems called on metadata change', async function () {
|
||||||
try {
|
const provideCalled = asPromise(onDidCallProvide);
|
||||||
vscode.notebook.createNotebookCellExecutionTask(document.uri, 1000, this.id);
|
const resource = await createRandomNotebookFile();
|
||||||
missedError = 'Expected to throw for invalid index';
|
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
return;
|
await provideCalled;
|
||||||
} catch (e) { }
|
|
||||||
|
|
||||||
try {
|
const edit = new vscode.WorkspaceEdit();
|
||||||
vscode.notebook.createNotebookCellExecutionTask(vscode.Uri.file('slkdf'), 0, this.id);
|
edit.replaceNotebookCellMetadata(resource, 0, new vscode.NotebookCellMetadata().with({ inputCollapsed: true }));
|
||||||
missedError = 'Expected to throw for invalid uri';
|
vscode.workspace.applyEdit(edit);
|
||||||
return;
|
await provideCalled;
|
||||||
} catch (e) { }
|
});
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
currentKernelProvider.addKernel(invalidKernel);
|
|
||||||
|
|
||||||
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
|
||||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
|
||||||
await vscode.commands.executeCommand('notebook.selectKernel', { extension: 'vscode.vscode-api-tests', id: invalidKernel.id });
|
|
||||||
await vscode.commands.executeCommand('notebook.cell.execute');
|
|
||||||
|
|
||||||
assert.strictEqual(missedError, undefined, missedError);
|
|
||||||
|
|
||||||
await saveAllFilesAndCloseAll(undefined);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// });
|
// });
|
||||||
@@ -1430,7 +1313,7 @@ suite('Notebook API tests', function () {
|
|||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// const resource = await createRandomFile('', undefined, '.vsctestnb');
|
// const resource = await createRandomNotebookFile();
|
||||||
// await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
// await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||||
// assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
// assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
||||||
// const uri = vscode.window.activeNotebookEditor!.asWebviewUri(vscode.Uri.file('./hello.png'));
|
// const uri = vscode.window.activeNotebookEditor!.asWebviewUri(vscode.Uri.file('./hello.png'));
|
||||||
|
|||||||
@@ -58,17 +58,16 @@ export function activate(context: vscode.ExtensionContext): any {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const kernel: vscode.NotebookKernel = {
|
const controller = vscode.notebook.createNotebookController(
|
||||||
id: 'notebookSmokeTest',
|
'notebookSmokeTest',
|
||||||
label: 'notebookSmokeTest',
|
{ pattern: '*.smoke-nb' },
|
||||||
isPreferred: true,
|
'notebookSmokeTest'
|
||||||
executeCellsRequest: async (document: vscode.NotebookDocument, ranges: vscode.NotebookRange[]) => {
|
);
|
||||||
const idx = ranges[0].start;
|
|
||||||
const task = vscode.notebook.createNotebookCellExecutionTask(document.uri, idx, 'notebookSmokeTest');
|
|
||||||
if (!task) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
controller.isPreferred = true;
|
||||||
|
controller.executeHandler = (cells) => {
|
||||||
|
for (const cell of cells) {
|
||||||
|
const task = controller.createNotebookCellExecutionTask(cell);
|
||||||
task.start();
|
task.start();
|
||||||
task.replaceOutput([new vscode.NotebookCellOutput([
|
task.replaceOutput([new vscode.NotebookCellOutput([
|
||||||
new vscode.NotebookCellOutputItem('text/html', ['test output'], undefined)
|
new vscode.NotebookCellOutputItem('text/html', ['test output'], undefined)
|
||||||
@@ -77,11 +76,7 @@ export function activate(context: vscode.ExtensionContext): any {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
context.subscriptions.push(vscode.notebook.registerNotebookKernelProvider({ filenamePattern: '*.smoke-nb' }, {
|
context.subscriptions.push(controller);
|
||||||
provideKernels: async () => {
|
|
||||||
return [kernel];
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
context.subscriptions.push(vscode.commands.registerCommand('vscode-notebook-tests.debugAction', async (cell: vscode.NotebookCell) => {
|
context.subscriptions.push(vscode.commands.registerCommand('vscode-notebook-tests.debugAction', async (cell: vscode.NotebookCell) => {
|
||||||
if (cell) {
|
if (cell) {
|
||||||
|
|||||||
Vendored
+107
-96
@@ -1328,18 +1328,6 @@ declare module 'vscode' {
|
|||||||
constructor(cells: NotebookCellData[], metadata?: NotebookDocumentMetadata);
|
constructor(cells: NotebookCellData[], metadata?: NotebookDocumentMetadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @deprecated used NotebookController */
|
|
||||||
export interface NotebookCommunication {
|
|
||||||
/** @deprecated used NotebookController */
|
|
||||||
readonly editorId: string;
|
|
||||||
/** @deprecated used NotebookController */
|
|
||||||
readonly onDidReceiveMessage: Event<any>;
|
|
||||||
/** @deprecated used NotebookController */
|
|
||||||
postMessage(message: any): Thenable<boolean>;
|
|
||||||
/** @deprecated used NotebookController */
|
|
||||||
asWebviewUri(localResource: Uri): Uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NotebookDocumentShowOptions {
|
export interface NotebookDocumentShowOptions {
|
||||||
viewColumn?: ViewColumn;
|
viewColumn?: ViewColumn;
|
||||||
preserveFocus?: boolean;
|
preserveFocus?: boolean;
|
||||||
@@ -1420,17 +1408,14 @@ declare module 'vscode' {
|
|||||||
//#region https://github.com/microsoft/vscode/issues/106744, NotebookEditorEdit
|
//#region https://github.com/microsoft/vscode/issues/106744, NotebookEditorEdit
|
||||||
|
|
||||||
export interface WorkspaceEdit {
|
export interface WorkspaceEdit {
|
||||||
|
// todo@API add NotebookEdit-type which handles all these cases?
|
||||||
replaceNotebookMetadata(uri: Uri, value: NotebookDocumentMetadata): void;
|
replaceNotebookMetadata(uri: Uri, value: NotebookDocumentMetadata): void;
|
||||||
|
replaceNotebookCells(uri: Uri, range: NotebookRange, cells: NotebookCellData[], metadata?: WorkspaceEditEntryMetadata): void;
|
||||||
// todo@API use NotebookCellRange
|
|
||||||
replaceNotebookCells(uri: Uri, start: number, end: number, cells: NotebookCellData[], metadata?: WorkspaceEditEntryMetadata): void;
|
|
||||||
replaceNotebookCellMetadata(uri: Uri, index: number, cellMetadata: NotebookCellMetadata, metadata?: WorkspaceEditEntryMetadata): void;
|
replaceNotebookCellMetadata(uri: Uri, index: number, cellMetadata: NotebookCellMetadata, metadata?: WorkspaceEditEntryMetadata): void;
|
||||||
|
|
||||||
|
//todo@API remove output modifications?
|
||||||
replaceNotebookCellOutput(uri: Uri, index: number, outputs: NotebookCellOutput[], metadata?: WorkspaceEditEntryMetadata): void;
|
replaceNotebookCellOutput(uri: Uri, index: number, outputs: NotebookCellOutput[], metadata?: WorkspaceEditEntryMetadata): void;
|
||||||
appendNotebookCellOutput(uri: Uri, index: number, outputs: NotebookCellOutput[], metadata?: WorkspaceEditEntryMetadata): void;
|
appendNotebookCellOutput(uri: Uri, index: number, outputs: NotebookCellOutput[], metadata?: WorkspaceEditEntryMetadata): void;
|
||||||
|
|
||||||
// TODO@api
|
|
||||||
// https://jupyter-protocol.readthedocs.io/en/latest/messaging.html#update-display-data
|
|
||||||
replaceNotebookCellOutputItems(uri: Uri, index: number, outputId: string, items: NotebookCellOutputItem[], metadata?: WorkspaceEditEntryMetadata): void;
|
replaceNotebookCellOutputItems(uri: Uri, index: number, outputId: string, items: NotebookCellOutputItem[], metadata?: WorkspaceEditEntryMetadata): void;
|
||||||
appendNotebookCellOutputItems(uri: Uri, index: number, outputId: string, items: NotebookCellOutputItem[], metadata?: WorkspaceEditEntryMetadata): void;
|
appendNotebookCellOutputItems(uri: Uri, index: number, outputId: string, items: NotebookCellOutputItem[], metadata?: WorkspaceEditEntryMetadata): void;
|
||||||
}
|
}
|
||||||
@@ -1461,15 +1446,47 @@ declare module 'vscode' {
|
|||||||
|
|
||||||
//#region https://github.com/microsoft/vscode/issues/106744, NotebookSerializer
|
//#region https://github.com/microsoft/vscode/issues/106744, NotebookSerializer
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The notebook serializer enables the editor to open notebook files.
|
||||||
|
*
|
||||||
|
* At its core the editor only knows a [notebook data structure](#NotebookData) but not
|
||||||
|
* how that data structure is written to a file, nor how it is read from a file. The
|
||||||
|
* notebook serializer bridges this gap by deserializing bytes into notebook data and
|
||||||
|
* vice versa.
|
||||||
|
*/
|
||||||
export interface NotebookSerializer {
|
export interface NotebookSerializer {
|
||||||
deserializeNotebook(data: Uint8Array, token: CancellationToken): NotebookData | Thenable<NotebookData>;
|
|
||||||
|
/**
|
||||||
|
* Deserialize contents of a notebook file into the notebook data structure.
|
||||||
|
*
|
||||||
|
* @param content Contents of a notebook file.
|
||||||
|
* @param token A cancellation token.
|
||||||
|
* @return Notebook data or a thenable that resolves to such.
|
||||||
|
*/
|
||||||
|
deserializeNotebook(content: Uint8Array, token: CancellationToken): NotebookData | Thenable<NotebookData>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize notebook data into file contents.
|
||||||
|
*
|
||||||
|
* @param data A notebook data structure.
|
||||||
|
* @param token A cancellation token.
|
||||||
|
* @returns An array of bytes or a thenable that resolves to such.
|
||||||
|
*/
|
||||||
serializeNotebook(data: NotebookData, token: CancellationToken): Uint8Array | Thenable<Uint8Array>;
|
serializeNotebook(data: NotebookData, token: CancellationToken): Uint8Array | Thenable<Uint8Array>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace notebook {
|
export namespace notebook {
|
||||||
|
|
||||||
// todo@API remove output when notebook marks that as transient, same for metadata
|
// todo@API remove output when notebook marks that as transient, same for metadata
|
||||||
export function registerNotebookSerializer(notebookType: string, provider: NotebookSerializer, options?: NotebookDocumentContentOptions): Disposable;
|
/**
|
||||||
|
* Register a [notebook serializer](#NotebookSerializer).
|
||||||
|
*
|
||||||
|
* @param notebookType A notebook.
|
||||||
|
* @param serializer A notebook serialzier.
|
||||||
|
* @param options Optional context options that define what parts of a notebook should be persisted
|
||||||
|
* @return A [disposable](#Disposable) that unregisters this serializer when being disposed.
|
||||||
|
*/
|
||||||
|
export function registerNotebookSerializer(notebookType: string, serializer: NotebookSerializer, options?: NotebookDocumentContentOptions): Disposable;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
@@ -1490,18 +1507,28 @@ declare module 'vscode' {
|
|||||||
* @param cells The notebook cells to execute
|
* @param cells The notebook cells to execute
|
||||||
* @param controller The controller that the handler is attached to
|
* @param controller The controller that the handler is attached to
|
||||||
*/
|
*/
|
||||||
(this: NotebookController, cells: NotebookCell[], controller: NotebookController): void
|
(this: NotebookController, cells: NotebookCell[], controller: NotebookController): void | Thenable<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NotebookInterruptHandler {
|
export interface NotebookInterruptHandler {
|
||||||
(this: NotebookController): void;
|
(this: NotebookController): void | Thenable<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NotebookController {
|
export interface NotebookController {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unique identifier of this notebook controller.
|
||||||
|
*/
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
|
|
||||||
// select notebook of a type and/or by file-pattern
|
/**
|
||||||
|
* The selector allows to narrow down on specific notebook types or
|
||||||
|
* instances.
|
||||||
|
*
|
||||||
|
* For instance `{ viewType: 'notebook.test' }` selects all notebook
|
||||||
|
* documents of the type `notebook.test`, whereas `{ pattern: '/my/file/test.nb' }`
|
||||||
|
* selects only the notebook with the path `/my/file/test.nb`.
|
||||||
|
*/
|
||||||
readonly selector: NotebookSelector;
|
readonly selector: NotebookSelector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1511,13 +1538,41 @@ declare module 'vscode' {
|
|||||||
*/
|
*/
|
||||||
readonly onDidChangeNotebookAssociation: Event<{ notebook: NotebookDocument, selected: boolean }>;
|
readonly onDidChangeNotebookAssociation: Event<{ notebook: NotebookDocument, selected: boolean }>;
|
||||||
|
|
||||||
// UI properties (get/set)
|
/**
|
||||||
|
* The human-readable label of this notebook controller.
|
||||||
|
*/
|
||||||
label: string;
|
label: string;
|
||||||
detail?: string;
|
|
||||||
|
/**
|
||||||
|
* The human-readable description which is rendered less prominent.
|
||||||
|
*/
|
||||||
description?: string;
|
description?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The human-readable detail which is rendered less prominent.
|
||||||
|
*/
|
||||||
|
detail?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks this notebook controller as preferred.
|
||||||
|
*
|
||||||
|
* When multiple notebook controller apply to a single notebook then
|
||||||
|
* users can select one - preferred controllers will be shows more
|
||||||
|
* prominent then.
|
||||||
|
*/
|
||||||
isPreferred?: boolean;
|
isPreferred?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of language identifiers that are supported by this
|
||||||
|
* controller.
|
||||||
|
*/
|
||||||
supportedLanguages: string[];
|
supportedLanguages: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this controller supports execution order so that the
|
||||||
|
* editor can render placeholders for them.
|
||||||
|
*/
|
||||||
|
// todo@API rename to supportsExecutionOrder, usesExecutionOrder
|
||||||
hasExecutionOrder?: boolean;
|
hasExecutionOrder?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1526,8 +1581,16 @@ declare module 'vscode' {
|
|||||||
*/
|
*/
|
||||||
executeHandler: NotebookExecutionHandler;
|
executeHandler: NotebookExecutionHandler;
|
||||||
|
|
||||||
// optional kernel interrupt command
|
/**
|
||||||
|
* The interrupt handler is invoked the interrupt all execution. This is contrary to cancellation (available via
|
||||||
|
* [`NotebookCellExecutionTask#token`](NotebookCellExecutionTask#token)) and should only be used when
|
||||||
|
* execution-level cancellation is supported
|
||||||
|
*/
|
||||||
interruptHandler?: NotebookInterruptHandler
|
interruptHandler?: NotebookInterruptHandler
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispose and free associated resources.
|
||||||
|
*/
|
||||||
dispose(): void;
|
dispose(): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1542,8 +1605,25 @@ declare module 'vscode' {
|
|||||||
|
|
||||||
// ipc
|
// ipc
|
||||||
readonly preloads: NotebookKernelPreload[];
|
readonly preloads: NotebookKernelPreload[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event that fires when a renderer (see `preloads`) has send a message to the controller.
|
||||||
|
*/
|
||||||
readonly onDidReceiveMessage: Event<{ editor: NotebookEditor, message: any }>;
|
readonly onDidReceiveMessage: Event<{ editor: NotebookEditor, message: any }>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message to the renderer of notebook editors.
|
||||||
|
*
|
||||||
|
* Note that only editors showing documents that are bound to this controller
|
||||||
|
* are receiving the message.
|
||||||
|
*
|
||||||
|
* @param message The message to send.
|
||||||
|
* @param editor A specific editor to send the message to. When `undefined` all applicable editors are receiving the message.
|
||||||
|
* @returns A promise that resolves to a boolean indicating if the message has been send or not.
|
||||||
|
*/
|
||||||
postMessage(message: any, editor?: NotebookEditor): Thenable<boolean>;
|
postMessage(message: any, editor?: NotebookEditor): Thenable<boolean>;
|
||||||
|
|
||||||
|
|
||||||
asWebviewUri(localResource: Uri): Uri;
|
asWebviewUri(localResource: Uri): Uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1631,45 +1711,6 @@ declare module 'vscode' {
|
|||||||
uri: Uri;
|
uri: Uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @deprecated used NotebookController */
|
|
||||||
export interface NotebookKernel {
|
|
||||||
|
|
||||||
// todo@API make this mandatory?
|
|
||||||
readonly id?: string;
|
|
||||||
|
|
||||||
label: string;
|
|
||||||
description?: string;
|
|
||||||
detail?: string;
|
|
||||||
isPreferred?: boolean;
|
|
||||||
|
|
||||||
// todo@API do we need an preload change event?
|
|
||||||
preloads?: NotebookKernelPreload[];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* languages supported by kernel
|
|
||||||
* - first is preferred
|
|
||||||
* - `undefined` means all languages available in the editor
|
|
||||||
*/
|
|
||||||
supportedLanguages?: string[];
|
|
||||||
|
|
||||||
// todo@API kernel updating itself
|
|
||||||
// fired when properties like the supported languages etc change
|
|
||||||
// onDidChangeProperties?: Event<void>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A kernel can optionally implement this which will be called when any "cancel" button is clicked in the document.
|
|
||||||
*/
|
|
||||||
interrupt?(document: NotebookDocument): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the user triggers execution of a cell by clicking the run button for a cell, multiple cells,
|
|
||||||
* or full notebook. The cell will be put into the Pending state when this method is called. If
|
|
||||||
* createNotebookCellExecutionTask has not been called by the time the promise returned by this method is
|
|
||||||
* resolved, the cell will be put back into the Idle state.
|
|
||||||
*/
|
|
||||||
executeCellsRequest(document: NotebookDocument, ranges: NotebookRange[]): Thenable<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NotebookCellExecuteStartContext {
|
export interface NotebookCellExecuteStartContext {
|
||||||
/**
|
/**
|
||||||
* The time that execution began, in milliseconds in the Unix epoch. Used to drive the clock
|
* The time that execution began, in milliseconds in the Unix epoch. Used to drive the clock
|
||||||
@@ -1726,12 +1767,7 @@ declare module 'vscode' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export namespace notebook {
|
export namespace notebook {
|
||||||
/**
|
/** @deprecated use NotebookController */
|
||||||
* Creates a [`NotebookCellExecutionTask`](#NotebookCellExecutionTask). Should only be called by a kernel. Returns undefined unless requested by the active kernel.
|
|
||||||
* @param uri The [uri](#Uri) of the notebook document.
|
|
||||||
* @param index The index of the cell.
|
|
||||||
* @param kernelId The id of the kernel requesting this run task. If this kernel is not the current active kernel, `undefined` is returned.
|
|
||||||
*/
|
|
||||||
export function createNotebookCellExecutionTask(uri: Uri, index: number, kernelId: string): NotebookCellExecutionTask | undefined;
|
export function createNotebookCellExecutionTask(uri: Uri, index: number, kernelId: string): NotebookCellExecutionTask | undefined;
|
||||||
|
|
||||||
export const onDidChangeCellExecutionState: Event<NotebookCellExecutionStateChangeEvent>;
|
export const onDidChangeCellExecutionState: Event<NotebookCellExecutionStateChangeEvent>;
|
||||||
@@ -1739,31 +1775,6 @@ declare module 'vscode' {
|
|||||||
|
|
||||||
export type NotebookFilenamePattern = GlobPattern | { include: GlobPattern; exclude: GlobPattern; };
|
export type NotebookFilenamePattern = GlobPattern | { include: GlobPattern; exclude: GlobPattern; };
|
||||||
|
|
||||||
// todo@API why not for NotebookContentProvider?
|
|
||||||
export interface NotebookDocumentFilter {
|
|
||||||
viewType?: string | string[];
|
|
||||||
filenamePattern?: NotebookFilenamePattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated used NotebookController */
|
|
||||||
export interface NotebookKernelProvider<T extends NotebookKernel = NotebookKernel> {
|
|
||||||
onDidChangeKernels?: Event<NotebookDocument | undefined>;
|
|
||||||
provideKernels(document: NotebookDocument, token: CancellationToken): ProviderResult<T[]>;
|
|
||||||
resolveKernel?(kernel: T, document: NotebookDocument, webview: NotebookCommunication, token: CancellationToken): ProviderResult<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NotebookEditor {
|
|
||||||
/** @deprecated kernels are private object*/
|
|
||||||
readonly kernel?: NotebookKernel;
|
|
||||||
}
|
|
||||||
|
|
||||||
export namespace notebook {
|
|
||||||
/** @deprecated */
|
|
||||||
export const onDidChangeActiveNotebookKernel: Event<{ document: NotebookDocument, kernel: NotebookKernel | undefined; }>;
|
|
||||||
/** @deprecated used NotebookController */
|
|
||||||
export function registerNotebookKernelProvider(selector: NotebookDocumentFilter, provider: NotebookKernelProvider): Disposable;
|
|
||||||
}
|
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region https://github.com/microsoft/vscode/issues/106744, NotebookEditorDecorationType
|
//#region https://github.com/microsoft/vscode/issues/106744, NotebookEditorDecorationType
|
||||||
|
|||||||
@@ -3,19 +3,16 @@
|
|||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { flatten } from 'vs/base/common/arrays';
|
|
||||||
import { VSBuffer } from 'vs/base/common/buffer';
|
import { VSBuffer } from 'vs/base/common/buffer';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { Emitter } from 'vs/base/common/event';
|
import { Emitter } from 'vs/base/common/event';
|
||||||
import { IRelativePattern } from 'vs/base/common/glob';
|
import { IRelativePattern } from 'vs/base/common/glob';
|
||||||
import { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';
|
import { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
|
||||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||||
import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService';
|
|
||||||
import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService';
|
import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService';
|
||||||
import { ICellRange, INotebookCellStatusBarItemProvider, INotebookDocumentFilter, INotebookExclusiveDocumentFilter, INotebookKernel, NotebookDataDto, TransientCellMetadata, TransientDocumentMetadata, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
|
||||||
import { NotebookSelector } from 'vs/workbench/contrib/notebook/common/notebookSelector';
|
import { NotebookSelector } from 'vs/workbench/contrib/notebook/common/notebookSelector';
|
||||||
|
import { INotebookCellStatusBarItemProvider, INotebookExclusiveDocumentFilter, NotebookDataDto, TransientCellMetadata, TransientDocumentMetadata, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||||
import { IMainNotebookController, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
|
import { IMainNotebookController, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
|
||||||
import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, MainContext, MainThreadNotebookShape, NotebookExtensionDescription } from '../common/extHost.protocol';
|
import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, MainContext, MainThreadNotebookShape, NotebookExtensionDescription } from '../common/extHost.protocol';
|
||||||
|
|
||||||
@@ -27,43 +24,25 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
|
|||||||
private readonly _proxy: ExtHostNotebookShape;
|
private readonly _proxy: ExtHostNotebookShape;
|
||||||
private readonly _notebookProviders = new Map<string, { controller: IMainNotebookController, disposable: IDisposable }>();
|
private readonly _notebookProviders = new Map<string, { controller: IMainNotebookController, disposable: IDisposable }>();
|
||||||
private readonly _notebookSerializer = new Map<number, IDisposable>();
|
private readonly _notebookSerializer = new Map<number, IDisposable>();
|
||||||
private readonly _notebookKernelProviders = new Map<number, { extension: NotebookExtensionDescription, emitter: Emitter<URI | undefined>, provider: IDisposable }>();
|
|
||||||
private readonly _notebookCellStatusBarRegistrations = new Map<number, IDisposable>();
|
private readonly _notebookCellStatusBarRegistrations = new Map<number, IDisposable>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
extHostContext: IExtHostContext,
|
extHostContext: IExtHostContext,
|
||||||
@INotebookService private readonly _notebookService: INotebookService,
|
@INotebookService private readonly _notebookService: INotebookService,
|
||||||
@INotebookEditorService private readonly _notebookEditorService: INotebookEditorService,
|
|
||||||
@ILogService private readonly _logService: ILogService,
|
|
||||||
@INotebookCellStatusBarService private readonly _cellStatusBarService: INotebookCellStatusBarService,
|
@INotebookCellStatusBarService private readonly _cellStatusBarService: INotebookCellStatusBarService,
|
||||||
) {
|
) {
|
||||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebook);
|
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebook);
|
||||||
this._registerListeners();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose(): void {
|
dispose(): void {
|
||||||
this._disposables.dispose();
|
this._disposables.dispose();
|
||||||
|
|
||||||
// remove all notebook providers
|
// remove all notebook providers
|
||||||
for (const item of this._notebookProviders.values()) {
|
for (const item of this._notebookProviders.values()) {
|
||||||
item.disposable.dispose();
|
item.disposable.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove all kernel providers
|
|
||||||
for (const item of this._notebookKernelProviders.values()) {
|
|
||||||
item.emitter.dispose();
|
|
||||||
item.provider.dispose();
|
|
||||||
}
|
|
||||||
dispose(this._notebookSerializer.values());
|
dispose(this._notebookSerializer.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private _registerListeners(): void {
|
|
||||||
this._disposables.add(this._notebookService.onDidChangeNotebookActiveKernel(e => {
|
|
||||||
this._proxy.$acceptNotebookActiveKernelChange(e);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, options: {
|
async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, options: {
|
||||||
transientOutputs: boolean;
|
transientOutputs: boolean;
|
||||||
transientCellMetadata: TransientCellMetadata;
|
transientCellMetadata: TransientCellMetadata;
|
||||||
@@ -89,12 +68,6 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
|
|||||||
transientOptions: contentOptions
|
transientOptions: contentOptions
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
resolveNotebookEditor: async (viewType: string, uri: URI, editorId: string) => {
|
|
||||||
await this._proxy.$resolveNotebookEditor(viewType, uri, editorId);
|
|
||||||
},
|
|
||||||
onDidReceiveMessage: (editorId: string, rendererType: string | undefined, message: unknown) => {
|
|
||||||
this._proxy.$onDidReceiveMessage(editorId, rendererType, message);
|
|
||||||
},
|
|
||||||
save: async (uri: URI, token: CancellationToken) => {
|
save: async (uri: URI, token: CancellationToken) => {
|
||||||
return this._proxy.$saveNotebook(viewType, uri, token);
|
return this._proxy.$saveNotebook(viewType, uri, token);
|
||||||
},
|
},
|
||||||
@@ -149,55 +122,6 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
|
|||||||
this._notebookSerializer.delete(handle);
|
this._notebookSerializer.delete(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $registerNotebookKernelProvider(extension: NotebookExtensionDescription, handle: number, documentFilter: INotebookDocumentFilter): Promise<void> {
|
|
||||||
const emitter = new Emitter<URI | undefined>();
|
|
||||||
const that = this;
|
|
||||||
|
|
||||||
const provider = this._notebookService.registerNotebookKernelProvider({
|
|
||||||
providerExtensionId: extension.id.value,
|
|
||||||
providerDescription: extension.description,
|
|
||||||
onDidChangeKernels: emitter.event,
|
|
||||||
selector: documentFilter,
|
|
||||||
provideKernels: async (uri: URI, token: CancellationToken): Promise<INotebookKernel[]> => {
|
|
||||||
const result: INotebookKernel[] = [];
|
|
||||||
const kernelsDto = await that._proxy.$provideNotebookKernels(handle, uri, token);
|
|
||||||
for (const dto of kernelsDto) {
|
|
||||||
result.push({
|
|
||||||
id: dto.id,
|
|
||||||
friendlyId: dto.friendlyId,
|
|
||||||
label: dto.label,
|
|
||||||
extension: dto.extension,
|
|
||||||
localResourceRoot: URI.revive(dto.extensionLocation),
|
|
||||||
providerHandle: dto.providerHandle,
|
|
||||||
description: dto.description,
|
|
||||||
detail: dto.detail,
|
|
||||||
isPreferred: dto.isPreferred,
|
|
||||||
preloadProvides: flatten(dto.preloads?.map(p => p.provides) ?? []),
|
|
||||||
preloadUris: dto.preloads?.map(u => URI.revive(u.uri)) ?? [],
|
|
||||||
supportedLanguages: dto.supportedLanguages,
|
|
||||||
implementsInterrupt: dto.implementsInterrupt,
|
|
||||||
implementsExecutionOrder: true, // todo@jrieken this is temporary and for the OLD API only
|
|
||||||
resolve: (uri: URI, editorId: string, token: CancellationToken): Promise<void> => {
|
|
||||||
this._logService.debug('MainthreadNotebooks.resolveNotebookKernel', uri.path, dto.friendlyId);
|
|
||||||
return this._proxy.$resolveNotebookKernel(handle, editorId, uri, dto.friendlyId, token);
|
|
||||||
},
|
|
||||||
executeNotebookCellsRequest: (uri: URI, cellRanges: ICellRange[]): Promise<void> => {
|
|
||||||
this._logService.debug('MainthreadNotebooks.executeNotebookCell', uri.path, dto.friendlyId, cellRanges);
|
|
||||||
return this._proxy.$executeNotebookKernelFromProvider(handle, uri, dto.friendlyId, cellRanges);
|
|
||||||
},
|
|
||||||
cancelNotebookCellExecution: (uri: URI, cellRanges: ICellRange[]): Promise<void> => {
|
|
||||||
this._logService.debug('MainthreadNotebooks.cancelNotebookCellExecution', uri.path, dto.friendlyId, cellRanges);
|
|
||||||
return this._proxy.$cancelNotebookCellExecution(handle, uri, dto.friendlyId, cellRanges);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this._notebookKernelProviders.set(handle, { extension, emitter, provider });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$emitCellStatusBarEvent(eventHandle: number): void {
|
$emitCellStatusBarEvent(eventHandle: number): void {
|
||||||
const emitter = this._notebookCellStatusBarRegistrations.get(eventHandle);
|
const emitter = this._notebookCellStatusBarRegistrations.get(eventHandle);
|
||||||
if (emitter instanceof Emitter) {
|
if (emitter instanceof Emitter) {
|
||||||
@@ -245,29 +169,4 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
|
|||||||
unregisterThing(eventHandle);
|
unregisterThing(eventHandle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async $unregisterNotebookKernelProvider(handle: number): Promise<void> {
|
|
||||||
const entry = this._notebookKernelProviders.get(handle);
|
|
||||||
|
|
||||||
if (entry) {
|
|
||||||
entry.emitter.dispose();
|
|
||||||
entry.provider.dispose();
|
|
||||||
this._notebookKernelProviders.delete(handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$onNotebookKernelChange(handle: number, uriComponents: UriComponents): void {
|
|
||||||
const entry = this._notebookKernelProviders.get(handle);
|
|
||||||
|
|
||||||
entry?.emitter.fire(uriComponents ? URI.revive(uriComponents) : undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
async $postMessage(id: string, forRendererId: string | undefined, value: any): Promise<boolean> {
|
|
||||||
const editor = this._notebookEditorService.getNotebookEditor(id);
|
|
||||||
if (!editor) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
editor.postMessage(forRendererId, value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookS
|
|||||||
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
|
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
|
||||||
import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, MainThreadNotebookDocumentsShape } from '../common/extHost.protocol';
|
import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, MainThreadNotebookDocumentsShape } from '../common/extHost.protocol';
|
||||||
import { MainThreadNotebooksAndEditors } from 'vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors';
|
import { MainThreadNotebooksAndEditors } from 'vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors';
|
||||||
|
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||||
|
|
||||||
export class MainThreadNotebookDocuments implements MainThreadNotebookDocumentsShape {
|
export class MainThreadNotebookDocuments implements MainThreadNotebookDocumentsShape {
|
||||||
|
|
||||||
@@ -139,6 +140,12 @@ export class MainThreadNotebookDocuments implements MainThreadNotebookDocumentsS
|
|||||||
throw new Error(`Can't apply edits to unknown notebook model: ${resource}`);
|
throw new Error(`Can't apply edits to unknown notebook model: ${resource}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
textModel.applyEdits(cellEdits, true, undefined, () => undefined, undefined, computeUndoRedo);
|
try {
|
||||||
|
textModel.applyEdits(cellEdits, true, undefined, () => undefined, undefined, computeUndoRedo);
|
||||||
|
} catch (e) {
|
||||||
|
// Clearing outputs at the same time as the EH calling append/replaceOutputItems is an expected race, and it should be a no-op.
|
||||||
|
// And any other failure should not throw back to the extension.
|
||||||
|
onUnexpectedError(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,17 +77,6 @@ export class MainThreadNotebookEditors implements MainThreadNotebookEditorsShape
|
|||||||
this._proxy.$acceptEditorPropertiesChanged(editor.getId(), { selections: { selections: editor.getSelections() } });
|
this._proxy.$acceptEditorPropertiesChanged(editor.getId(), { selections: { selections: editor.getSelections() } });
|
||||||
}));
|
}));
|
||||||
|
|
||||||
editorDisposables.add(editor.onDidChangeKernel(() => {
|
|
||||||
if (!editor.hasModel()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._proxy.$acceptNotebookActiveKernelChange({
|
|
||||||
uri: editor.viewModel.uri,
|
|
||||||
providerHandle: editor.activeKernel?.providerHandle,
|
|
||||||
kernelFriendlyId: editor.activeKernel?.friendlyId
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
const wrapper = new MainThreadNotebook(editor, editorDisposables);
|
const wrapper = new MainThreadNotebook(editor, editorDisposables);
|
||||||
this._mainThreadEditors.set(editor.getId(), wrapper);
|
this._mainThreadEditors.set(editor.getId(), wrapper);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,16 +11,16 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
|||||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||||
import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||||
import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService';
|
import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService';
|
||||||
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
import { INotebookKernel, INotebookKernelChangeEvent } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||||
import { INotebookKernel2, INotebookKernel2ChangeEvent, INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
|
import { INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
|
||||||
import { NotebookSelector } from 'vs/workbench/contrib/notebook/common/notebookSelector';
|
import { NotebookSelector } from 'vs/workbench/contrib/notebook/common/notebookSelector';
|
||||||
import { ExtHostContext, ExtHostNotebookKernelsShape, IExtHostContext, INotebookKernelDto2, MainContext, MainThreadNotebookKernelsShape } from '../common/extHost.protocol';
|
import { ExtHostContext, ExtHostNotebookKernelsShape, IExtHostContext, INotebookKernelDto2, MainContext, MainThreadNotebookKernelsShape } from '../common/extHost.protocol';
|
||||||
|
|
||||||
abstract class MainThreadKernel implements INotebookKernel2 {
|
abstract class MainThreadKernel implements INotebookKernel {
|
||||||
|
|
||||||
private readonly _onDidChange = new Emitter<INotebookKernel2ChangeEvent>();
|
private readonly _onDidChange = new Emitter<INotebookKernelChangeEvent>();
|
||||||
private readonly preloads: { uri: URI, provides: string[] }[];
|
private readonly preloads: { uri: URI, provides: string[] }[];
|
||||||
readonly onDidChange: Event<INotebookKernel2ChangeEvent> = this._onDidChange.event;
|
readonly onDidChange: Event<INotebookKernelChangeEvent> = this._onDidChange.event;
|
||||||
|
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
readonly selector: NotebookSelector;
|
readonly selector: NotebookSelector;
|
||||||
@@ -61,7 +61,8 @@ abstract class MainThreadKernel implements INotebookKernel2 {
|
|||||||
|
|
||||||
|
|
||||||
update(data: Partial<INotebookKernelDto2>) {
|
update(data: Partial<INotebookKernelDto2>) {
|
||||||
const event: INotebookKernel2ChangeEvent = Object.create(null);
|
|
||||||
|
const event: INotebookKernelChangeEvent = Object.create(null);
|
||||||
if (data.label !== undefined) {
|
if (data.label !== undefined) {
|
||||||
this.label = data.label;
|
this.label = data.label;
|
||||||
event.label = true;
|
event.label = true;
|
||||||
@@ -89,13 +90,8 @@ abstract class MainThreadKernel implements INotebookKernel2 {
|
|||||||
this._onDidChange.fire(event);
|
this._onDidChange.fire(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract executeNotebookCellsRequest(uri: URI, ranges: ICellRange[]): Promise<void>;
|
abstract executeNotebookCellsRequest(uri: URI, cellHandles: number[]): Promise<void>;
|
||||||
abstract cancelNotebookCellExecution(uri: URI, ranges: ICellRange[]): Promise<void>;
|
abstract cancelNotebookCellExecution(uri: URI, cellHandles: number[]): Promise<void>;
|
||||||
|
|
||||||
// old stuff
|
|
||||||
readonly resolve = () => Promise.resolve();
|
|
||||||
get friendlyId() { return this.id; }
|
|
||||||
get providerHandle() { return undefined; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@extHostNamedCustomer(MainContext.MainThreadNotebookKernels)
|
@extHostNamedCustomer(MainContext.MainThreadNotebookKernels)
|
||||||
@@ -137,7 +133,7 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape
|
|||||||
if (!editor.hasModel()) {
|
if (!editor.hasModel()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const kernel = this._notebookKernelService.getBoundKernel(editor.viewModel.notebookDocument);
|
const { bound: kernel } = this._notebookKernelService.getNotebookKernels(editor.viewModel.notebookDocument);
|
||||||
if (!kernel) {
|
if (!kernel) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -167,7 +163,7 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape
|
|||||||
if (!editor.hasModel()) {
|
if (!editor.hasModel()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (this._notebookKernelService.getBoundKernel(editor.viewModel.notebookDocument) !== kernel) {
|
if (this._notebookKernelService.getNotebookKernels(editor.viewModel.notebookDocument).bound !== kernel) {
|
||||||
// different kernel
|
// different kernel
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -190,19 +186,19 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape
|
|||||||
async $addKernel(handle: number, data: INotebookKernelDto2): Promise<void> {
|
async $addKernel(handle: number, data: INotebookKernelDto2): Promise<void> {
|
||||||
const that = this;
|
const that = this;
|
||||||
const kernel = new class extends MainThreadKernel {
|
const kernel = new class extends MainThreadKernel {
|
||||||
async executeNotebookCellsRequest(uri: URI, ranges: ICellRange[]): Promise<void> {
|
async executeNotebookCellsRequest(uri: URI, handles: number[]): Promise<void> {
|
||||||
await that._proxy.$executeCells(handle, uri, ranges);
|
await that._proxy.$executeCells(handle, uri, handles);
|
||||||
}
|
}
|
||||||
async cancelNotebookCellExecution(uri: URI, ranges: ICellRange[]): Promise<void> {
|
async cancelNotebookCellExecution(uri: URI, handles: number[]): Promise<void> {
|
||||||
await that._proxy.$cancelCells(handle, uri, ranges);
|
await that._proxy.$cancelCells(handle, uri, handles);
|
||||||
}
|
}
|
||||||
}(data);
|
}(data);
|
||||||
const registration = this._notebookKernelService.registerKernel(kernel);
|
const registration = this._notebookKernelService.registerKernel(kernel);
|
||||||
|
|
||||||
const listener = this._notebookKernelService.onDidChangeNotebookKernelBinding(e => {
|
const listener = this._notebookKernelService.onDidChangeNotebookKernelBinding(e => {
|
||||||
if (e.oldKernel === kernel) {
|
if (e.oldKernel === kernel.id) {
|
||||||
this._proxy.$acceptSelection(handle, e.notebook, false);
|
this._proxy.$acceptSelection(handle, e.notebook, false);
|
||||||
} else if (e.newKernel === kernel) {
|
} else if (e.newKernel === kernel.id) {
|
||||||
this._proxy.$acceptSelection(handle, e.notebook, true);
|
this._proxy.$acceptSelection(handle, e.notebook, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
|||||||
const extHostDocuments = rpcProtocol.set(ExtHostContext.ExtHostDocuments, new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors));
|
const extHostDocuments = rpcProtocol.set(ExtHostContext.ExtHostDocuments, new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors));
|
||||||
const extHostDocumentContentProviders = rpcProtocol.set(ExtHostContext.ExtHostDocumentContentProviders, new ExtHostDocumentContentProvider(rpcProtocol, extHostDocumentsAndEditors, extHostLogService));
|
const extHostDocumentContentProviders = rpcProtocol.set(ExtHostContext.ExtHostDocumentContentProviders, new ExtHostDocumentContentProvider(rpcProtocol, extHostDocumentsAndEditors, extHostLogService));
|
||||||
const extHostDocumentSaveParticipant = rpcProtocol.set(ExtHostContext.ExtHostDocumentSaveParticipant, new ExtHostDocumentSaveParticipant(extHostLogService, extHostDocuments, rpcProtocol.getProxy(MainContext.MainThreadBulkEdits)));
|
const extHostDocumentSaveParticipant = rpcProtocol.set(ExtHostContext.ExtHostDocumentSaveParticipant, new ExtHostDocumentSaveParticipant(extHostLogService, extHostDocuments, rpcProtocol.getProxy(MainContext.MainThreadBulkEdits)));
|
||||||
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, extHostDocuments, initData.environment, extHostLogService, extensionStoragePaths));
|
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, extHostDocuments, extHostLogService, extensionStoragePaths));
|
||||||
const extHostNotebookKernels = rpcProtocol.set(ExtHostContext.ExtHostNotebookKernels, new ExtHostNotebookKernels(rpcProtocol, initData, extHostNotebook));
|
const extHostNotebookKernels = rpcProtocol.set(ExtHostContext.ExtHostNotebookKernels, new ExtHostNotebookKernels(rpcProtocol, initData, extHostNotebook));
|
||||||
const extHostEditors = rpcProtocol.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(rpcProtocol, extHostDocumentsAndEditors));
|
const extHostEditors = rpcProtocol.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(rpcProtocol, extHostDocumentsAndEditors));
|
||||||
const extHostTreeViews = rpcProtocol.set(ExtHostContext.ExtHostTreeViews, new ExtHostTreeViews(rpcProtocol.getProxy(MainContext.MainThreadTreeViews), extHostCommands, extHostLogService));
|
const extHostTreeViews = rpcProtocol.set(ExtHostContext.ExtHostTreeViews, new ExtHostTreeViews(rpcProtocol.getProxy(MainContext.MainThreadTreeViews), extHostCommands, extHostLogService));
|
||||||
@@ -1057,10 +1057,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
|||||||
checkProposedApiEnabled(extension);
|
checkProposedApiEnabled(extension);
|
||||||
return extHostNotebook.notebookDocuments.map(d => d.notebookDocument);
|
return extHostNotebook.notebookDocuments.map(d => d.notebookDocument);
|
||||||
},
|
},
|
||||||
get onDidChangeActiveNotebookKernel() {
|
|
||||||
checkProposedApiEnabled(extension);
|
|
||||||
return extHostNotebook.onDidChangeActiveNotebookKernel;
|
|
||||||
},
|
|
||||||
registerNotebookSerializer(viewType, serializer, options) {
|
registerNotebookSerializer(viewType, serializer, options) {
|
||||||
checkProposedApiEnabled(extension);
|
checkProposedApiEnabled(extension);
|
||||||
return extHostNotebook.registerNotebookSerializer(extension, viewType, serializer, options);
|
return extHostNotebook.registerNotebookSerializer(extension, viewType, serializer, options);
|
||||||
@@ -1069,10 +1065,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
|||||||
checkProposedApiEnabled(extension);
|
checkProposedApiEnabled(extension);
|
||||||
return extHostNotebook.registerNotebookContentProvider(extension, viewType, provider, options);
|
return extHostNotebook.registerNotebookContentProvider(extension, viewType, provider, options);
|
||||||
},
|
},
|
||||||
registerNotebookKernelProvider: (selector: vscode.NotebookDocumentFilter, provider: vscode.NotebookKernelProvider) => {
|
|
||||||
checkProposedApiEnabled(extension);
|
|
||||||
return extHostNotebook.registerNotebookKernelProvider(extension, selector, provider);
|
|
||||||
},
|
|
||||||
registerNotebookCellStatusBarItemProvider: (selector: vscode.NotebookSelector, provider: vscode.NotebookCellStatusBarItemProvider) => {
|
registerNotebookCellStatusBarItemProvider: (selector: vscode.NotebookSelector, provider: vscode.NotebookCellStatusBarItemProvider) => {
|
||||||
checkProposedApiEnabled(extension);
|
checkProposedApiEnabled(extension);
|
||||||
return extHostNotebook.registerNotebookCellStatusBarItemProvider(extension, selector, provider);
|
return extHostNotebook.registerNotebookCellStatusBarItemProvider(extension, selector, provider);
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
|
|||||||
import { TunnelCreationOptions, TunnelProviderFeatures, TunnelOptions, ProvidedPortAttributes } from 'vs/platform/remote/common/tunnel';
|
import { TunnelCreationOptions, TunnelProviderFeatures, TunnelOptions, ProvidedPortAttributes } from 'vs/platform/remote/common/tunnel';
|
||||||
import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline';
|
import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline';
|
||||||
import { revive } from 'vs/base/common/marshalling';
|
import { revive } from 'vs/base/common/marshalling';
|
||||||
import { NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEventDto, NotebookDataDto, IMainCellDto, INotebookDocumentFilter, TransientCellMetadata, ICellRange, INotebookDecorationRenderOptions, INotebookExclusiveDocumentFilter, IOutputDto, TransientOptions, IImmediateCellEditOperation, INotebookCellStatusBarItem, TransientDocumentMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
import { NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEventDto, NotebookDataDto, IMainCellDto, TransientCellMetadata, ICellRange, INotebookDecorationRenderOptions, INotebookExclusiveDocumentFilter, IOutputDto, TransientOptions, IImmediateCellEditOperation, INotebookCellStatusBarItem, TransientDocumentMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||||
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||||
import { Dto } from 'vs/base/common/types';
|
import { Dto } from 'vs/base/common/types';
|
||||||
import { DebugConfigurationProviderTriggerKind, TestResultState } from 'vs/workbench/api/common/extHostTypes';
|
import { DebugConfigurationProviderTriggerKind, TestResultState } from 'vs/workbench/api/common/extHostTypes';
|
||||||
@@ -884,13 +884,9 @@ export interface MainThreadNotebookShape extends IDisposable {
|
|||||||
$registerNotebookSerializer(handle: number, extension: NotebookExtensionDescription, viewType: string, options: TransientOptions): void;
|
$registerNotebookSerializer(handle: number, extension: NotebookExtensionDescription, viewType: string, options: TransientOptions): void;
|
||||||
$unregisterNotebookSerializer(handle: number): void;
|
$unregisterNotebookSerializer(handle: number): void;
|
||||||
|
|
||||||
$registerNotebookKernelProvider(extension: NotebookExtensionDescription, handle: number, documentFilter: INotebookDocumentFilter): Promise<void>;
|
|
||||||
$unregisterNotebookKernelProvider(handle: number): Promise<void>;
|
|
||||||
$registerNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined, selector: NotebookSelector): Promise<void>;
|
$registerNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined, selector: NotebookSelector): Promise<void>;
|
||||||
$unregisterNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined): Promise<void>;
|
$unregisterNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined): Promise<void>;
|
||||||
$emitCellStatusBarEvent(eventHandle: number): void;
|
$emitCellStatusBarEvent(eventHandle: number): void;
|
||||||
$onNotebookKernelChange(handle: number, uri: UriComponents | undefined): void;
|
|
||||||
$postMessage(editorId: string, forRendererId: string | undefined, value: any): Promise<boolean>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MainThreadNotebookEditorsShape extends IDisposable {
|
export interface MainThreadNotebookEditorsShape extends IDisposable {
|
||||||
@@ -1925,15 +1921,8 @@ export interface INotebookKernelInfoDto2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ExtHostNotebookShape extends ExtHostNotebookDocumentsAndEditorsShape, ExtHostNotebookDocumentsShape, ExtHostNotebookEditorsShape {
|
export interface ExtHostNotebookShape extends ExtHostNotebookDocumentsAndEditorsShape, ExtHostNotebookDocumentsShape, ExtHostNotebookEditorsShape {
|
||||||
$resolveNotebookEditor(viewType: string, uri: UriComponents, editorId: string): Promise<void>;
|
|
||||||
$acceptNotebookActiveKernelChange(event: { uri: UriComponents, providerHandle: number | undefined, kernelFriendlyId: string | undefined }): void;
|
|
||||||
$provideNotebookKernels(handle: number, uri: UriComponents, token: CancellationToken): Promise<INotebookKernelInfoDto2[]>;
|
|
||||||
$resolveNotebookKernel(handle: number, editorId: string, uri: UriComponents, kernelId: string, token: CancellationToken): Promise<void>;
|
|
||||||
$executeNotebookKernelFromProvider(handle: number, uri: UriComponents, kernelId: string, cellRanges: ICellRange[]): Promise<void>;
|
|
||||||
$cancelNotebookCellExecution(handle: number, uri: UriComponents, kernelId: string, cellRange: ICellRange[]): Promise<void>;
|
|
||||||
$provideNotebookCellStatusBarItems(handle: number, uri: UriComponents, index: number, token: CancellationToken): Promise<INotebookCellStatusBarListDto | undefined>;
|
$provideNotebookCellStatusBarItems(handle: number, uri: UriComponents, index: number, token: CancellationToken): Promise<INotebookCellStatusBarListDto | undefined>;
|
||||||
$releaseNotebookCellStatusBarItems(id: number): void;
|
$releaseNotebookCellStatusBarItems(id: number): void;
|
||||||
$onDidReceiveMessage(editorId: string, rendererId: string | undefined, message: unknown): void;
|
|
||||||
|
|
||||||
$openNotebook(viewType: string, uri: UriComponents, backupId: string | undefined, untitledDocumentData: VSBuffer | undefined, token: CancellationToken): Promise<NotebookDataDto>;
|
$openNotebook(viewType: string, uri: UriComponents, backupId: string | undefined, untitledDocumentData: VSBuffer | undefined, token: CancellationToken): Promise<NotebookDataDto>;
|
||||||
$saveNotebook(viewType: string, uri: UriComponents, token: CancellationToken): Promise<boolean>;
|
$saveNotebook(viewType: string, uri: UriComponents, token: CancellationToken): Promise<boolean>;
|
||||||
@@ -1964,8 +1953,8 @@ export interface ExtHostNotebookEditorsShape {
|
|||||||
|
|
||||||
export interface ExtHostNotebookKernelsShape {
|
export interface ExtHostNotebookKernelsShape {
|
||||||
$acceptSelection(handle: number, uri: UriComponents, value: boolean): void;
|
$acceptSelection(handle: number, uri: UriComponents, value: boolean): void;
|
||||||
$executeCells(handle: number, uri: UriComponents, ranges: ICellRange[]): Promise<void>;
|
$executeCells(handle: number, uri: UriComponents, handles: number[]): Promise<void>;
|
||||||
$cancelCells(handle: number, uri: UriComponents, ranges: ICellRange[]): Promise<void>;
|
$cancelCells(handle: number, uri: UriComponents, handles: number[]): Promise<void>;
|
||||||
$acceptRendererMessage(handle: number, editorId: string, message: any): void;
|
$acceptRendererMessage(handle: number, editorId: string, message: any): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,17 +7,15 @@ import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cance
|
|||||||
import { Emitter, Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||||
import * as UUID from 'vs/base/common/uuid';
|
|
||||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||||
import { ExtHostNotebookShape, IMainContext, IModelAddedData, INotebookCellStatusBarListDto, INotebookDocumentPropertiesChangeData, INotebookDocumentsAndEditorsDelta, INotebookDocumentShowOptions, INotebookEditorAddData, INotebookEditorPropertiesChangeData, INotebookEditorViewColumnInfo, INotebookKernelInfoDto2, MainContext, MainThreadNotebookDocumentsShape, MainThreadNotebookEditorsShape, MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol';
|
import { ExtHostNotebookShape, IMainContext, IModelAddedData, INotebookCellStatusBarListDto, INotebookDocumentPropertiesChangeData, INotebookDocumentsAndEditorsDelta, INotebookDocumentShowOptions, INotebookEditorAddData, INotebookEditorPropertiesChangeData, INotebookEditorViewColumnInfo, MainContext, MainThreadNotebookDocumentsShape, MainThreadNotebookEditorsShape, MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { CommandsConverter, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
import { CommandsConverter, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||||
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
|
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
|
||||||
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||||
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
||||||
import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/webview';
|
import { CellEditType, INotebookExclusiveDocumentFilter, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookDataDto, NullablePartialNotebookCellMetadata, IImmediateCellEditOperation } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||||
import { CellEditType, ICellRange, INotebookExclusiveDocumentFilter, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookDataDto, NullablePartialNotebookCellMetadata, IImmediateCellEditOperation } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
|
||||||
import type * as vscode from 'vscode';
|
import type * as vscode from 'vscode';
|
||||||
import { ResourceMap } from 'vs/base/common/map';
|
import { ResourceMap } from 'vs/base/common/map';
|
||||||
import { ExtHostCell, ExtHostNotebookDocument } from './extHostNotebookDocument';
|
import { ExtHostCell, ExtHostNotebookDocument } from './extHostNotebookDocument';
|
||||||
@@ -30,162 +28,6 @@ import { hash } from 'vs/base/common/hash';
|
|||||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||||
import { Cache } from 'vs/workbench/api/common/cache';
|
import { Cache } from 'vs/workbench/api/common/cache';
|
||||||
|
|
||||||
class ExtHostWebviewCommWrapper extends Disposable {
|
|
||||||
private readonly _onDidReceiveDocumentMessage = new Emitter<any>();
|
|
||||||
private readonly _rendererIdToEmitters = new Map<string, Emitter<any>>();
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private _editorId: string,
|
|
||||||
public uri: URI,
|
|
||||||
private _proxy: MainThreadNotebookShape,
|
|
||||||
private _webviewInitData: WebviewInitData,
|
|
||||||
public document: ExtHostNotebookDocument,
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public onDidReceiveMessage(forRendererId: string | undefined, message: any) {
|
|
||||||
this._onDidReceiveDocumentMessage.fire(message);
|
|
||||||
if (forRendererId !== undefined) {
|
|
||||||
this._rendererIdToEmitters.get(forRendererId)?.fire(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly contentProviderComm: vscode.NotebookCommunication = {
|
|
||||||
editorId: this._editorId,
|
|
||||||
onDidReceiveMessage: this._onDidReceiveDocumentMessage.event,
|
|
||||||
postMessage: (message: any) => this._proxy.$postMessage(this._editorId, undefined, message),
|
|
||||||
asWebviewUri: (uri: vscode.Uri) => this._asWebviewUri(uri),
|
|
||||||
};
|
|
||||||
|
|
||||||
public getRendererComm(rendererId: string): vscode.NotebookCommunication {
|
|
||||||
const emitter = new Emitter<any>();
|
|
||||||
this._rendererIdToEmitters.set(rendererId, emitter);
|
|
||||||
return {
|
|
||||||
editorId: this._editorId,
|
|
||||||
onDidReceiveMessage: emitter.event,
|
|
||||||
postMessage: (message: any) => this._proxy.$postMessage(this._editorId, rendererId, message),
|
|
||||||
asWebviewUri: (uri: vscode.Uri) => this._asWebviewUri(uri),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private _asWebviewUri(localResource: vscode.Uri): vscode.Uri {
|
|
||||||
return asWebviewUri(this._webviewInitData, this._editorId, localResource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ExtHostNotebookKernelProviderAdapter extends Disposable {
|
|
||||||
private _kernelToFriendlyId = new ResourceMap<Map<vscode.NotebookKernel, string>>();
|
|
||||||
private _friendlyIdToKernel = new ResourceMap<Map<string, vscode.NotebookKernel>>();
|
|
||||||
constructor(
|
|
||||||
private readonly _proxy: MainThreadNotebookShape,
|
|
||||||
private readonly _handle: number,
|
|
||||||
private readonly _extension: IExtensionDescription,
|
|
||||||
private readonly _provider: vscode.NotebookKernelProvider
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
if (this._provider.onDidChangeKernels) {
|
|
||||||
this._register(this._provider.onDidChangeKernels((e: vscode.NotebookDocument | undefined) => {
|
|
||||||
const uri = e?.uri;
|
|
||||||
this._proxy.$onNotebookKernelChange(this._handle, uri);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async provideKernels(document: ExtHostNotebookDocument, token: vscode.CancellationToken): Promise<INotebookKernelInfoDto2[]> {
|
|
||||||
const data = await this._provider.provideKernels(document.notebookDocument, token) || [];
|
|
||||||
|
|
||||||
const newMap = new Map<vscode.NotebookKernel, string>();
|
|
||||||
let kernel_unique_pool = 0;
|
|
||||||
const kernelFriendlyIdCache = new Set<string>();
|
|
||||||
|
|
||||||
const kernelToFriendlyId = this._kernelToFriendlyId.get(document.uri);
|
|
||||||
|
|
||||||
const transformedData: INotebookKernelInfoDto2[] = data.map(kernel => {
|
|
||||||
let friendlyId = kernelToFriendlyId?.get(kernel);
|
|
||||||
if (friendlyId === undefined) {
|
|
||||||
if (kernel.id && kernelFriendlyIdCache.has(kernel.id)) {
|
|
||||||
friendlyId = `${this._extension.identifier.value}_${kernel.id}_${kernel_unique_pool++}`;
|
|
||||||
} else {
|
|
||||||
friendlyId = `${this._extension.identifier.value}_${kernel.id || UUID.generateUuid()}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newMap.set(kernel, friendlyId);
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: kernel.id,
|
|
||||||
friendlyId: friendlyId,
|
|
||||||
label: kernel.label,
|
|
||||||
extension: this._extension.identifier,
|
|
||||||
extensionLocation: this._extension.extensionLocation,
|
|
||||||
providerHandle: this._handle,
|
|
||||||
description: kernel.description,
|
|
||||||
detail: kernel.detail,
|
|
||||||
isPreferred: kernel.isPreferred,
|
|
||||||
preloads: kernel.preloads?.map(preload => {
|
|
||||||
// todo@connor4312: back compat on 2020-04-12, remove after transition
|
|
||||||
if (URI.isUri(preload)) {
|
|
||||||
preload = { uri: preload, provides: [] };
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
uri: preload.uri, provides: typeof preload.provides === 'string'
|
|
||||||
? [preload.provides]
|
|
||||||
: preload.provides === undefined
|
|
||||||
? []
|
|
||||||
: preload.provides
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
supportedLanguages: kernel.supportedLanguages,
|
|
||||||
implementsInterrupt: !!kernel.interrupt
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
this._kernelToFriendlyId.set(document.uri, newMap);
|
|
||||||
const friendlyIdToKernel = new Map<string, vscode.NotebookKernel>();
|
|
||||||
newMap.forEach((value, key) => {
|
|
||||||
friendlyIdToKernel.set(value, key);
|
|
||||||
});
|
|
||||||
|
|
||||||
this._friendlyIdToKernel.set(document.uri, friendlyIdToKernel);
|
|
||||||
return transformedData;
|
|
||||||
}
|
|
||||||
|
|
||||||
getKernelByFriendlyId(uri: URI, kernelId: string) {
|
|
||||||
return this._friendlyIdToKernel.get(uri)?.get(kernelId);
|
|
||||||
}
|
|
||||||
|
|
||||||
async resolveNotebook(kernelId: string, document: ExtHostNotebookDocument, webview: vscode.NotebookCommunication, token: CancellationToken) {
|
|
||||||
const kernel = this._friendlyIdToKernel.get(document.uri)?.get(kernelId);
|
|
||||||
|
|
||||||
if (kernel && this._provider.resolveKernel) {
|
|
||||||
return this._provider.resolveKernel(kernel, document.notebookDocument, webview, token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async executeNotebook(kernelId: string, document: ExtHostNotebookDocument, cellRange: ICellRange[]): Promise<void> {
|
|
||||||
const kernel = this._friendlyIdToKernel.get(document.uri)?.get(kernelId);
|
|
||||||
|
|
||||||
if (!kernel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const extCellRange = cellRange.map(c => typeConverters.NotebookRange.to(c));
|
|
||||||
return kernel.executeCellsRequest(document.notebookDocument, extCellRange);
|
|
||||||
}
|
|
||||||
|
|
||||||
async interruptNotebookExecution(kernelId: string, document: ExtHostNotebookDocument): Promise<void> {
|
|
||||||
const kernel = this._friendlyIdToKernel.get(document.uri)?.get(kernelId);
|
|
||||||
|
|
||||||
if (!kernel || !kernel.interrupt) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return kernel.interrupt(document.notebookDocument);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class NotebookEditorDecorationType {
|
export class NotebookEditorDecorationType {
|
||||||
|
|
||||||
@@ -213,7 +55,6 @@ type NotebookContentProviderData = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export class ExtHostNotebookController implements ExtHostNotebookShape {
|
export class ExtHostNotebookController implements ExtHostNotebookShape {
|
||||||
private static _notebookKernelProviderHandlePool: number = 0;
|
|
||||||
private static _notebookStatusBarItemProviderHandlePool: number = 0;
|
private static _notebookStatusBarItemProviderHandlePool: number = 0;
|
||||||
|
|
||||||
private readonly _notebookProxy: MainThreadNotebookShape;
|
private readonly _notebookProxy: MainThreadNotebookShape;
|
||||||
@@ -221,11 +62,9 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
|
|||||||
private readonly _notebookEditorsProxy: MainThreadNotebookEditorsShape;
|
private readonly _notebookEditorsProxy: MainThreadNotebookEditorsShape;
|
||||||
|
|
||||||
private readonly _notebookContentProviders = new Map<string, NotebookContentProviderData>();
|
private readonly _notebookContentProviders = new Map<string, NotebookContentProviderData>();
|
||||||
private readonly _notebookKernelProviders = new Map<number, ExtHostNotebookKernelProviderAdapter>();
|
|
||||||
private readonly _notebookStatusBarItemProviders = new Map<number, vscode.NotebookCellStatusBarItemProvider>();
|
private readonly _notebookStatusBarItemProviders = new Map<number, vscode.NotebookCellStatusBarItemProvider>();
|
||||||
private readonly _documents = new ResourceMap<ExtHostNotebookDocument>();
|
private readonly _documents = new ResourceMap<ExtHostNotebookDocument>();
|
||||||
private readonly _editors = new Map<string, ExtHostNotebookEditor>();
|
private readonly _editors = new Map<string, ExtHostNotebookEditor>();
|
||||||
private readonly _webviewComm = new Map<string, ExtHostWebviewCommWrapper>();
|
|
||||||
private readonly _commandsConverter: CommandsConverter;
|
private readonly _commandsConverter: CommandsConverter;
|
||||||
private readonly _onDidChangeNotebookEditorSelection = new Emitter<vscode.NotebookEditorSelectionChangeEvent>();
|
private readonly _onDidChangeNotebookEditorSelection = new Emitter<vscode.NotebookEditorSelectionChangeEvent>();
|
||||||
readonly onDidChangeNotebookEditorSelection = this._onDidChangeNotebookEditorSelection.event;
|
readonly onDidChangeNotebookEditorSelection = this._onDidChangeNotebookEditorSelection.event;
|
||||||
@@ -259,8 +98,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
|
|||||||
onDidCloseNotebookDocument: Event<vscode.NotebookDocument> = this._onDidCloseNotebookDocument.event;
|
onDidCloseNotebookDocument: Event<vscode.NotebookDocument> = this._onDidCloseNotebookDocument.event;
|
||||||
private _onDidSaveNotebookDocument = new Emitter<vscode.NotebookDocument>();
|
private _onDidSaveNotebookDocument = new Emitter<vscode.NotebookDocument>();
|
||||||
onDidSaveNotebookDocument: Event<vscode.NotebookDocument> = this._onDidSaveNotebookDocument.event;
|
onDidSaveNotebookDocument: Event<vscode.NotebookDocument> = this._onDidSaveNotebookDocument.event;
|
||||||
private _onDidChangeActiveNotebookKernel = new Emitter<{ document: vscode.NotebookDocument, kernel: vscode.NotebookKernel | undefined; }>();
|
|
||||||
onDidChangeActiveNotebookKernel = this._onDidChangeActiveNotebookKernel.event;
|
|
||||||
private _onDidChangeVisibleNotebookEditors = new Emitter<vscode.NotebookEditor[]>();
|
private _onDidChangeVisibleNotebookEditors = new Emitter<vscode.NotebookEditor[]>();
|
||||||
onDidChangeVisibleNotebookEditors = this._onDidChangeVisibleNotebookEditors.event;
|
onDidChangeVisibleNotebookEditors = this._onDidChangeVisibleNotebookEditors.event;
|
||||||
|
|
||||||
@@ -273,7 +110,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
|
|||||||
commands: ExtHostCommands,
|
commands: ExtHostCommands,
|
||||||
private _textDocumentsAndEditors: ExtHostDocumentsAndEditors,
|
private _textDocumentsAndEditors: ExtHostDocumentsAndEditors,
|
||||||
private _textDocuments: ExtHostDocuments,
|
private _textDocuments: ExtHostDocuments,
|
||||||
private readonly _webviewInitData: WebviewInitData,
|
|
||||||
private readonly logService: ILogService,
|
private readonly logService: ILogService,
|
||||||
private readonly _extensionStoragePaths: IExtensionStoragePaths,
|
private readonly _extensionStoragePaths: IExtensionStoragePaths,
|
||||||
) {
|
) {
|
||||||
@@ -388,23 +224,8 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
registerNotebookKernelProvider(extension: IExtensionDescription, selector: vscode.NotebookDocumentFilter, provider: vscode.NotebookKernelProvider) {
|
|
||||||
const handle = ExtHostNotebookController._notebookKernelProviderHandlePool++;
|
|
||||||
const adapter = new ExtHostNotebookKernelProviderAdapter(this._notebookProxy, handle, extension, provider);
|
|
||||||
this._notebookKernelProviders.set(handle, adapter);
|
|
||||||
this._notebookProxy.$registerNotebookKernelProvider({ id: extension.identifier, location: extension.extensionLocation, description: extension.description }, handle, {
|
|
||||||
viewType: selector.viewType,
|
|
||||||
filenamePattern: selector.filenamePattern ? typeConverters.NotebookExclusiveDocumentPattern.from(selector.filenamePattern) : undefined
|
|
||||||
});
|
|
||||||
|
|
||||||
return new extHostTypes.Disposable(() => {
|
|
||||||
adapter.dispose();
|
|
||||||
this._notebookKernelProviders.delete(handle);
|
|
||||||
this._notebookProxy.$unregisterNotebookKernelProvider(handle);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
registerNotebookCellStatusBarItemProvider(extension: IExtensionDescription, selector: vscode.NotebookSelector, provider: vscode.NotebookCellStatusBarItemProvider) {
|
registerNotebookCellStatusBarItemProvider(extension: IExtensionDescription, selector: vscode.NotebookSelector, provider: vscode.NotebookCellStatusBarItemProvider) {
|
||||||
|
|
||||||
const handle = ExtHostNotebookController._notebookStatusBarItemProviderHandlePool++;
|
const handle = ExtHostNotebookController._notebookStatusBarItemProviderHandlePool++;
|
||||||
const eventHandle = typeof provider.onDidChangeCellStatusBarItems === 'function' ? ExtHostNotebookController._notebookStatusBarItemProviderHandlePool++ : undefined;
|
const eventHandle = typeof provider.onDidChangeCellStatusBarItems === 'function' ? ExtHostNotebookController._notebookStatusBarItemProviderHandlePool++ : undefined;
|
||||||
|
|
||||||
@@ -439,21 +260,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
|
|||||||
return assertIsDefined(document?.notebookDocument);
|
return assertIsDefined(document?.notebookDocument);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _withAdapter<T>(handle: number, uri: UriComponents, callback: (adapter: ExtHostNotebookKernelProviderAdapter, document: ExtHostNotebookDocument) => Promise<T>) {
|
|
||||||
const document = this._documents.get(URI.revive(uri));
|
|
||||||
|
|
||||||
if (!document) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const provider = this._notebookKernelProviders.get(handle);
|
|
||||||
|
|
||||||
if (!provider) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return callback(provider, document);
|
|
||||||
}
|
|
||||||
|
|
||||||
async showNotebookDocument(notebookOrUri: vscode.NotebookDocument | URI, options?: vscode.NotebookDocumentShowOptions): Promise<vscode.NotebookEditor> {
|
async showNotebookDocument(notebookOrUri: vscode.NotebookDocument | URI, options?: vscode.NotebookDocumentShowOptions): Promise<vscode.NotebookEditor> {
|
||||||
|
|
||||||
@@ -489,22 +295,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async $provideNotebookKernels(handle: number, uri: UriComponents, token: CancellationToken): Promise<INotebookKernelInfoDto2[]> {
|
|
||||||
return this._withAdapter<INotebookKernelInfoDto2[]>(handle, uri, (adapter, document) => {
|
|
||||||
return adapter.provideKernels(document, token);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async $resolveNotebookKernel(handle: number, editorId: string, uri: UriComponents, kernelId: string, token: CancellationToken): Promise<void> {
|
|
||||||
await this._withAdapter<void>(handle, uri, async (adapter, document) => {
|
|
||||||
const webComm = this._webviewComm.get(editorId);
|
|
||||||
|
|
||||||
if (webComm) {
|
|
||||||
await adapter.resolveNotebook(kernelId, document, webComm.contentProviderComm, token);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async $provideNotebookCellStatusBarItems(handle: number, uri: UriComponents, index: number, token: CancellationToken): Promise<INotebookCellStatusBarListDto | undefined> {
|
async $provideNotebookCellStatusBarItems(handle: number, uri: UriComponents, index: number, token: CancellationToken): Promise<INotebookCellStatusBarListDto | undefined> {
|
||||||
const provider = this._notebookStatusBarItemProviders.get(handle);
|
const provider = this._notebookStatusBarItemProviders.get(handle);
|
||||||
const revivedUri = URI.revive(uri);
|
const revivedUri = URI.revive(uri);
|
||||||
@@ -536,27 +326,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
|
|||||||
this._statusBarCache.delete(cacheId);
|
this._statusBarCache.delete(cacheId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $resolveNotebookEditor(viewType: string, uri: UriComponents, editorId: string): Promise<void> {
|
|
||||||
const provider = this._notebookContentProviders.get(viewType);
|
|
||||||
const revivedUri = URI.revive(uri);
|
|
||||||
const document = this._documents.get(revivedUri);
|
|
||||||
if (!document || !provider) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let webComm = this._webviewComm.get(editorId);
|
|
||||||
if (!webComm) {
|
|
||||||
webComm = new ExtHostWebviewCommWrapper(editorId, revivedUri, this._notebookProxy, this._webviewInitData, document);
|
|
||||||
this._webviewComm.set(editorId, webComm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async $executeNotebookKernelFromProvider(handle: number, uri: UriComponents, kernelId: string, cellRange: ICellRange[]): Promise<void> {
|
|
||||||
await this._withAdapter(handle, uri, async (adapter, document) => {
|
|
||||||
return adapter.executeNotebook(kernelId, document, cellRange);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- serialize/deserialize
|
// --- serialize/deserialize
|
||||||
|
|
||||||
private _handlePool = 0;
|
private _handlePool = 0;
|
||||||
@@ -601,26 +370,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
|
|||||||
return VSBuffer.wrap(bytes);
|
return VSBuffer.wrap(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $cancelNotebookCellExecution(handle: number, uri: UriComponents, kernelId: string, cellRange: ICellRange[]): Promise<void> {
|
|
||||||
await this._withAdapter(handle, uri, async (adapter, document) => {
|
|
||||||
return adapter.interruptNotebookExecution(kernelId, document);
|
|
||||||
});
|
|
||||||
|
|
||||||
const document = this._documents.get(URI.revive(uri));
|
|
||||||
if (!document) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let range of cellRange) {
|
|
||||||
for (let i = range.start; i < range.end; i++) {
|
|
||||||
const cell = document.getCellFromIndex(i);
|
|
||||||
if (cell) {
|
|
||||||
this.cancelOneNotebookCellExecution(cell);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cancelOneNotebookCellExecution(cell: ExtHostCell): void {
|
cancelOneNotebookCellExecution(cell: ExtHostCell): void {
|
||||||
const execution = this._activeExecutions.get(cell.uri);
|
const execution = this._activeExecutions.get(cell.uri);
|
||||||
execution?.cancel();
|
execution?.cancel();
|
||||||
@@ -666,24 +415,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
|
|||||||
return backup.id;
|
return backup.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
$acceptNotebookActiveKernelChange(event: { uri: UriComponents, providerHandle: number | undefined, kernelFriendlyId: string | undefined; }) {
|
|
||||||
if (event.providerHandle !== undefined) {
|
|
||||||
this._withAdapter(event.providerHandle, event.uri, async (adapter, document) => {
|
|
||||||
const kernel = event.kernelFriendlyId ? adapter.getKernelByFriendlyId(URI.revive(event.uri), event.kernelFriendlyId) : undefined;
|
|
||||||
this._editors.forEach(editor => {
|
|
||||||
if (editor.notebookData === document) {
|
|
||||||
editor._acceptKernel(kernel);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this._onDidChangeActiveNotebookKernel.fire({ document: document.notebookDocument, kernel });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$onDidReceiveMessage(editorId: string, forRendererType: string | undefined, message: any): void {
|
|
||||||
this._webviewComm.get(editorId)?.onDidReceiveMessage(forRendererType, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
$acceptModelChanged(uri: UriComponents, event: NotebookCellsChangedEventDto, isDirty: boolean): void {
|
$acceptModelChanged(uri: UriComponents, event: NotebookCellsChangedEventDto, isDirty: boolean): void {
|
||||||
const document = this._getNotebookDocument(URI.revive(uri));
|
const document = this._getNotebookDocument(URI.revive(uri));
|
||||||
document.acceptModelChanged(event, isDirty);
|
document.acceptModelChanged(event, isDirty);
|
||||||
@@ -755,14 +486,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
|
|||||||
throw new Error(`editor with id ALREADY EXSIST: ${editorId}`);
|
throw new Error(`editor with id ALREADY EXSIST: ${editorId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const revivedUri = document.uri;
|
|
||||||
let webComm = this._webviewComm.get(editorId);
|
|
||||||
|
|
||||||
if (!webComm) {
|
|
||||||
webComm = new ExtHostWebviewCommWrapper(editorId, revivedUri, this._notebookProxy, this._webviewInitData, document);
|
|
||||||
this._webviewComm.set(editorId, webComm);
|
|
||||||
}
|
|
||||||
|
|
||||||
const editor = new ExtHostNotebookEditor(
|
const editor = new ExtHostNotebookEditor(
|
||||||
editorId,
|
editorId,
|
||||||
this._notebookEditorsProxy,
|
this._notebookEditorsProxy,
|
||||||
@@ -912,17 +635,17 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
|
|||||||
createNotebookCellExecution(docUri: vscode.Uri, index: number, kernelId: string): vscode.NotebookCellExecutionTask | undefined {
|
createNotebookCellExecution(docUri: vscode.Uri, index: number, kernelId: string): vscode.NotebookCellExecutionTask | undefined {
|
||||||
const document = this.lookupNotebookDocument(docUri);
|
const document = this.lookupNotebookDocument(docUri);
|
||||||
if (!document) {
|
if (!document) {
|
||||||
throw new Error(`Invalid cell uri / index: ${docUri}, ${index} `);
|
throw new Error(`Invalid uri: ${docUri} `);
|
||||||
}
|
}
|
||||||
|
|
||||||
const cell = document.getCellFromIndex(index);
|
const cell = document.getCellFromIndex(index);
|
||||||
if (!cell) {
|
if (!cell) {
|
||||||
throw new Error(`Invalid cell uri / index: ${docUri}, ${index} `);
|
throw new Error(`Invalid cell index: ${docUri}, ${index} `);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO@roblou also validate kernelId, once kernel has moved from editor to document
|
// TODO@roblou also validate kernelId, once kernel has moved from editor to document
|
||||||
if (this._activeExecutions.has(cell.uri)) {
|
if (this._activeExecutions.has(cell.uri)) {
|
||||||
return;
|
throw new Error(`duplicate execution for ${cell.uri}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const execution = new NotebookCellExecutionTask(docUri, document, cell, this._notebookDocumentsProxy);
|
const execution = new NotebookCellExecutionTask(docUri, document, cell, this._notebookDocumentsProxy);
|
||||||
|
|||||||
@@ -89,8 +89,6 @@ export class ExtHostNotebookEditor {
|
|||||||
private _viewColumn?: vscode.ViewColumn;
|
private _viewColumn?: vscode.ViewColumn;
|
||||||
|
|
||||||
private _visible: boolean = false;
|
private _visible: boolean = false;
|
||||||
private _kernel?: vscode.NotebookKernel;
|
|
||||||
|
|
||||||
private readonly _hasDecorationsForKey = new Set<string>();
|
private readonly _hasDecorationsForKey = new Set<string>();
|
||||||
|
|
||||||
private _editor?: vscode.NotebookEditor;
|
private _editor?: vscode.NotebookEditor;
|
||||||
@@ -136,9 +134,6 @@ export class ExtHostNotebookEditor {
|
|||||||
callback(edit);
|
callback(edit);
|
||||||
return that._applyEdit(edit.finalize());
|
return that._applyEdit(edit.finalize());
|
||||||
},
|
},
|
||||||
get kernel() {
|
|
||||||
return that._kernel;
|
|
||||||
},
|
|
||||||
setDecorations(decorationType, range) {
|
setDecorations(decorationType, range) {
|
||||||
return that.setDecorations(decorationType, range);
|
return that.setDecorations(decorationType, range);
|
||||||
}
|
}
|
||||||
@@ -147,10 +142,6 @@ export class ExtHostNotebookEditor {
|
|||||||
return this._editor;
|
return this._editor;
|
||||||
}
|
}
|
||||||
|
|
||||||
_acceptKernel(kernel?: vscode.NotebookKernel) {
|
|
||||||
this._kernel = kernel;
|
|
||||||
}
|
|
||||||
|
|
||||||
get visible(): boolean {
|
get visible(): boolean {
|
||||||
return this._visible;
|
return this._visible;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import * as vscode from 'vscode';
|
|||||||
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
|
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
|
||||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||||
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
|
||||||
import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||||
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||||
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
||||||
@@ -181,7 +180,7 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
|
|||||||
return that._proxy.$postMessage(handle, editor && that._extHostNotebook.getIdByEditor(editor), message);
|
return that._proxy.$postMessage(handle, editor && that._extHostNotebook.getIdByEditor(editor), message);
|
||||||
},
|
},
|
||||||
asWebviewUri(uri: URI) {
|
asWebviewUri(uri: URI) {
|
||||||
return asWebviewUri(that._initData.environment, data.id, uri);
|
return asWebviewUri(that._initData.environment, String(handle), uri);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -199,7 +198,7 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async $executeCells(handle: number, uri: UriComponents, ranges: ICellRange[]): Promise<void> {
|
async $executeCells(handle: number, uri: UriComponents, handles: number[]): Promise<void> {
|
||||||
const obj = this._kernelData.get(handle);
|
const obj = this._kernelData.get(handle);
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
// extension can dispose kernels in the meantime
|
// extension can dispose kernels in the meantime
|
||||||
@@ -211,19 +210,22 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const cells: vscode.NotebookCell[] = [];
|
const cells: vscode.NotebookCell[] = [];
|
||||||
for (let range of ranges) {
|
for (let cellHandle of handles) {
|
||||||
cells.push(...document.notebookDocument.getCells(extHostTypeConverters.NotebookRange.to(range)));
|
const cell = document.getCell(cellHandle);
|
||||||
|
if (cell) {
|
||||||
|
cells.push(cell.cell);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
obj.controller.executeHandler.call(obj.controller, cells, obj.controller);
|
await obj.controller.executeHandler.call(obj.controller, cells, obj.controller);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
//
|
//
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async $cancelCells(handle: number, uri: UriComponents, ranges: ICellRange[]): Promise<void> {
|
async $cancelCells(handle: number, uri: UriComponents, handles: number[]): Promise<void> {
|
||||||
const obj = this._kernelData.get(handle);
|
const obj = this._kernelData.get(handle);
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
// extension can dispose kernels in the meantime
|
// extension can dispose kernels in the meantime
|
||||||
@@ -234,16 +236,14 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
|
|||||||
throw new Error('MISSING notebook');
|
throw new Error('MISSING notebook');
|
||||||
}
|
}
|
||||||
if (obj.controller.interruptHandler) {
|
if (obj.controller.interruptHandler) {
|
||||||
obj.controller.interruptHandler.call(obj.controller);
|
await obj.controller.interruptHandler.call(obj.controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we do both? interrupt and cancellation or should we be selective?
|
// we do both? interrupt and cancellation or should we be selective?
|
||||||
for (const range of ranges) {
|
for (let cellHandle of handles) {
|
||||||
for (let i = range.start; i < range.end; i++) {
|
const cell = document.getCell(cellHandle);
|
||||||
const cell = document.getCellFromIndex(i);
|
if (cell) {
|
||||||
if (cell) {
|
this._extHostNotebook.cancelOneNotebookCellExecution(cell);
|
||||||
this._extHostNotebook.cancelOneNotebookCellExecution(cell);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -677,9 +677,32 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit {
|
|||||||
this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit: { editType: CellEditType.DocumentMetadata, metadata: value }, notebookMetadata: value });
|
this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit: { editType: CellEditType.DocumentMetadata, metadata: value }, notebookMetadata: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceNotebookCells(uri: URI, start: number, end: number, cells: vscode.NotebookCellData[], metadata?: vscode.WorkspaceEditEntryMetadata): void {
|
replaceNotebookCells(uri: URI, range: vscode.NotebookRange, cells: vscode.NotebookCellData[], metadata?: vscode.WorkspaceEditEntryMetadata): void;
|
||||||
if (start !== end || cells.length > 0) {
|
replaceNotebookCells(uri: URI, start: number, end: number, cells: vscode.NotebookCellData[], metadata?: vscode.WorkspaceEditEntryMetadata): void;
|
||||||
this._edits.push({ _type: FileEditType.CellReplace, uri, index: start, count: end - start, cells, metadata });
|
replaceNotebookCells(uri: URI, startOrRange: number | vscode.NotebookRange, endOrCells: number | vscode.NotebookCellData[], cellsOrMetadata?: vscode.NotebookCellData[] | vscode.WorkspaceEditEntryMetadata, metadata?: vscode.WorkspaceEditEntryMetadata): void {
|
||||||
|
let start: number | undefined;
|
||||||
|
let end: number | undefined;
|
||||||
|
let cellData: vscode.NotebookCellData[] = [];
|
||||||
|
let workspaceEditMetadata: vscode.WorkspaceEditEntryMetadata | undefined;
|
||||||
|
|
||||||
|
if (NotebookRange.isNotebookRange(startOrRange) && NotebookCellData.isNotebookCellDataArray(endOrCells) && !NotebookCellData.isNotebookCellDataArray(cellsOrMetadata)) {
|
||||||
|
start = startOrRange.start;
|
||||||
|
end = startOrRange.end;
|
||||||
|
cellData = endOrCells;
|
||||||
|
workspaceEditMetadata = cellsOrMetadata;
|
||||||
|
} else if (typeof startOrRange === 'number' && typeof endOrCells === 'number' && NotebookCellData.isNotebookCellDataArray(cellsOrMetadata)) {
|
||||||
|
start = startOrRange;
|
||||||
|
end = endOrCells;
|
||||||
|
cellData = cellsOrMetadata;
|
||||||
|
workspaceEditMetadata = metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start === undefined || end === undefined) {
|
||||||
|
throw new Error('Invalid arguments');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start !== end || cellData.length > 0) {
|
||||||
|
this._edits.push({ _type: FileEditType.CellReplace, uri, index: start, count: end - start, cells: cellData, metadata: workspaceEditMetadata });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2897,6 +2920,16 @@ export enum ColorThemeKind {
|
|||||||
//#region Notebook
|
//#region Notebook
|
||||||
|
|
||||||
export class NotebookRange {
|
export class NotebookRange {
|
||||||
|
static isNotebookRange(thing: any): thing is vscode.NotebookRange {
|
||||||
|
if (thing instanceof NotebookRange) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!thing) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return typeof (<NotebookRange>thing).start === 'number'
|
||||||
|
&& typeof (<NotebookRange>thing).end === 'number';
|
||||||
|
}
|
||||||
|
|
||||||
private _start: number;
|
private _start: number;
|
||||||
private _end: number;
|
private _end: number;
|
||||||
@@ -3063,6 +3096,15 @@ export class NotebookDocumentMetadata {
|
|||||||
|
|
||||||
export class NotebookCellData {
|
export class NotebookCellData {
|
||||||
|
|
||||||
|
static isNotebookCellDataArray(value: unknown): value is vscode.NotebookCellData[] {
|
||||||
|
return Array.isArray(value) && (<unknown[]>value).every(elem => NotebookCellData.isNotebookCellData(elem));
|
||||||
|
}
|
||||||
|
|
||||||
|
static isNotebookCellData(value: unknown): value is vscode.NotebookCellData {
|
||||||
|
// return value instanceof NotebookCellData;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
kind: NotebookCellKind;
|
kind: NotebookCellKind;
|
||||||
source: string;
|
source: string;
|
||||||
language: string;
|
language: string;
|
||||||
|
|||||||
@@ -19,18 +19,19 @@ import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation
|
|||||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||||
import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput';
|
import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput';
|
||||||
import { BaseCellRenderTemplate, CellEditState, CellFocusMode, EXECUTE_CELL_COMMAND_ID, EXPAND_CELL_INPUT_COMMAND_ID, getNotebookEditorFromEditorPane, IActiveNotebookEditor, ICellViewModel, NOTEBOOK_CELL_EDITABLE, NOTEBOOK_CELL_HAS_OUTPUTS, NOTEBOOK_CELL_INPUT_COLLAPSED, NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_OUTPUT_COLLAPSED, NOTEBOOK_CELL_EXECUTION_STATE, NOTEBOOK_CELL_TYPE, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_KERNEL_COUNT, NOTEBOOK_OUTPUT_FOCUSED, NOTEBOOK_INTERRUPTIBLE_KERNEL, NOTEBOOK_HAS_RUNNING_CELL, CHANGE_CELL_LANGUAGE, QUIT_EDIT_CELL_COMMAND_ID } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
import { BaseCellRenderTemplate, CellEditState, CellFocusMode, EXECUTE_CELL_COMMAND_ID, EXPAND_CELL_INPUT_COMMAND_ID, getNotebookEditorFromEditorPane, IActiveNotebookEditor, ICellViewModel, NOTEBOOK_CELL_EDITABLE, NOTEBOOK_CELL_HAS_OUTPUTS, NOTEBOOK_CELL_INPUT_COLLAPSED, NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_OUTPUT_COLLAPSED, NOTEBOOK_CELL_EXECUTION_STATE, NOTEBOOK_CELL_TYPE, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_KERNEL_COUNT, NOTEBOOK_OUTPUT_FOCUSED, NOTEBOOK_INTERRUPTIBLE_KERNEL, NOTEBOOK_HAS_RUNNING_CELL, CHANGE_CELL_LANGUAGE, QUIT_EDIT_CELL_COMMAND_ID } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||||
import { CellEditType, CellKind, ICellEditOperation, ICellRange, INotebookDocumentFilter, isDocumentExcludePattern, NotebookCellMetadata, NotebookCellExecutionState, NOTEBOOK_EDITOR_CURSOR_BOUNDARY, TransientCellMetadata, TransientDocumentMetadata, SelectionStateType, ICellReplaceEdit } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
import { CellEditType, CellKind, ICellEditOperation, ICellRange, isDocumentExcludePattern, NotebookCellMetadata, NotebookCellExecutionState, NOTEBOOK_EDITOR_CURSOR_BOUNDARY, TransientCellMetadata, TransientDocumentMetadata, SelectionStateType, ICellReplaceEdit } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||||
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
|
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
|
||||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import * as icons from 'vs/workbench/contrib/notebook/browser/notebookIcons';
|
import * as icons from 'vs/workbench/contrib/notebook/browser/notebookIcons';
|
||||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
|
||||||
import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebookEditorInput';
|
import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebookEditorInput';
|
||||||
import { EditorsOrder } from 'vs/workbench/common/editor';
|
import { EditorsOrder } from 'vs/workbench/common/editor';
|
||||||
import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService';
|
import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService';
|
||||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
import { WorkbenchActionExecutedClassification, WorkbenchActionExecutedEvent } from 'vs/base/common/actions';
|
import { WorkbenchActionExecutedClassification, WorkbenchActionExecutedEvent } from 'vs/base/common/actions';
|
||||||
import { NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
|
import { NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
|
||||||
|
import { INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
|
||||||
|
import { Iterable } from 'vs/base/common/iterator';
|
||||||
|
|
||||||
// Notebook Commands
|
// Notebook Commands
|
||||||
const EXECUTE_NOTEBOOK_COMMAND_ID = 'notebook.execute';
|
const EXECUTE_NOTEBOOK_COMMAND_ID = 'notebook.execute';
|
||||||
@@ -426,7 +427,7 @@ registerAction2(class CancelExecuteCell extends NotebookCellAction<ICellRange> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
|
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
|
||||||
return context.notebookEditor.cancelNotebookCellExecution(context.cell);
|
return context.notebookEditor.cancelNotebookCells(Iterable.single(context.cell));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -568,7 +569,7 @@ registerAction2(class extends NotebookAction {
|
|||||||
group?.pinEditor(editor.editor);
|
group?.pinEditor(editor.editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
return context.notebookEditor.executeNotebook();
|
return context.notebookEditor.executeNotebookCells();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -610,7 +611,7 @@ registerAction2(class CancelNotebook extends NotebookAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise<void> {
|
async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise<void> {
|
||||||
return context.notebookEditor.cancelNotebookExecution();
|
return context.notebookEditor.cancelNotebookCells();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -690,7 +691,12 @@ async function runCell(accessor: ServicesAccessor, context: INotebookCellActionC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return context.notebookEditor.executeNotebookCell(context.cell);
|
if (context.cell.cellKind === CellKind.Markdown) {
|
||||||
|
context.notebookEditor.focusNotebookCell(context.cell, 'container');
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
return context.notebookEditor.executeNotebookCells(Iterable.single(context.cell));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function changeCellToKind(kind: CellKind, context: INotebookCellActionContext, language?: string): Promise<ICellViewModel | null> {
|
export async function changeCellToKind(kind: CellKind, context: INotebookCellActionContext, language?: string): Promise<ICellViewModel | null> {
|
||||||
@@ -1731,20 +1737,6 @@ CommandsRegistry.registerCommand('_resolveNotebookContentProvider', (accessor, a
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
CommandsRegistry.registerCommand('_resolveNotebookKernelProviders', async (accessor, args): Promise<{
|
|
||||||
extensionId: string;
|
|
||||||
description?: string;
|
|
||||||
selector: INotebookDocumentFilter;
|
|
||||||
}[]> => {
|
|
||||||
const notebookService = accessor.get<INotebookService>(INotebookService);
|
|
||||||
const providers = await notebookService.getContributedNotebookKernelProviders();
|
|
||||||
return providers.map(provider => ({
|
|
||||||
extensionId: provider.providerExtensionId,
|
|
||||||
description: provider.providerDescription,
|
|
||||||
selector: provider.selector
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
CommandsRegistry.registerCommand('_resolveNotebookKernels', async (accessor, args: {
|
CommandsRegistry.registerCommand('_resolveNotebookKernels', async (accessor, args: {
|
||||||
viewType: string;
|
viewType: string;
|
||||||
uri: UriComponents;
|
uri: UriComponents;
|
||||||
@@ -1756,14 +1748,12 @@ CommandsRegistry.registerCommand('_resolveNotebookKernels', async (accessor, arg
|
|||||||
isPreferred?: boolean;
|
isPreferred?: boolean;
|
||||||
preloads?: URI[];
|
preloads?: URI[];
|
||||||
}[]> => {
|
}[]> => {
|
||||||
const notebookService = accessor.get<INotebookService>(INotebookService);
|
const notebookKernelService = accessor.get(INotebookKernelService);
|
||||||
const uri = URI.revive(args.uri as UriComponents);
|
const uri = URI.revive(args.uri as UriComponents);
|
||||||
const source = new CancellationTokenSource();
|
const kernels = notebookKernelService.getNotebookKernels({ uri, viewType: args.viewType });
|
||||||
const kernels = await notebookService.getNotebookKernels(args.viewType, uri, source.token);
|
|
||||||
source.dispose();
|
|
||||||
|
|
||||||
return kernels.map(provider => ({
|
return kernels.all.map(provider => ({
|
||||||
id: provider.friendlyId,
|
id: provider.id,
|
||||||
label: provider.label,
|
label: provider.label,
|
||||||
description: provider.description,
|
description: provider.description,
|
||||||
detail: provider.detail,
|
detail: provider.detail,
|
||||||
|
|||||||
@@ -7,21 +7,22 @@ import * as nls from 'vs/nls';
|
|||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
import { Action2, registerAction2 } from 'vs/platform/actions/common/actions';
|
import { Action2, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput';
|
import { IQuickInputButton, IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
||||||
import { NOTEBOOK_ACTIONS_CATEGORY } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions';
|
import { NOTEBOOK_ACTIONS_CATEGORY } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions';
|
||||||
import { getNotebookEditorFromEditorPane, INotebookEditor, NOTEBOOK_IS_ACTIVE_EDITOR } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
import { getNotebookEditorFromEditorPane, INotebookEditor, NOTEBOOK_IS_ACTIVE_EDITOR } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
|
||||||
import { INotebookKernel } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
|
||||||
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry, IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry, IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||||
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||||
import { Disposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
|
import { Disposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from 'vs/workbench/services/statusbar/common/statusbar';
|
import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from 'vs/workbench/services/statusbar/common/statusbar';
|
||||||
import { NotebookKernelProviderAssociation, NotebookKernelProviderAssociations, notebookKernelProviderAssociationsSettingId } from 'vs/workbench/contrib/notebook/browser/notebookKernelAssociation';
|
import { NotebookKernelProviderAssociation, NotebookKernelProviderAssociations, notebookKernelProviderAssociationsSettingId } from 'vs/workbench/contrib/notebook/browser/notebookKernelAssociation';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { configureKernelIcon, selectKernelIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons';
|
import { configureKernelIcon, selectKernelIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons';
|
||||||
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
|
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||||
import { NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
|
import { NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
|
||||||
|
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||||
|
import { INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
|
||||||
|
import { INotebookKernel } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||||
|
|
||||||
registerAction2(class extends Action2 {
|
registerAction2(class extends Action2 {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -58,90 +59,60 @@ registerAction2(class extends Action2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async run(accessor: ServicesAccessor, context?: { id: string, extension: string }): Promise<void> {
|
async run(accessor: ServicesAccessor, context?: { id: string, extension: string }): Promise<void> {
|
||||||
const editorService = accessor.get<IEditorService>(IEditorService);
|
const notebookKernelService = accessor.get(INotebookKernelService);
|
||||||
const quickInputService = accessor.get<IQuickInputService>(IQuickInputService);
|
const editorService = accessor.get(IEditorService);
|
||||||
const configurationService = accessor.get<IConfigurationService>(IConfigurationService);
|
const quickInputService = accessor.get(IQuickInputService);
|
||||||
|
const configurationService = accessor.get(IConfigurationService);
|
||||||
|
|
||||||
const editor = getNotebookEditorFromEditorPane(editorService.activeEditorPane);
|
const editor = getNotebookEditorFromEditorPane(editorService.activeEditorPane);
|
||||||
if (!editor) {
|
if (!editor || !editor.hasModel()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!editor.hasModel()) {
|
if (context && (typeof context.id !== 'string' || typeof context.extension !== 'string')) {
|
||||||
|
// validate context: id & extension MUST be strings
|
||||||
|
context = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const notebook = editor.viewModel.notebookDocument;
|
||||||
|
const { bound, all } = notebookKernelService.getNotebookKernels(notebook);
|
||||||
|
|
||||||
|
if (bound && context && bound.id === context.id && ExtensionIdentifier.equals(bound.extension, context.extension)) {
|
||||||
|
// current kernel is wanted kernel -> done
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const activeKernel = editor.activeKernel;
|
let newKernel: INotebookKernel | undefined;
|
||||||
|
if (context) {
|
||||||
const picker = quickInputService.createQuickPick<(IQuickPickItem & { run(): void; kernelProviderId?: string })>();
|
for (let candidate of all) {
|
||||||
picker.placeholder = nls.localize('notebook.runCell.selectKernel', "Select a notebook kernel to run this notebook");
|
if (candidate.id === context.id && ExtensionIdentifier.equals(candidate.extension, context.extension)) {
|
||||||
picker.matchOnDetail = true;
|
newKernel = candidate;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (context && context.id) {
|
}
|
||||||
} else {
|
|
||||||
picker.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
picker.busy = true;
|
if (!newKernel) {
|
||||||
|
type KernelPick = IQuickPickItem & { kernel: INotebookKernel };
|
||||||
const tokenSource = new CancellationTokenSource();
|
const configButton: IQuickInputButton = {
|
||||||
const availableKernels = await editor.beginComputeContributedKernels();
|
iconClass: ThemeIcon.asClassName(configureKernelIcon),
|
||||||
|
tooltip: nls.localize('notebook.promptKernel.setDefaultTooltip', "Set as default kernel provider for '{0}'", editor.viewModel.viewType)
|
||||||
const selectedKernel = availableKernels.length ? availableKernels.find(
|
|
||||||
kernel => kernel.id && context?.id && kernel.id === context?.id && kernel.extension.value === context?.extension
|
|
||||||
) : undefined;
|
|
||||||
|
|
||||||
if (selectedKernel) {
|
|
||||||
editor.activeKernel = selectedKernel;
|
|
||||||
return selectedKernel.resolve(editor.viewModel.uri, editor.getId(), tokenSource.token);
|
|
||||||
} else {
|
|
||||||
picker.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
const picks: QuickPickInput<IQuickPickItem & { run(): void; kernelProviderId?: string; }>[] = [...availableKernels].map((a) => {
|
|
||||||
return {
|
|
||||||
id: a.friendlyId,
|
|
||||||
label: a.label,
|
|
||||||
picked: a.friendlyId === activeKernel?.friendlyId,
|
|
||||||
description:
|
|
||||||
a.description
|
|
||||||
? a.description
|
|
||||||
: a.extension.value + (a.friendlyId === activeKernel?.friendlyId
|
|
||||||
? nls.localize('currentActiveKernel', " (Currently Active)")
|
|
||||||
: ''),
|
|
||||||
detail: a.detail,
|
|
||||||
kernelProviderId: a.extension.value,
|
|
||||||
run: async () => {
|
|
||||||
editor.activeKernel = a;
|
|
||||||
a.resolve(editor.viewModel.uri, editor.getId(), tokenSource.token);
|
|
||||||
},
|
|
||||||
buttons: [{
|
|
||||||
iconClass: ThemeIcon.asClassName(configureKernelIcon),
|
|
||||||
tooltip: nls.localize('notebook.promptKernel.setDefaultTooltip', "Set as default kernel provider for '{0}'", editor.viewModel.viewType)
|
|
||||||
}]
|
|
||||||
};
|
};
|
||||||
});
|
const picks = all.map(kernel => {
|
||||||
|
return <KernelPick>{
|
||||||
picker.items = picks;
|
kernel,
|
||||||
picker.busy = false;
|
picked: kernel.id === bound?.id,
|
||||||
picker.activeItems = picks.filter(pick => (pick as IQuickPickItem).picked) as (IQuickPickItem & { run(): void; kernelProviderId?: string; })[];
|
label: kernel.label,
|
||||||
|
description: kernel.description,
|
||||||
const pickedItem = await new Promise<(IQuickPickItem & { run(): void; kernelProviderId?: string; }) | undefined>(resolve => {
|
detail: kernel.detail,
|
||||||
picker.onDidAccept(() => {
|
buttons: [configButton]
|
||||||
resolve(picker.selectedItems.length === 1 ? picker.selectedItems[0] : undefined);
|
};
|
||||||
picker.dispose();
|
|
||||||
});
|
});
|
||||||
|
const pick = await quickInputService.pick(picks, {
|
||||||
|
onDidTriggerItemButton: (context) => {
|
||||||
|
newKernel = context.item.kernel;
|
||||||
|
|
||||||
picker.onDidTriggerItemButton(e => {
|
const newAssociation: NotebookKernelProviderAssociation = { viewType: notebook.viewType, kernelProvider: context.item.kernel.extension.value };
|
||||||
const pick = e.item;
|
|
||||||
const id = pick.id;
|
|
||||||
resolve(pick); // open the view
|
|
||||||
picker.dispose();
|
|
||||||
|
|
||||||
// And persist the setting
|
|
||||||
if (pick && id && pick.kernelProviderId) {
|
|
||||||
const newAssociation: NotebookKernelProviderAssociation = { viewType: editor.viewModel.viewType, kernelProvider: pick.kernelProviderId };
|
|
||||||
const currentAssociations = [...configurationService.getValue<NotebookKernelProviderAssociations>(notebookKernelProviderAssociationsSettingId)];
|
const currentAssociations = [...configurationService.getValue<NotebookKernelProviderAssociations>(notebookKernelProviderAssociationsSettingId)];
|
||||||
|
|
||||||
// First try updating existing association
|
// First try updating existing association
|
||||||
@@ -160,71 +131,75 @@ registerAction2(class extends Action2 {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
if (pick) {
|
||||||
|
newKernel = pick.kernel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tokenSource.dispose();
|
if (newKernel) {
|
||||||
return pickedItem?.run();
|
notebookKernelService.updateNotebookKernelBinding(notebook, newKernel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export class KernelStatus extends Disposable implements IWorkbenchContribution {
|
export class KernelStatus extends Disposable implements IWorkbenchContribution {
|
||||||
|
|
||||||
private readonly _editorDisposable = this._register(new DisposableStore());
|
private readonly _editorDisposables = this._register(new DisposableStore());
|
||||||
private readonly _kernelInfoElement = this._register(new MutableDisposable<IStatusbarEntryAccessor>());
|
private readonly _kernelInfoElement = this._register(new MutableDisposable<IStatusbarEntryAccessor>());
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@IEditorService private readonly _editorService: IEditorService,
|
@IEditorService private readonly _editorService: IEditorService,
|
||||||
@IStatusbarService private readonly _statusbarService: IStatusbarService,
|
@IStatusbarService private readonly _statusbarService: IStatusbarService,
|
||||||
|
@INotebookKernelService private readonly _notebookKernelService: INotebookKernelService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this._register(this._editorService.onDidActiveEditorChange(() => this._updateStatusbar()));
|
this._register(this._editorService.onDidActiveEditorChange(() => this._updateStatusbar()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private _updateStatusbar() {
|
private _updateStatusbar() {
|
||||||
this._editorDisposable.clear();
|
this._editorDisposables.clear();
|
||||||
|
|
||||||
const activeEditor = getNotebookEditorFromEditorPane(this._editorService.activeEditorPane);
|
const activeEditor = getNotebookEditorFromEditorPane(this._editorService.activeEditorPane);
|
||||||
if (activeEditor) {
|
if (!activeEditor) {
|
||||||
this._editorDisposable.add(activeEditor.onDidChangeKernel(() => {
|
// not a notebook -> clean-up, done
|
||||||
this._showKernelStatus(activeEditor.activeKernel, activeEditor.availableKernelCount);
|
|
||||||
}));
|
|
||||||
this._editorDisposable.add(activeEditor.onDidChangeAvailableKernels(() => {
|
|
||||||
this._showKernelStatus(activeEditor.activeKernel, activeEditor.availableKernelCount);
|
|
||||||
}));
|
|
||||||
this._showKernelStatus(activeEditor.activeKernel, activeEditor.availableKernelCount);
|
|
||||||
} else {
|
|
||||||
this._kernelInfoElement.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly _chooseKernelEntry: IStatusbarEntry = {
|
|
||||||
text: nls.localize('choose', "Choose Kernel"),
|
|
||||||
ariaLabel: nls.localize('choose', "Choose Kernel"),
|
|
||||||
tooltip: nls.localize('tooltop', "Choose kernel for current notebook"),
|
|
||||||
command: 'notebook.selectKernel'
|
|
||||||
};
|
|
||||||
|
|
||||||
private _showKernelStatus(kernel: INotebookKernel | undefined, availableKernelCount: number) {
|
|
||||||
|
|
||||||
if (availableKernelCount === 0) {
|
|
||||||
this._kernelInfoElement.clear();
|
this._kernelInfoElement.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let entry: IStatusbarEntry;
|
const updateStatus = () => {
|
||||||
|
const notebook = activeEditor.viewModel?.notebookDocument;
|
||||||
|
if (notebook) {
|
||||||
|
const info = this._notebookKernelService.getNotebookKernels(notebook);
|
||||||
|
this._showKernelStatus(info.bound, info.all);
|
||||||
|
} else {
|
||||||
|
this._kernelInfoElement.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (kernel) {
|
this._editorDisposables.add(this._notebookKernelService.onDidAddKernel(updateStatus));
|
||||||
entry = {
|
this._editorDisposables.add(this._notebookKernelService.onDidChangeNotebookKernelBinding(updateStatus));
|
||||||
text: `$(notebook-kernel-select) ${kernel.label}`,
|
this._editorDisposables.add(activeEditor.onDidChangeModel(updateStatus));
|
||||||
ariaLabel: kernel.label,
|
updateStatus();
|
||||||
tooltip: kernel.description ?? kernel.detail ?? kernel.label,
|
}
|
||||||
command: availableKernelCount > 1 ? 'notebook.selectKernel' : undefined,
|
|
||||||
};
|
private _showKernelStatus(boundKernel: INotebookKernel | undefined, availableKernels: INotebookKernel[]) {
|
||||||
} else {
|
|
||||||
entry = KernelStatus._chooseKernelEntry;
|
if (availableKernels.length === 0) {
|
||||||
|
this._kernelInfoElement.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!boundKernel) {
|
||||||
|
boundKernel = availableKernels[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
this._kernelInfoElement.value = this._statusbarService.addEntry(
|
this._kernelInfoElement.value = this._statusbarService.addEntry(
|
||||||
entry,
|
{
|
||||||
|
text: `$(notebook-kernel-select) ${boundKernel.label}`,
|
||||||
|
ariaLabel: boundKernel.label,
|
||||||
|
tooltip: boundKernel.description ?? boundKernel.detail ?? boundKernel.label,
|
||||||
|
command: availableKernels.length > 1 ? 'notebook.selectKernel' : undefined,
|
||||||
|
},
|
||||||
'notebook.selectKernel',
|
'notebook.selectKernel',
|
||||||
nls.localize('notebook.info', "Notebook Kernel Info"),
|
nls.localize('notebook.info', "Notebook Kernel Info"),
|
||||||
StatusbarAlignment.RIGHT,
|
StatusbarAlignment.RIGHT,
|
||||||
|
|||||||
@@ -407,6 +407,7 @@
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
display: flex;
|
display: flex;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.monaco-workbench .notebookOverlay.cell-statusbar-hidden .cell-statusbar-container {
|
.monaco-workbench .notebookOverlay.cell-statusbar-hidden .cell-statusbar-container {
|
||||||
@@ -424,6 +425,10 @@
|
|||||||
z-index: 26;
|
z-index: 26;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.monaco-workbench .notebookOverlay .cell-statusbar-container .cell-status-right {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
.monaco-workbench .notebookOverlay .cell-statusbar-container .cell-status-right .cell-contributed-items {
|
.monaco-workbench .notebookOverlay .cell-statusbar-container .cell-status-right .cell-contributed-items {
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
@@ -440,7 +445,9 @@
|
|||||||
white-space: pre;
|
white-space: pre;
|
||||||
|
|
||||||
height: 21px; /* Editor outline is -1px in, don't overlap */
|
height: 21px; /* Editor outline is -1px in, don't overlap */
|
||||||
padding: 0px 6px;
|
margin: 0px 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: clip;
|
||||||
}
|
}
|
||||||
|
|
||||||
.monaco-workbench .notebookOverlay .cell-statusbar-container .cell-status-item.cell-status-item-has-command {
|
.monaco-workbench .notebookOverlay .cell-statusbar-container .cell-status-item.cell-status-item-has-command {
|
||||||
@@ -953,7 +960,6 @@
|
|||||||
|
|
||||||
.monaco-workbench .notebookOverlay .output .error,
|
.monaco-workbench .notebookOverlay .output .error,
|
||||||
.monaco-workbench .notebookOverlay .output .output-plaintext {
|
.monaco-workbench .notebookOverlay .output .output-plaintext {
|
||||||
margin: 4px 0;
|
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ export const NOTEBOOK_CELL_HAS_OUTPUTS = new RawContextKey<boolean>('notebookCel
|
|||||||
export const NOTEBOOK_CELL_INPUT_COLLAPSED = new RawContextKey<boolean>('notebookCellInputIsCollapsed', false); // bool
|
export const NOTEBOOK_CELL_INPUT_COLLAPSED = new RawContextKey<boolean>('notebookCellInputIsCollapsed', false); // bool
|
||||||
export const NOTEBOOK_CELL_OUTPUT_COLLAPSED = new RawContextKey<boolean>('notebookCellOutputIsCollapsed', false); // bool
|
export const NOTEBOOK_CELL_OUTPUT_COLLAPSED = new RawContextKey<boolean>('notebookCellOutputIsCollapsed', false); // bool
|
||||||
// Kernels
|
// Kernels
|
||||||
export const NOTEBOOK_HAS_MULTIPLE_KERNELS = new RawContextKey<boolean>('notebookHasMultipleKernels', false);
|
|
||||||
export const NOTEBOOK_KERNEL_COUNT = new RawContextKey<number>('notebookKernelCount', 0);
|
export const NOTEBOOK_KERNEL_COUNT = new RawContextKey<number>('notebookKernelCount', 0);
|
||||||
export const NOTEBOOK_INTERRUPTIBLE_KERNEL = new RawContextKey<boolean>('notebookInterruptibleKernel', false);
|
export const NOTEBOOK_INTERRUPTIBLE_KERNEL = new RawContextKey<boolean>('notebookInterruptibleKernel', false);
|
||||||
|
|
||||||
@@ -374,11 +373,8 @@ export interface INotebookEditor extends ICommonNotebookEditor {
|
|||||||
*/
|
*/
|
||||||
readonly onDidChangeModel: Event<NotebookTextModel | undefined>;
|
readonly onDidChangeModel: Event<NotebookTextModel | undefined>;
|
||||||
readonly onDidFocusEditorWidget: Event<void>;
|
readonly onDidFocusEditorWidget: Event<void>;
|
||||||
activeKernel: INotebookKernel | undefined;
|
|
||||||
readonly availableKernelCount: number;
|
|
||||||
readonly onDidScroll: Event<void>;
|
readonly onDidScroll: Event<void>;
|
||||||
readonly onDidChangeAvailableKernels: Event<void>;
|
|
||||||
readonly onDidChangeKernel: Event<void>;
|
|
||||||
readonly onDidChangeActiveCell: Event<void>;
|
readonly onDidChangeActiveCell: Event<void>;
|
||||||
isDisposed: boolean;
|
isDisposed: boolean;
|
||||||
dispose(): void;
|
dispose(): void;
|
||||||
@@ -417,11 +413,6 @@ export interface INotebookEditor extends ICommonNotebookEditor {
|
|||||||
*/
|
*/
|
||||||
getOutputRenderer(): OutputRenderer;
|
getOutputRenderer(): OutputRenderer;
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch the contributed kernels for this notebook
|
|
||||||
*/
|
|
||||||
beginComputeContributedKernels(): Promise<INotebookKernel[]>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert a new cell around `cell`
|
* Insert a new cell around `cell`
|
||||||
*/
|
*/
|
||||||
@@ -459,25 +450,17 @@ export interface INotebookEditor extends ICommonNotebookEditor {
|
|||||||
|
|
||||||
focusNextNotebookCell(cell: ICellViewModel, focus: 'editor' | 'container' | 'output'): void;
|
focusNextNotebookCell(cell: ICellViewModel, focus: 'editor' | 'container' | 'output'): void;
|
||||||
|
|
||||||
/**
|
readonly activeKernel: INotebookKernel | undefined;
|
||||||
* Execute the given notebook cell
|
|
||||||
*/
|
|
||||||
executeNotebookCell(cell: ICellViewModel): Promise<void>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel the cell execution
|
* Execute the given notebook cells
|
||||||
*/
|
*/
|
||||||
cancelNotebookCellExecution(cell: ICellViewModel): void;
|
executeNotebookCells(cells?: Iterable<ICellViewModel>): Promise<void>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes all notebook cells in order
|
* Cancel the given notebook cells
|
||||||
*/
|
*/
|
||||||
executeNotebook(): Promise<void>;
|
cancelNotebookCells(cells?: Iterable<ICellViewModel>): Promise<void>
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancel the notebook execution
|
|
||||||
*/
|
|
||||||
cancelNotebookExecution(): void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get current active cell
|
* Get current active cell
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import { IEditorDropService } from 'vs/workbench/services/editor/browser/editorD
|
|||||||
import { IEditorGroup, IEditorGroupsService, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService';
|
import { IEditorGroup, IEditorGroupsService, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import { NotebookEditorOptions, NOTEBOOK_EDITOR_ID } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
import { NotebookEditorOptions, NOTEBOOK_EDITOR_ID } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||||
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
|
|
||||||
import { IBorrowValue, INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService';
|
import { IBorrowValue, INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService';
|
||||||
import { clearMarks, getAndClearMarks, mark } from 'vs/workbench/contrib/notebook/common/notebookPerformance';
|
import { clearMarks, getAndClearMarks, mark } from 'vs/workbench/contrib/notebook/common/notebookPerformance';
|
||||||
import { IFileService } from 'vs/platform/files/common/files';
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
@@ -59,7 +58,6 @@ export class NotebookEditor extends EditorPane {
|
|||||||
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
|
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
|
||||||
@IEditorDropService private readonly _editorDropService: IEditorDropService,
|
@IEditorDropService private readonly _editorDropService: IEditorDropService,
|
||||||
@INotificationService private readonly _notificationService: INotificationService,
|
@INotificationService private readonly _notificationService: INotificationService,
|
||||||
@INotebookService private readonly _notebookService: INotebookService,
|
|
||||||
@INotebookEditorService private readonly _notebookWidgetService: INotebookEditorService,
|
@INotebookEditorService private readonly _notebookWidgetService: INotebookEditorService,
|
||||||
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
||||||
@IFileService private readonly fileService: IFileService,
|
@IFileService private readonly fileService: IFileService,
|
||||||
@@ -189,8 +187,7 @@ export class NotebookEditor extends EditorPane {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this._notebookService.resolveNotebookEditor(model.viewType, model.resource, this._widget.value!.getId());
|
|
||||||
mark(input.resource, 'webviewCommLoaded');
|
|
||||||
|
|
||||||
const viewState = this._loadNotebookEditorViewState(input);
|
const viewState = this._loadNotebookEditorViewState(input);
|
||||||
|
|
||||||
|
|||||||
@@ -3,510 +3,62 @@
|
|||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import * as nls from 'vs/nls';
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput';
|
import { ICellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||||
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
|
import { CellKind, INotebookKernel, INotebookTextModel } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||||
import { Emitter, Event } from 'vs/base/common/event';
|
import { INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
|
||||||
import { Disposable, DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';
|
|
||||||
import { URI } from 'vs/base/common/uri';
|
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
|
||||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
|
||||||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
|
||||||
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
|
|
||||||
import { Memento } from 'vs/workbench/common/memento';
|
|
||||||
import { ICellViewModel, NOTEBOOK_HAS_MULTIPLE_KERNELS, NOTEBOOK_HAS_RUNNING_CELL, NOTEBOOK_INTERRUPTIBLE_KERNEL, NOTEBOOK_KERNEL_COUNT, getRanges } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
|
||||||
import { configureKernelIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons';
|
|
||||||
import { NotebookKernelProviderAssociation, NotebookKernelProviderAssociations, notebookKernelProviderAssociationsSettingId } from 'vs/workbench/contrib/notebook/browser/notebookKernelAssociation';
|
|
||||||
import { CellViewModel, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
|
|
||||||
import { cellIndexesToRanges, CellKind, ICellRange, INotebookKernel, NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
|
||||||
import { NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider';
|
|
||||||
|
|
||||||
const NotebookEditorActiveKernelCache = 'workbench.editor.notebook.activeKernel';
|
|
||||||
|
|
||||||
export interface IKernelManagerDelegate {
|
|
||||||
viewModel: NotebookViewModel | undefined;
|
|
||||||
onDidChangeViewModel: Event<void>;
|
|
||||||
getId(): string;
|
|
||||||
getContributedNotebookProviders(resource?: URI): readonly NotebookProviderInfo[];
|
|
||||||
getContributedNotebookProvider(viewType: string): NotebookProviderInfo | undefined;
|
|
||||||
getNotebookKernels(viewType: string, resource: URI, token: CancellationToken): Promise<INotebookKernel[]>;
|
|
||||||
loadKernelPreloads(extensionLocation: URI, kernel: INotebookKernel): Promise<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class NotebookEditorKernelManager extends Disposable {
|
export class NotebookEditorKernelManager extends Disposable {
|
||||||
private _isDisposed: boolean = false;
|
|
||||||
|
|
||||||
private _activeKernelExecuted: boolean = false;
|
|
||||||
private _activeKernel: INotebookKernel | undefined = undefined;
|
|
||||||
private readonly _onDidChangeKernel = this._register(new Emitter<void>());
|
|
||||||
readonly onDidChangeKernel: Event<void> = this._onDidChangeKernel.event;
|
|
||||||
private readonly _onDidChangeAvailableKernels = this._register(new Emitter<void>());
|
|
||||||
readonly onDidChangeAvailableKernels: Event<void> = this._onDidChangeAvailableKernels.event;
|
|
||||||
|
|
||||||
private _contributedKernelsComputePromise: CancelablePromise<INotebookKernel[]> | null = null;
|
|
||||||
private _initialKernelComputationDone: boolean = false;
|
|
||||||
|
|
||||||
private readonly _notebookHasMultipleKernels: IContextKey<boolean>;
|
|
||||||
private readonly _notebookKernelCount: IContextKey<number>;
|
|
||||||
private readonly _interruptibleKernel: IContextKey<boolean>;
|
|
||||||
private readonly _someCellRunning: IContextKey<boolean>;
|
|
||||||
|
|
||||||
private _cellStateListeners: IDisposable[] = [];
|
|
||||||
private _executionCount = 0;
|
|
||||||
private _viewModelDisposables: DisposableStore;
|
|
||||||
|
|
||||||
get activeKernel() {
|
|
||||||
return this._activeKernel;
|
|
||||||
}
|
|
||||||
|
|
||||||
set activeKernel(kernel: INotebookKernel | undefined) {
|
|
||||||
if (this._isDisposed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this._delegate.viewModel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._activeKernel === kernel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._interruptibleKernel.set(!!kernel?.implementsInterrupt);
|
|
||||||
|
|
||||||
this._activeKernel = kernel;
|
|
||||||
this._activeKernelResolvePromise = undefined;
|
|
||||||
|
|
||||||
const memento = this._activeKernelMemento.getMemento(StorageScope.GLOBAL, StorageTarget.MACHINE);
|
|
||||||
memento[this._delegate.viewModel.viewType] = this._activeKernel?.friendlyId;
|
|
||||||
this._activeKernelMemento.saveMemento();
|
|
||||||
this._onDidChangeKernel.fire();
|
|
||||||
if (this._activeKernel) {
|
|
||||||
this._delegate.loadKernelPreloads(this._activeKernel.localResourceRoot, this._activeKernel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _activeKernelResolvePromise: Promise<void> | undefined = undefined;
|
|
||||||
|
|
||||||
|
|
||||||
private _kernelCount: number = 0;
|
|
||||||
|
|
||||||
get availableKernelCount() {
|
|
||||||
return this._kernelCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly _activeKernelMemento: Memento;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _delegate: IKernelManagerDelegate,
|
@ICommandService private readonly _commandService: ICommandService,
|
||||||
@IStorageService storageService: IStorageService,
|
@INotebookKernelService private readonly _notebookKernelService: INotebookKernelService,
|
||||||
@IContextKeyService contextKeyService: IContextKeyService,
|
) {
|
||||||
@IQuickInputService private readonly _quickInputService: IQuickInputService,
|
|
||||||
@IConfigurationService private readonly _configurationService: IConfigurationService,) {
|
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this._activeKernelMemento = new Memento(NotebookEditorActiveKernelCache, storageService);
|
|
||||||
|
|
||||||
this._notebookHasMultipleKernels = NOTEBOOK_HAS_MULTIPLE_KERNELS.bindTo(contextKeyService);
|
|
||||||
this._notebookKernelCount = NOTEBOOK_KERNEL_COUNT.bindTo(contextKeyService);
|
|
||||||
this._interruptibleKernel = NOTEBOOK_INTERRUPTIBLE_KERNEL.bindTo(contextKeyService);
|
|
||||||
this._someCellRunning = NOTEBOOK_HAS_RUNNING_CELL.bindTo(contextKeyService);
|
|
||||||
|
|
||||||
this._viewModelDisposables = this._register(new DisposableStore());
|
|
||||||
this._register(this._delegate.onDidChangeViewModel(() => {
|
|
||||||
this._viewModelDisposables.clear();
|
|
||||||
this.initCellListeners();
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private initCellListeners(): void {
|
getActiveKernel(notebook: INotebookTextModel): INotebookKernel | undefined {
|
||||||
dispose(this._cellStateListeners);
|
const info = this._notebookKernelService.getNotebookKernels(notebook);
|
||||||
this._cellStateListeners = [];
|
return info.bound ?? info.all[0];
|
||||||
|
|
||||||
if (!this._delegate.viewModel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const addCellStateListener = (c: ICellViewModel) => {
|
|
||||||
return (c as CellViewModel).onDidChangeState(e => {
|
|
||||||
if (!e.runStateChanged) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c.metadata?.runState === NotebookCellExecutionState.Pending) {
|
|
||||||
this._executionCount++;
|
|
||||||
} else if (c.metadata?.runState === NotebookCellExecutionState.Idle) {
|
|
||||||
this._executionCount--;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._someCellRunning.set(this._executionCount > 0);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
this._cellStateListeners = this._delegate.viewModel.viewCells.map(addCellStateListener);
|
|
||||||
|
|
||||||
this._viewModelDisposables.add(this._delegate.viewModel.onDidChangeViewCells(e => {
|
|
||||||
e.splices.reverse().forEach(splice => {
|
|
||||||
const [start, deleted, newCells] = splice;
|
|
||||||
const deletedCells = this._cellStateListeners.splice(start, deleted, ...newCells.map(addCellStateListener));
|
|
||||||
dispose(deletedCells);
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setKernels(refresh: boolean, tokenSource: CancellationTokenSource) {
|
async executeNotebookCells(notebook: INotebookTextModel, cells: Iterable<ICellViewModel>): Promise<void> {
|
||||||
if (!this._delegate.viewModel) {
|
if (!notebook.metadata.trusted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!refresh && this._activeKernel !== undefined && this._activeKernelExecuted) {
|
let kernel = this.getActiveKernel(notebook);
|
||||||
// kernel already executed, we should not change it automatically
|
if (!kernel) {
|
||||||
|
await this._commandService.executeCommand('notebook.selectKernel');
|
||||||
|
kernel = this.getActiveKernel(notebook);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!kernel) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const provider = this._delegate.getContributedNotebookProvider(this._delegate.viewModel.viewType) || this._delegate.getContributedNotebookProviders(this._delegate.viewModel.uri)[0];
|
const cellHandles: number[] = [];
|
||||||
const availableKernels = await this.beginComputeContributedKernels();
|
for (const cell of cells) {
|
||||||
|
if (cell.cellKind !== CellKind.Code) {
|
||||||
if (tokenSource.token.isCancellationRequested) {
|
continue;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._kernelCount = availableKernels.length;
|
|
||||||
this._notebookKernelCount.set(this._kernelCount);
|
|
||||||
this._notebookHasMultipleKernels.set(this._kernelCount > 1);
|
|
||||||
|
|
||||||
this._onDidChangeAvailableKernels.fire();
|
|
||||||
|
|
||||||
let activeKernelStillExist = false;
|
|
||||||
if (this._activeKernel?.friendlyId) {
|
|
||||||
for (let candidateKernel of availableKernels) {
|
|
||||||
if (this._activeKernel.friendlyId === candidateKernel.friendlyId) {
|
|
||||||
// exiting kernel still exists but might have changed. Only update the object and call it a day
|
|
||||||
this._activeKernel = candidateKernel;
|
|
||||||
activeKernelStillExist = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
if (!kernel.supportedLanguages.includes(cell.language)) {
|
||||||
|
continue;
|
||||||
|
|
||||||
if (activeKernelStillExist) {
|
|
||||||
// the kernel still exist, we don't want to modify the selection otherwise user's temporary preference is lost
|
|
||||||
this._onDidChangeKernel.fire();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (availableKernels.length) {
|
|
||||||
return this._setKernelsFromProviders(provider, availableKernels, tokenSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._initialKernelComputationDone = true;
|
|
||||||
|
|
||||||
tokenSource.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
async beginComputeContributedKernels() {
|
|
||||||
if (this._contributedKernelsComputePromise) {
|
|
||||||
return this._contributedKernelsComputePromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._contributedKernelsComputePromise = createCancelablePromise(token => {
|
|
||||||
return this._delegate.getNotebookKernels(this._delegate.viewModel!.viewType, this._delegate.viewModel!.uri, token);
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await this._contributedKernelsComputePromise;
|
|
||||||
this._initialKernelComputationDone = true;
|
|
||||||
this._contributedKernelsComputePromise = null;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _setKernelsFromProviders(provider: NotebookProviderInfo, kernels: INotebookKernel[], tokenSource: CancellationTokenSource) {
|
|
||||||
const rawAssociations = this._configurationService.getValue<NotebookKernelProviderAssociations>(notebookKernelProviderAssociationsSettingId) || [];
|
|
||||||
const userSetKernelProvider = rawAssociations.filter(e => e.viewType === this._delegate.viewModel?.viewType)[0]?.kernelProvider;
|
|
||||||
const memento = this._activeKernelMemento.getMemento(StorageScope.GLOBAL, StorageTarget.MACHINE);
|
|
||||||
|
|
||||||
if (userSetKernelProvider) {
|
|
||||||
const filteredKernels = kernels.filter(kernel => kernel.extension.value === userSetKernelProvider);
|
|
||||||
|
|
||||||
if (filteredKernels.length) {
|
|
||||||
const cachedKernelId = memento[provider.id];
|
|
||||||
this.activeKernel =
|
|
||||||
filteredKernels.find(kernel => kernel.isPreferred)
|
|
||||||
|| filteredKernels.find(kernel => kernel.friendlyId === cachedKernelId)
|
|
||||||
|| filteredKernels[0];
|
|
||||||
} else {
|
|
||||||
this.activeKernel = undefined;
|
|
||||||
}
|
}
|
||||||
|
cellHandles.push(cell.handle);
|
||||||
if (this.activeKernel) {
|
|
||||||
await this._delegate.loadKernelPreloads(this.activeKernel.localResourceRoot, this.activeKernel);
|
|
||||||
|
|
||||||
if (tokenSource.token.isCancellationRequested) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._activeKernelResolvePromise = this.activeKernel.resolve(this._delegate.viewModel!.uri, this._delegate.getId(), tokenSource.token);
|
|
||||||
await this._activeKernelResolvePromise;
|
|
||||||
|
|
||||||
if (tokenSource.token.isCancellationRequested) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
memento[provider.id] = this._activeKernel?.friendlyId;
|
|
||||||
this._activeKernelMemento.saveMemento();
|
|
||||||
|
|
||||||
tokenSource.dispose();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// choose a preferred kernel
|
if (cellHandles.length > 0) {
|
||||||
const kernelsFromSameExtension = kernels.filter(kernel => kernel.extension.value === provider.providerExtensionId);
|
this._notebookKernelService.updateNotebookKernelBinding(notebook, kernel);
|
||||||
if (kernelsFromSameExtension.length) {
|
await kernel.executeNotebookCellsRequest(notebook.uri, cellHandles);
|
||||||
const cachedKernelId = memento[provider.id];
|
|
||||||
|
|
||||||
const preferedKernel = kernelsFromSameExtension.find(kernel => kernel.isPreferred)
|
|
||||||
|| kernelsFromSameExtension.find(kernel => kernel.friendlyId === cachedKernelId)
|
|
||||||
|| kernelsFromSameExtension[0];
|
|
||||||
this.activeKernel = preferedKernel;
|
|
||||||
if (this.activeKernel) {
|
|
||||||
await this._delegate.loadKernelPreloads(this.activeKernel.localResourceRoot, this.activeKernel);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokenSource.token.isCancellationRequested) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await preferedKernel.resolve(this._delegate.viewModel!.uri, this._delegate.getId(), tokenSource.token);
|
|
||||||
|
|
||||||
if (tokenSource.token.isCancellationRequested) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
memento[provider.id] = this._activeKernel?.friendlyId;
|
|
||||||
this._activeKernelMemento.saveMemento();
|
|
||||||
tokenSource.dispose();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the provider doesn't have a builtin kernel, choose a kernel
|
|
||||||
this.activeKernel = kernels[0];
|
|
||||||
if (this.activeKernel) {
|
|
||||||
await this._delegate.loadKernelPreloads(this.activeKernel.localResourceRoot, this.activeKernel);
|
|
||||||
if (tokenSource.token.isCancellationRequested) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.activeKernel.resolve(this._delegate.viewModel!.uri, this._delegate.getId(), tokenSource.token);
|
|
||||||
if (tokenSource.token.isCancellationRequested) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenSource.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _ensureActiveKernel() {
|
|
||||||
if (this._activeKernel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._activeKernelResolvePromise) {
|
|
||||||
await this._activeKernelResolvePromise;
|
|
||||||
|
|
||||||
if (this._activeKernel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!this._initialKernelComputationDone) {
|
|
||||||
await this.setKernels(false, new CancellationTokenSource());
|
|
||||||
|
|
||||||
if (this._activeKernel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// pick active kernel
|
|
||||||
|
|
||||||
const picker = this._quickInputService.createQuickPick<(IQuickPickItem & { run(): void; kernelProviderId?: string })>();
|
|
||||||
picker.placeholder = nls.localize('notebook.runCell.selectKernel', "Select a notebook kernel to run this notebook");
|
|
||||||
picker.matchOnDetail = true;
|
|
||||||
|
|
||||||
const tokenSource = new CancellationTokenSource();
|
|
||||||
const availableKernels = await this.beginComputeContributedKernels();
|
|
||||||
const picks: QuickPickInput<IQuickPickItem & { run(): void; kernelProviderId?: string; }>[] = availableKernels.map((a) => {
|
|
||||||
return {
|
|
||||||
id: a.friendlyId,
|
|
||||||
label: a.label,
|
|
||||||
picked: false,
|
|
||||||
description:
|
|
||||||
a.description
|
|
||||||
? a.description
|
|
||||||
: a.extension.value,
|
|
||||||
detail: a.detail,
|
|
||||||
kernelProviderId: a.extension.value,
|
|
||||||
run: async () => {
|
|
||||||
this.activeKernel = a;
|
|
||||||
this._activeKernelResolvePromise = this.activeKernel.resolve(this._delegate.viewModel!.uri, this._delegate.getId(), tokenSource.token);
|
|
||||||
},
|
|
||||||
buttons: [{
|
|
||||||
iconClass: ThemeIcon.asClassName(configureKernelIcon),
|
|
||||||
tooltip: nls.localize('notebook.promptKernel.setDefaultTooltip', "Set as default kernel provider for '{0}'", this._delegate.viewModel!.viewType)
|
|
||||||
}]
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
picker.items = picks;
|
|
||||||
picker.busy = false;
|
|
||||||
|
|
||||||
const pickedItem = await new Promise<(IQuickPickItem & { run(): void; kernelProviderId?: string; }) | undefined>(resolve => {
|
|
||||||
picker.onDidAccept(() => {
|
|
||||||
resolve(picker.selectedItems.length === 1 ? picker.selectedItems[0] : undefined);
|
|
||||||
picker.dispose();
|
|
||||||
});
|
|
||||||
|
|
||||||
picker.onDidTriggerItemButton(e => {
|
|
||||||
const pick = e.item;
|
|
||||||
const id = pick.id;
|
|
||||||
resolve(pick); // open the view
|
|
||||||
picker.dispose();
|
|
||||||
|
|
||||||
// And persist the setting
|
|
||||||
if (pick && id && pick.kernelProviderId) {
|
|
||||||
const newAssociation: NotebookKernelProviderAssociation = { viewType: this._delegate.viewModel!.viewType, kernelProvider: pick.kernelProviderId };
|
|
||||||
const currentAssociations = [...this._configurationService.getValue<NotebookKernelProviderAssociations>(notebookKernelProviderAssociationsSettingId)];
|
|
||||||
|
|
||||||
// First try updating existing association
|
|
||||||
for (let i = 0; i < currentAssociations.length; ++i) {
|
|
||||||
const existing = currentAssociations[i];
|
|
||||||
if (existing.viewType === newAssociation.viewType) {
|
|
||||||
currentAssociations.splice(i, 1, newAssociation);
|
|
||||||
this._configurationService.updateValue(notebookKernelProviderAssociationsSettingId, currentAssociations);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, create a new one
|
|
||||||
currentAssociations.unshift(newAssociation);
|
|
||||||
this._configurationService.updateValue(notebookKernelProviderAssociationsSettingId, currentAssociations);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
tokenSource.dispose();
|
|
||||||
|
|
||||||
if (pickedItem) {
|
|
||||||
await pickedItem.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
async cancelNotebookExecution(): Promise<void> {
|
|
||||||
if (!this._delegate.viewModel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this._ensureActiveKernel();
|
|
||||||
|
|
||||||
const fullRange: ICellRange = {
|
|
||||||
start: 0, end: this._delegate.viewModel.length
|
|
||||||
};
|
|
||||||
await this._activeKernel?.cancelNotebookCellExecution!(this._delegate.viewModel.uri, [fullRange]);
|
|
||||||
}
|
|
||||||
|
|
||||||
async executeNotebook(): Promise<void> {
|
|
||||||
if (!this._delegate.viewModel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this._ensureActiveKernel();
|
|
||||||
if (!this.canExecuteNotebook()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const codeCellRanges = getRanges(this._delegate.viewModel.viewCells, cell => cell.cellKind === CellKind.Code);
|
|
||||||
if (codeCellRanges.length) {
|
|
||||||
this._activeKernelExecuted = true;
|
|
||||||
await this._activeKernel?.executeNotebookCellsRequest(this._delegate.viewModel.uri, codeCellRanges);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async cancelNotebookCellExecution(cell: ICellViewModel): Promise<void> {
|
async cancelNotebookCells(notebook: INotebookTextModel, cells: Iterable<ICellViewModel>): Promise<void> {
|
||||||
if (!this._delegate.viewModel) {
|
let kernel = this.getActiveKernel(notebook);
|
||||||
return;
|
if (kernel) {
|
||||||
|
await kernel.cancelNotebookCellExecution(notebook.uri, Array.from(cells, cell => cell.handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cell.cellKind !== CellKind.Code) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const metadata = cell.getEvaluatedMetadata(this._delegate.viewModel.metadata);
|
|
||||||
if (metadata.runState === NotebookCellExecutionState.Idle) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this._ensureActiveKernel();
|
|
||||||
|
|
||||||
const idx = this._delegate.viewModel.getCellIndex(cell);
|
|
||||||
const ranges = cellIndexesToRanges([idx]);
|
|
||||||
await this._activeKernel?.cancelNotebookCellExecution!(this._delegate.viewModel.uri, ranges);
|
|
||||||
}
|
|
||||||
|
|
||||||
async executeNotebookCell(cell: ICellViewModel): Promise<void> {
|
|
||||||
if (!this._delegate.viewModel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this._ensureActiveKernel();
|
|
||||||
if (!this.canExecuteCell(cell)) {
|
|
||||||
throw new Error('Cell is not executable: ' + cell.uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.activeKernel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const idx = this._delegate.viewModel.getCellIndex(cell);
|
|
||||||
const range = cellIndexesToRanges([idx]);
|
|
||||||
this._activeKernelExecuted = true;
|
|
||||||
await this._activeKernel!.executeNotebookCellsRequest(this._delegate.viewModel.uri, range);
|
|
||||||
}
|
|
||||||
|
|
||||||
private canExecuteNotebook(): boolean {
|
|
||||||
if (!this.activeKernel) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this._delegate.viewModel?.trusted) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private canExecuteCell(cell: ICellViewModel): boolean {
|
|
||||||
if (!this.activeKernel) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cell.cellKind !== CellKind.Code) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.activeKernel.supportedLanguages) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.activeKernel.supportedLanguages.includes(cell.language)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,12 +10,11 @@ import { IMouseWheelEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent
|
|||||||
import { IListContextMenuEvent } from 'vs/base/browser/ui/list/list';
|
import { IListContextMenuEvent } from 'vs/base/browser/ui/list/list';
|
||||||
import { IAction } from 'vs/base/common/actions';
|
import { IAction } from 'vs/base/common/actions';
|
||||||
import { SequencerByKey } from 'vs/base/common/async';
|
import { SequencerByKey } from 'vs/base/common/async';
|
||||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
|
||||||
import { Color, RGBA } from 'vs/base/common/color';
|
import { Color, RGBA } from 'vs/base/common/color';
|
||||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||||
import { Emitter, Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
import { combinedDisposable, Disposable, DisposableStore, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
import { combinedDisposable, Disposable, DisposableStore, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { extname } from 'vs/base/common/resources';
|
import { extname, isEqual } from 'vs/base/common/resources';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { generateUuid } from 'vs/base/common/uuid';
|
import { generateUuid } from 'vs/base/common/uuid';
|
||||||
import 'vs/css!./media/notebook';
|
import 'vs/css!./media/notebook';
|
||||||
@@ -47,7 +46,7 @@ import { BOTTOM_CELL_TOOLBAR_GAP, BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_BOTTOM_MARGIN
|
|||||||
import { CellEditState, CellFocusMode, IActiveNotebookEditor, ICellOutputViewModel, ICellViewModel, ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IFocusNotebookCellOptions, IGenericCellViewModel, IInsetRenderOutput, INotebookCellList, INotebookCellOutputLayoutInfo, INotebookDeltaDecoration, INotebookEditor, INotebookEditorContribution, INotebookEditorContributionDescription, INotebookEditorCreationOptions, INotebookEditorMouseEvent, NotebookEditorOptions, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_ID, NOTEBOOK_OUTPUT_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
import { CellEditState, CellFocusMode, IActiveNotebookEditor, ICellOutputViewModel, ICellViewModel, ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IFocusNotebookCellOptions, IGenericCellViewModel, IInsetRenderOutput, INotebookCellList, INotebookCellOutputLayoutInfo, INotebookDeltaDecoration, INotebookEditor, INotebookEditorContribution, INotebookEditorContributionDescription, INotebookEditorCreationOptions, INotebookEditorMouseEvent, NotebookEditorOptions, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_ID, NOTEBOOK_OUTPUT_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||||
import { NotebookDecorationCSSRules, NotebookRefCountedStyleSheet } from 'vs/workbench/contrib/notebook/browser/notebookEditorDecorations';
|
import { NotebookDecorationCSSRules, NotebookRefCountedStyleSheet } from 'vs/workbench/contrib/notebook/browser/notebookEditorDecorations';
|
||||||
import { NotebookEditorExtensionsRegistry } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions';
|
import { NotebookEditorExtensionsRegistry } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions';
|
||||||
import { IKernelManagerDelegate, NotebookEditorKernelManager } from 'vs/workbench/contrib/notebook/browser/notebookEditorKernelManager';
|
import { NotebookEditorKernelManager } from 'vs/workbench/contrib/notebook/browser/notebookEditorKernelManager';
|
||||||
import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService';
|
import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService';
|
||||||
import { errorStateIcon, successStateIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons';
|
import { errorStateIcon, successStateIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons';
|
||||||
import { NotebookCellList } from 'vs/workbench/contrib/notebook/browser/view/notebookCellList';
|
import { NotebookCellList } from 'vs/workbench/contrib/notebook/browser/view/notebookCellList';
|
||||||
@@ -61,9 +60,7 @@ import { NotebookEventDispatcher, NotebookLayoutChangedEvent } from 'vs/workbenc
|
|||||||
import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel';
|
import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel';
|
||||||
import { CellViewModel, IModelDecorationsChangeAccessor, INotebookEditorViewState, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
|
import { CellViewModel, IModelDecorationsChangeAccessor, INotebookEditorViewState, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
|
||||||
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
|
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
|
||||||
import { CellKind, CellToolbarLocKey, ExperimentalUseMarkdownRenderer, ICellRange, INotebookKernel, SelectionStateType, ShowCellStatusBarKey } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
import { CellKind, CellToolbarLocKey, ExperimentalUseMarkdownRenderer, ICellRange, SelectionStateType, ShowCellStatusBarKey } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||||
import { NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider';
|
|
||||||
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
|
|
||||||
import { editorGutterModifiedBackground } from 'vs/workbench/contrib/scm/browser/dirtydiffDecorator';
|
import { editorGutterModifiedBackground } from 'vs/workbench/contrib/scm/browser/dirtydiffDecorator';
|
||||||
import { Webview } from 'vs/workbench/contrib/webview/browser/webview';
|
import { Webview } from 'vs/workbench/contrib/webview/browser/webview';
|
||||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||||
@@ -76,6 +73,8 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
|
|||||||
import { isWeb } from 'vs/base/common/platform';
|
import { isWeb } from 'vs/base/common/platform';
|
||||||
import { mark } from 'vs/workbench/contrib/notebook/common/notebookPerformance';
|
import { mark } from 'vs/workbench/contrib/notebook/common/notebookPerformance';
|
||||||
import { readFontInfo } from 'vs/editor/browser/config/configuration';
|
import { readFontInfo } from 'vs/editor/browser/config/configuration';
|
||||||
|
import { INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
|
||||||
|
import { NotebookEditorContextKeys } from 'vs/workbench/contrib/notebook/browser/notebookEditorWidgetContextKeys';
|
||||||
|
|
||||||
const $ = DOM.$;
|
const $ = DOM.$;
|
||||||
|
|
||||||
@@ -267,27 +266,6 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
|||||||
return this._notebookViewModel?.notebookDocument;
|
return this._notebookViewModel?.notebookDocument;
|
||||||
}
|
}
|
||||||
|
|
||||||
get onDidChangeKernel(): Event<void> {
|
|
||||||
return this._kernelManger.onDidChangeKernel;
|
|
||||||
}
|
|
||||||
get onDidChangeAvailableKernels(): Event<void> {
|
|
||||||
return this._kernelManger.onDidChangeAvailableKernels;
|
|
||||||
}
|
|
||||||
|
|
||||||
get activeKernel() {
|
|
||||||
return this._kernelManger.activeKernel;
|
|
||||||
}
|
|
||||||
|
|
||||||
set activeKernel(value) {
|
|
||||||
this._kernelManger.activeKernel = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _currentKernelTokenSource: CancellationTokenSource | undefined = undefined;
|
|
||||||
|
|
||||||
get availableKernelCount() {
|
|
||||||
return this._kernelManger.availableKernelCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly _onDidChangeActiveEditor = this._register(new Emitter<this>());
|
private readonly _onDidChangeActiveEditor = this._register(new Emitter<this>());
|
||||||
readonly onDidChangeActiveEditor: Event<this> = this._onDidChangeActiveEditor.event;
|
readonly onDidChangeActiveEditor: Event<this> = this._onDidChangeActiveEditor.event;
|
||||||
|
|
||||||
@@ -333,8 +311,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
|||||||
@IInstantiationService instantiationService: IInstantiationService,
|
@IInstantiationService instantiationService: IInstantiationService,
|
||||||
@IStorageService storageService: IStorageService,
|
@IStorageService storageService: IStorageService,
|
||||||
@IAccessibilityService accessibilityService: IAccessibilityService,
|
@IAccessibilityService accessibilityService: IAccessibilityService,
|
||||||
@INotebookService private notebookService: INotebookService,
|
|
||||||
@INotebookEditorService private readonly notebookEditorService: INotebookEditorService,
|
@INotebookEditorService private readonly notebookEditorService: INotebookEditorService,
|
||||||
|
@INotebookKernelService notebookKernelService: INotebookKernelService,
|
||||||
@IEditorService private readonly editorService: IEditorService,
|
@IEditorService private readonly editorService: IEditorService,
|
||||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||||
@IContextKeyService contextKeyService: IContextKeyService,
|
@IContextKeyService contextKeyService: IContextKeyService,
|
||||||
@@ -356,22 +334,14 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
|||||||
this.scopedContextKeyService = contextKeyService.createScoped(this._overlayContainer);
|
this.scopedContextKeyService = contextKeyService.createScoped(this._overlayContainer);
|
||||||
this.instantiationService = instantiationService.createChild(new ServiceCollection([IContextKeyService, this.scopedContextKeyService]));
|
this.instantiationService = instantiationService.createChild(new ServiceCollection([IContextKeyService, this.scopedContextKeyService]));
|
||||||
|
|
||||||
const that = this;
|
this._register(instantiationService.createInstance(NotebookEditorContextKeys, this));
|
||||||
this._kernelManger = instantiationService.createInstance(NotebookEditorKernelManager, <IKernelManagerDelegate>{
|
|
||||||
getId() { return that.getId(); },
|
this._kernelManger = instantiationService.createInstance(NotebookEditorKernelManager);
|
||||||
loadKernelPreloads: that._loadKernelPreloads.bind(that),
|
this._register(notebookKernelService.onDidChangeNotebookKernelBinding(e => {
|
||||||
onDidChangeViewModel: that.onDidChangeModel,
|
if (isEqual(e.notebook, this.viewModel?.uri)) {
|
||||||
get viewModel() { return that.viewModel; },
|
this._loadKernelPreloads();
|
||||||
getContributedNotebookProviders(resource?: URI) {
|
|
||||||
return that.notebookService.getContributedNotebookProviders(resource);
|
|
||||||
},
|
|
||||||
getContributedNotebookProvider(viewType: string): NotebookProviderInfo | undefined {
|
|
||||||
return that.notebookService.getContributedNotebookProvider(viewType);
|
|
||||||
},
|
|
||||||
getNotebookKernels(viewType: string, resource: URI, token: CancellationToken): Promise<INotebookKernel[]> {
|
|
||||||
return that.notebookService.getNotebookKernels(viewType, resource, token);
|
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
|
|
||||||
this._memento = new Memento(NOTEBOOK_EDITOR_ID, storageService);
|
this._memento = new Memento(NOTEBOOK_EDITOR_ID, storageService);
|
||||||
|
|
||||||
@@ -888,24 +858,12 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
|||||||
this.restoreListViewState(viewState);
|
this.restoreListViewState(viewState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// load preloads for matching kernel
|
||||||
|
this._loadKernelPreloads();
|
||||||
|
|
||||||
// clear state
|
// clear state
|
||||||
this._dndController?.clearGlobalDragState();
|
this._dndController?.clearGlobalDragState();
|
||||||
|
|
||||||
this._currentKernelTokenSource = new CancellationTokenSource();
|
|
||||||
this._localStore.add(this._currentKernelTokenSource);
|
|
||||||
// we don't await for it, otherwise it will slow down the file opening
|
|
||||||
this._setKernels(false, this._currentKernelTokenSource);
|
|
||||||
|
|
||||||
this._localStore.add(this.notebookService.onDidChangeKernels(async (e) => {
|
|
||||||
if (e && e.toString() !== this.textModel?.uri.toString()) {
|
|
||||||
// kernel update is not for current document.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._currentKernelTokenSource?.cancel();
|
|
||||||
this._currentKernelTokenSource = new CancellationTokenSource();
|
|
||||||
await this._setKernels(true, this._currentKernelTokenSource);
|
|
||||||
}));
|
|
||||||
|
|
||||||
this._localStore.add(this._list.onDidChangeFocus(() => {
|
this._localStore.add(this._list.onDidChangeFocus(() => {
|
||||||
this.updateContextKeysOnFocusChange();
|
this.updateContextKeysOnFocusChange();
|
||||||
}));
|
}));
|
||||||
@@ -998,28 +956,6 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
|||||||
this._list.clear();
|
this._list.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
async beginComputeContributedKernels() {
|
|
||||||
return this._kernelManger.beginComputeContributedKernels();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _setKernels(refresh: boolean, tokenSource: CancellationTokenSource) {
|
|
||||||
if (this.viewModel) {
|
|
||||||
this._kernelManger.setKernels(refresh, tokenSource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _loadKernelPreloads(extensionLocation: URI, kernel: INotebookKernel) {
|
|
||||||
const preloadUris = kernel.preloadUris;
|
|
||||||
if (!preloadUris.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this._webview?.isResolved()) {
|
|
||||||
await this._resolveWebview();
|
|
||||||
}
|
|
||||||
|
|
||||||
this._webview?.updateKernelPreloads([extensionLocation], kernel.preloadUris);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _updateForOptions(): void {
|
private _updateForOptions(): void {
|
||||||
if (!this.hasModel()) {
|
if (!this.hasModel()) {
|
||||||
@@ -1072,13 +1008,6 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this._localStore.add(this._webview.onMessage(e => {
|
|
||||||
if (this.viewModel) {
|
|
||||||
this.notebookService.onDidReceiveMessage(this.viewModel.viewType, this.getId(), e.forRenderer, e.message);
|
|
||||||
this._onDidReceiveMessage.fire(e);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
resolve(this._webview);
|
resolve(this._webview);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1716,30 +1645,46 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
|||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region Kernel/Execution
|
//#region Kernel/Execution
|
||||||
async cancelNotebookExecution(): Promise<void> {
|
|
||||||
return this._kernelManger.cancelNotebookExecution();
|
|
||||||
}
|
|
||||||
|
|
||||||
async executeNotebook(): Promise<void> {
|
private async _loadKernelPreloads() {
|
||||||
return this._kernelManger.executeNotebook();
|
const kernel = this.activeKernel;
|
||||||
}
|
if (!kernel) {
|
||||||
|
return;
|
||||||
async cancelNotebookCellExecution(cell: ICellViewModel): Promise<void> {
|
}
|
||||||
return this._kernelManger.cancelNotebookCellExecution(cell);
|
const preloadUris = kernel.preloadUris;
|
||||||
}
|
if (!preloadUris.length) {
|
||||||
|
|
||||||
async executeNotebookCell(cell: ICellViewModel): Promise<void> {
|
|
||||||
if (!this.viewModel) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO@roblourens, don't use the "execute" command for this
|
if (!this._webview?.isResolved()) {
|
||||||
if (cell.cellKind === CellKind.Markdown) {
|
await this._resolveWebview();
|
||||||
this.focusNotebookCell(cell, 'container');
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._kernelManger.executeNotebookCell(cell);
|
this._webview?.updateKernelPreloads([kernel.localResourceRoot], kernel.preloadUris);
|
||||||
|
}
|
||||||
|
|
||||||
|
get activeKernel() {
|
||||||
|
return this.viewModel && this._kernelManger.getActiveKernel(this.viewModel.notebookDocument);
|
||||||
|
}
|
||||||
|
|
||||||
|
async cancelNotebookCells(cells?: Iterable<ICellViewModel>): Promise<void> {
|
||||||
|
if (!this.hasModel()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!cells) {
|
||||||
|
cells = this.viewModel.viewCells;
|
||||||
|
}
|
||||||
|
return this._kernelManger.cancelNotebookCells(this.viewModel.notebookDocument, cells);
|
||||||
|
}
|
||||||
|
|
||||||
|
async executeNotebookCells(cells?: Iterable<ICellViewModel>): Promise<void> {
|
||||||
|
if (!this.hasModel()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!cells) {
|
||||||
|
cells = this.viewModel.viewCells;
|
||||||
|
}
|
||||||
|
return this._kernelManger.executeNotebookCells(this.viewModel.notebookDocument, cells);
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
@@ -1811,7 +1756,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
|||||||
const nextIndex = ui ? this.viewModel.getNextVisibleCellIndex(index) : index + 1;
|
const nextIndex = ui ? this.viewModel.getNextVisibleCellIndex(index) : index + 1;
|
||||||
let language;
|
let language;
|
||||||
if (type === CellKind.Code) {
|
if (type === CellKind.Code) {
|
||||||
const supportedLanguages = this._kernelManger.activeKernel?.supportedLanguages ?? this.modeService.getRegisteredModes();
|
const supportedLanguages = this.activeKernel?.supportedLanguages ?? this.modeService.getRegisteredModes();
|
||||||
const defaultLanguage = supportedLanguages[0] || 'plaintext';
|
const defaultLanguage = supportedLanguages[0] || 'plaintext';
|
||||||
if (cell?.cellKind === CellKind.Code) {
|
if (cell?.cellKind === CellKind.Code) {
|
||||||
language = cell.language;
|
language = cell.language;
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||||
|
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||||
|
import { ICellViewModel, NOTEBOOK_HAS_RUNNING_CELL, NOTEBOOK_INTERRUPTIBLE_KERNEL, NOTEBOOK_KERNEL_COUNT, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||||
|
import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
|
||||||
|
import { NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||||
|
import { INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
|
||||||
|
|
||||||
|
export class NotebookEditorContextKeys {
|
||||||
|
|
||||||
|
private readonly _notebookKernelCount: IContextKey<number>;
|
||||||
|
private readonly _interruptibleKernel: IContextKey<boolean>;
|
||||||
|
private readonly _someCellRunning: IContextKey<boolean>;
|
||||||
|
|
||||||
|
private readonly _disposables = new DisposableStore();
|
||||||
|
private readonly _viewModelDisposables = new DisposableStore();
|
||||||
|
private readonly _cellStateListeners: IDisposable[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly _editor: INotebookEditor,
|
||||||
|
@INotebookKernelService private readonly _notebookKernelService: INotebookKernelService,
|
||||||
|
@IContextKeyService contextKeyService: IContextKeyService,
|
||||||
|
) {
|
||||||
|
this._notebookKernelCount = NOTEBOOK_KERNEL_COUNT.bindTo(contextKeyService);
|
||||||
|
this._interruptibleKernel = NOTEBOOK_INTERRUPTIBLE_KERNEL.bindTo(contextKeyService);
|
||||||
|
this._someCellRunning = NOTEBOOK_HAS_RUNNING_CELL.bindTo(contextKeyService);
|
||||||
|
|
||||||
|
this._disposables.add(_editor.onDidChangeModel(() => this._initCellListeners()));
|
||||||
|
this._initCellListeners();
|
||||||
|
|
||||||
|
this._updateKernelContext();
|
||||||
|
this._disposables.add(_notebookKernelService.onDidAddKernel(this._updateKernelContext, this));
|
||||||
|
this._disposables.add(_notebookKernelService.onDidChangeNotebookKernelBinding(this._updateKernelContext, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose(): void {
|
||||||
|
this._disposables.dispose();
|
||||||
|
this._viewModelDisposables.dispose();
|
||||||
|
this._notebookKernelCount.reset();
|
||||||
|
this._interruptibleKernel.reset();
|
||||||
|
this._someCellRunning.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _initCellListeners(): void {
|
||||||
|
|
||||||
|
this._viewModelDisposables.clear();
|
||||||
|
dispose(this._cellStateListeners);
|
||||||
|
this._cellStateListeners.length = 0;
|
||||||
|
|
||||||
|
if (!this._editor.hasModel()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let executionCount = 0;
|
||||||
|
|
||||||
|
const addCellStateListener = (c: ICellViewModel) => {
|
||||||
|
return (c as CellViewModel).onDidChangeState(e => {
|
||||||
|
if (!e.runStateChanged) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (c.metadata?.runState === NotebookCellExecutionState.Pending) {
|
||||||
|
executionCount++;
|
||||||
|
} else if (c.metadata?.runState === NotebookCellExecutionState.Idle) {
|
||||||
|
executionCount--;
|
||||||
|
}
|
||||||
|
this._someCellRunning.set(executionCount > 0);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const cell of this._editor.viewModel.viewCells) {
|
||||||
|
this._cellStateListeners.push(addCellStateListener(cell));
|
||||||
|
}
|
||||||
|
|
||||||
|
this._viewModelDisposables.add(this._editor.viewModel.onDidChangeViewCells(e => {
|
||||||
|
e.splices.reverse().forEach(splice => {
|
||||||
|
const [start, deleted, newCells] = splice;
|
||||||
|
const deletedCells = this._cellStateListeners.splice(start, deleted, ...newCells.map(addCellStateListener));
|
||||||
|
dispose(deletedCells);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private _updateKernelContext(): void {
|
||||||
|
if (!this._editor.hasModel()) {
|
||||||
|
this._notebookKernelCount.reset();
|
||||||
|
this._interruptibleKernel.reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { bound, all } = this._notebookKernelService.getNotebookKernels(this._editor.viewModel.notebookDocument);
|
||||||
|
this._notebookKernelCount.set(all.length);
|
||||||
|
this._interruptibleKernel.set(bound?.implementsInterrupt ?? false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,32 +4,68 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { Event, Emitter } from 'vs/base/common/event';
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
import { DisposableStore, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { INotebookTextModel } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
import { INotebookKernel, INotebookTextModel } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||||
import { INotebookKernelBindEvent, INotebookKernel2, INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
|
import { INotebookKernelBindEvent, INotebookKernelService, INotebookTextModelLike } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
|
||||||
import { score } from 'vs/workbench/contrib/notebook/common/notebookSelector';
|
import { score } from 'vs/workbench/contrib/notebook/common/notebookSelector';
|
||||||
import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
|
import { LRUCache } from 'vs/base/common/map';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||||
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
|
||||||
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
|
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { ResourceMap } from 'vs/base/common/map';
|
import { runWhenIdle } from 'vs/base/common/async';
|
||||||
import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
|
import { isEqual } from 'vs/base/common/resources';
|
||||||
|
|
||||||
|
interface IKernelInfo {
|
||||||
|
kernel: INotebookKernel;
|
||||||
|
score: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScoreInfo {
|
||||||
|
constructor(private readonly _anchor: INotebookTextModelLike) { }
|
||||||
|
|
||||||
|
equals(candidate: INotebookTextModelLike): boolean {
|
||||||
|
return this._anchor.viewType === candidate.viewType && isEqual(this._anchor.uri, candidate.uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class NotebookKernelService implements INotebookKernelService {
|
export class NotebookKernelService implements INotebookKernelService {
|
||||||
|
|
||||||
declare _serviceBrand: undefined;
|
declare _serviceBrand: undefined;
|
||||||
|
|
||||||
private readonly _kernels = new Map<string, INotebookKernel2>();
|
private static _storageKey = 'notebook.kernelBindings';
|
||||||
private readonly _kernelBindings = new ResourceMap<INotebookKernel2>();
|
|
||||||
|
private readonly _kernels = new Map<string, IKernelInfo>();
|
||||||
|
private readonly _kernelBindings = new LRUCache<string, string>(1000, 0.7);
|
||||||
|
private _scoreInfo?: ScoreInfo;
|
||||||
|
|
||||||
private readonly _onDidChangeNotebookKernelBinding = new Emitter<INotebookKernelBindEvent>();
|
private readonly _onDidChangeNotebookKernelBinding = new Emitter<INotebookKernelBindEvent>();
|
||||||
private readonly _onDidAddKernel = new Emitter<INotebookKernel2>();
|
private readonly _onDidAddKernel = new Emitter<INotebookKernel>();
|
||||||
private readonly _onDidRemoveKernel = new Emitter<INotebookKernel2>();
|
private readonly _onDidRemoveKernel = new Emitter<INotebookKernel>();
|
||||||
|
|
||||||
readonly onDidChangeNotebookKernelBinding: Event<INotebookKernelBindEvent> = this._onDidChangeNotebookKernelBinding.event;
|
readonly onDidChangeNotebookKernelBinding: Event<INotebookKernelBindEvent> = this._onDidChangeNotebookKernelBinding.event;
|
||||||
readonly onDidAddKernel: Event<INotebookKernel2> = this._onDidAddKernel.event;
|
readonly onDidAddKernel: Event<INotebookKernel> = this._onDidAddKernel.event;
|
||||||
readonly onDidRemoveKernel: Event<INotebookKernel2> = this._onDidRemoveKernel.event;
|
readonly onDidRemoveKernel: Event<INotebookKernel> = this._onDidRemoveKernel.event;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@IStorageService private _storageService: IStorageService,
|
||||||
|
@ILogService logService: ILogService,
|
||||||
|
) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
const value = _storageService.get(NotebookKernelService._storageKey, StorageScope.WORKSPACE, '[]');
|
||||||
|
const data = JSON.parse(value);
|
||||||
|
this._kernelBindings.fromJSON(data);
|
||||||
|
} catch {
|
||||||
|
logService.warn('FAILED to restore kernel bindings');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _persistBindings(): void {
|
||||||
|
runWhenIdle(() => {
|
||||||
|
const raw = JSON.stringify(this._kernelBindings);
|
||||||
|
this._storageService.store(NotebookKernelService._storageKey, raw, StorageScope.WORKSPACE, StorageTarget.MACHINE);
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
dispose() {
|
dispose() {
|
||||||
this._onDidChangeNotebookKernelBinding.dispose();
|
this._onDidChangeNotebookKernelBinding.dispose();
|
||||||
@@ -38,154 +74,80 @@ export class NotebookKernelService implements INotebookKernelService {
|
|||||||
this._kernels.clear();
|
this._kernels.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
registerKernel(kernel: INotebookKernel2): IDisposable {
|
registerKernel(kernel: INotebookKernel): IDisposable {
|
||||||
if (this._kernels.has(kernel.id)) {
|
if (this._kernels.has(kernel.id)) {
|
||||||
throw new Error(`NOTEBOOK CONTROLLER with id '${kernel.id}' already exists`);
|
throw new Error(`NOTEBOOK CONTROLLER with id '${kernel.id}' already exists`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._kernels.set(kernel.id, kernel);
|
this._scoreInfo = undefined;
|
||||||
|
this._kernels.set(kernel.id, { kernel, score: -1 });
|
||||||
this._onDidAddKernel.fire(kernel);
|
this._onDidAddKernel.fire(kernel);
|
||||||
|
|
||||||
return toDisposable(() => {
|
return toDisposable(() => {
|
||||||
|
this._scoreInfo = undefined;
|
||||||
if (this._kernels.delete(kernel.id)) {
|
if (this._kernels.delete(kernel.id)) {
|
||||||
this._onDidRemoveKernel.fire(kernel);
|
this._onDidRemoveKernel.fire(kernel);
|
||||||
}
|
}
|
||||||
for (let [uri, candidate] of this._kernelBindings) {
|
for (let [uri, candidate] of Array.from(this._kernelBindings)) {
|
||||||
if (candidate === kernel) {
|
if (candidate === kernel.id) {
|
||||||
this._kernelBindings.delete(uri);
|
this._kernelBindings.delete(uri);
|
||||||
this._onDidChangeNotebookKernelBinding.fire({ notebook: uri, oldKernel: kernel, newKernel: undefined });
|
this._onDidChangeNotebookKernelBinding.fire({ notebook: URI.parse(uri), oldKernel: kernel.id, newKernel: undefined });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getMatchingKernels(notebook: INotebookTextModel): INotebookKernel2[] {
|
getNotebookKernels(notebook: INotebookTextModelLike): { bound: INotebookKernel | undefined, all: INotebookKernel[] } {
|
||||||
const result: INotebookKernel2[] = [];
|
|
||||||
for (const kernel of this._kernels.values()) {
|
// update score if needed
|
||||||
if (score(kernel.selector, notebook.uri, notebook.viewType) > 0) {
|
if (!this._scoreInfo?.equals(notebook)) {
|
||||||
result.push(kernel);
|
for (let item of this._kernels.values()) {
|
||||||
|
item.score = score(item.kernel.selector, notebook.uri, notebook.viewType);
|
||||||
}
|
}
|
||||||
|
this._scoreInfo = new ScoreInfo(notebook);
|
||||||
}
|
}
|
||||||
const boundKernel = this._kernelBindings.get(notebook.uri);
|
|
||||||
return result.sort((a, b) => {
|
// all applicable kernels
|
||||||
// (1) binding a kernel
|
const all = Array.from(this._kernels.values())
|
||||||
if (a === boundKernel) {
|
.filter(item => item.score > 0)
|
||||||
return -1;
|
.sort((a, b) => {
|
||||||
} else if (b === boundKernel) {
|
// (1) sort by preference
|
||||||
return 1;
|
if (a.kernel.isPreferred !== b.kernel.isPreferred) {
|
||||||
}
|
if (a.kernel.isPreferred) {
|
||||||
// (2) preferring a kernel
|
return -1;
|
||||||
if (a.isPreferred === b.isPreferred) {
|
} else {
|
||||||
return 0;
|
return 1;
|
||||||
} else if (a.isPreferred) {
|
}
|
||||||
return -1;
|
}
|
||||||
} else {
|
// (2) sort by score
|
||||||
return 1;
|
if (b.score !== a.score) {
|
||||||
}
|
return b.score - a.score;
|
||||||
});
|
}
|
||||||
|
// (3) sort by name
|
||||||
|
return a.kernel.label.localeCompare(b.kernel.label);
|
||||||
|
})
|
||||||
|
.map(item => item.kernel);
|
||||||
|
|
||||||
|
// bound kernel
|
||||||
|
const boundId = this._kernelBindings.get(notebook.uri.toString());
|
||||||
|
const bound = boundId ? this._kernels.get(boundId)?.kernel : undefined;
|
||||||
|
|
||||||
|
return { all, bound };
|
||||||
}
|
}
|
||||||
|
|
||||||
// a notebook has one kernel, a kernel has N notebooks
|
// a notebook has one kernel, a kernel has N notebooks
|
||||||
// notebook <-1----N-> kernel
|
// notebook <-1----N-> kernel
|
||||||
updateNotebookKernelBinding(notebook: INotebookTextModel, kernel: INotebookKernel2 | undefined): void {
|
updateNotebookKernelBinding(notebook: INotebookTextModel, kernel: INotebookKernel | undefined): void {
|
||||||
const oldKernel = this._kernelBindings.get(notebook.uri);
|
const key = notebook.uri.toString();
|
||||||
if (oldKernel !== kernel) {
|
const oldKernel = this._kernelBindings.get(key);
|
||||||
|
if (oldKernel !== kernel?.id) {
|
||||||
if (kernel) {
|
if (kernel) {
|
||||||
this._kernelBindings.set(notebook.uri, kernel);
|
this._kernelBindings.set(key, kernel.id);
|
||||||
} else {
|
} else {
|
||||||
this._kernelBindings.delete(notebook.uri);
|
this._kernelBindings.delete(key);
|
||||||
}
|
}
|
||||||
this._onDidChangeNotebookKernelBinding.fire({ notebook: notebook.uri, oldKernel, newKernel: kernel });
|
this._onDidChangeNotebookKernelBinding.fire({ notebook: notebook.uri, oldKernel, newKernel: kernel?.id });
|
||||||
|
this._persistBindings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getBoundKernel(notebook: INotebookTextModel): INotebookKernel2 | undefined {
|
|
||||||
return this._kernelBindings.get(notebook.uri);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// below is some GLUE code to bridge managed kernels into the existing kernel pull
|
|
||||||
// world. this should eventually disappear
|
|
||||||
|
|
||||||
class KernelAdaptorBridge implements IWorkbenchContribution {
|
|
||||||
|
|
||||||
readonly dispose: () => void;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
@INotebookKernelService notebookKernelService: INotebookKernelService,
|
|
||||||
@INotebookService notebookService: INotebookService,
|
|
||||||
@INotebookEditorService notebookEditorService: INotebookEditorService
|
|
||||||
) {
|
|
||||||
|
|
||||||
const disposables = new DisposableStore();
|
|
||||||
|
|
||||||
const emitter = new Emitter<URI | undefined>();
|
|
||||||
const kernels = new Map<INotebookKernel2, IDisposable>();
|
|
||||||
|
|
||||||
disposables.add(notebookKernelService.onDidAddKernel(kernel => {
|
|
||||||
const reg = kernel.onDidChange(() => emitter.fire(undefined));
|
|
||||||
kernels.set(kernel, reg);
|
|
||||||
emitter.fire(undefined);
|
|
||||||
}));
|
|
||||||
|
|
||||||
disposables.add(notebookKernelService.onDidRemoveKernel(kernel => {
|
|
||||||
const reg = kernels.get(kernel);
|
|
||||||
if (reg) {
|
|
||||||
reg.dispose();
|
|
||||||
kernels.delete(kernel);
|
|
||||||
emitter.fire(undefined);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
// kernel -> provider
|
|
||||||
const registration = notebookService.registerNotebookKernelProvider({
|
|
||||||
onDidChangeKernels: emitter.event,
|
|
||||||
providerExtensionId: 'notAnExtension',
|
|
||||||
selector: { filenamePattern: '**/*' },
|
|
||||||
async provideKernels(uri: URI) {
|
|
||||||
const model = notebookService.getNotebookTextModel(uri);
|
|
||||||
if (!model) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
return notebookKernelService.getMatchingKernels(model);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// kernel binding
|
|
||||||
const editorListener = new Map<string, IDisposable>();
|
|
||||||
disposables.add(notebookEditorService.onDidAddNotebookEditor(e => {
|
|
||||||
const r1 = e.onDidChangeKernel(() => {
|
|
||||||
if (!e.viewModel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let kernel: INotebookKernel2 | undefined;
|
|
||||||
if (e.activeKernel) {
|
|
||||||
for (const candidate of kernels.keys()) {
|
|
||||||
if (e.activeKernel.friendlyId === candidate.id) {
|
|
||||||
kernel = candidate;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
notebookKernelService.updateNotebookKernelBinding(e.viewModel.notebookDocument, kernel);
|
|
||||||
});
|
|
||||||
editorListener.set(e.getId(), r1);
|
|
||||||
}));
|
|
||||||
disposables.add(notebookEditorService.onDidRemoveNotebookEditor(e => {
|
|
||||||
editorListener.get(e.getId())?.dispose();
|
|
||||||
editorListener.delete(e.getId());
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
this.dispose = () => {
|
|
||||||
dispose(editorListener.values());
|
|
||||||
disposables.dispose();
|
|
||||||
emitter.dispose();
|
|
||||||
registration.dispose();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Registry
|
|
||||||
.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
|
|
||||||
.registerWorkbenchContribution(KernelAdaptorBridge, LifecyclePhase.Ready);
|
|
||||||
|
|||||||
@@ -6,8 +6,6 @@
|
|||||||
import * as glob from 'vs/base/common/glob';
|
import * as glob from 'vs/base/common/glob';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import { getPixelRatio, getZoomLevel } from 'vs/base/browser/browser';
|
import { getPixelRatio, getZoomLevel } from 'vs/base/browser/browser';
|
||||||
import { flatten } from 'vs/base/common/arrays';
|
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
|
||||||
import { Emitter, Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
import { Iterable } from 'vs/base/common/iterator';
|
import { Iterable } from 'vs/base/common/iterator';
|
||||||
import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||||
@@ -24,10 +22,10 @@ import { NotebookExtensionDescription } from 'vs/workbench/api/common/extHost.pr
|
|||||||
import { Memento } from 'vs/workbench/common/memento';
|
import { Memento } from 'vs/workbench/common/memento';
|
||||||
import { INotebookEditorContribution, notebookMarkdownRendererExtensionPoint, notebookProviderExtensionPoint, notebookRendererExtensionPoint } from 'vs/workbench/contrib/notebook/browser/extensionPoint';
|
import { INotebookEditorContribution, notebookMarkdownRendererExtensionPoint, notebookProviderExtensionPoint, notebookRendererExtensionPoint } from 'vs/workbench/contrib/notebook/browser/extensionPoint';
|
||||||
import { NotebookEditorOptions, updateEditorTopPadding } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
import { NotebookEditorOptions, updateEditorTopPadding } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||||
import { NotebookKernelProviderAssociationRegistry, NotebookViewTypesExtensionRegistry, updateNotebookKernelProvideAssociationSchema } from 'vs/workbench/contrib/notebook/browser/notebookKernelAssociation';
|
import { NotebookViewTypesExtensionRegistry, updateNotebookKernelProvideAssociationSchema } from 'vs/workbench/contrib/notebook/browser/notebookKernelAssociation';
|
||||||
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
|
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
|
||||||
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
|
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
|
||||||
import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, BUILTIN_RENDERER_ID, CellUri, DisplayOrderKey, INotebookExclusiveDocumentFilter, INotebookKernel, INotebookKernelProvider, INotebookMarkdownRendererInfo, INotebookRendererInfo, INotebookTextModel, IOrderedMimeType, IOutputDto, mimeTypeIsAlwaysSecure, mimeTypeSupportedByCore, NotebookDataDto, notebookDocumentFilterMatch, NotebookEditorPriority, NotebookRendererMatch, NotebookTextDiffEditorPreview, RENDERER_NOT_AVAILABLE, sortMimeTypes, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, BUILTIN_RENDERER_ID, CellUri, DisplayOrderKey, INotebookExclusiveDocumentFilter, INotebookMarkdownRendererInfo, INotebookRendererInfo, INotebookTextModel, IOrderedMimeType, IOutputDto, mimeTypeIsAlwaysSecure, mimeTypeSupportedByCore, NotebookDataDto, NotebookEditorPriority, NotebookRendererMatch, NotebookTextDiffEditorPreview, RENDERER_NOT_AVAILABLE, sortMimeTypes, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||||
import { NotebookMarkdownRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookMarkdownRenderer';
|
import { NotebookMarkdownRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookMarkdownRenderer';
|
||||||
import { NotebookOutputRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookOutputRenderer';
|
import { NotebookOutputRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookOutputRenderer';
|
||||||
import { NotebookEditorDescriptor, NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider';
|
import { NotebookEditorDescriptor, NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider';
|
||||||
@@ -44,44 +42,6 @@ import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebo
|
|||||||
import { ContributedEditorPriority, priorityToRank } from 'vs/workbench/services/editor/common/editorOverrideService';
|
import { ContributedEditorPriority, priorityToRank } from 'vs/workbench/services/editor/common/editorOverrideService';
|
||||||
import { IEditorOverrideService } from 'vs/workbench/services/editor/browser/editorOverrideService';
|
import { IEditorOverrideService } from 'vs/workbench/services/editor/browser/editorOverrideService';
|
||||||
|
|
||||||
export class NotebookKernelProviderInfoStore {
|
|
||||||
private readonly _notebookKernelProviders: INotebookKernelProvider[] = [];
|
|
||||||
|
|
||||||
add(provider: INotebookKernelProvider) {
|
|
||||||
this._notebookKernelProviders.push(provider);
|
|
||||||
this._updateProviderExtensionsInfo();
|
|
||||||
|
|
||||||
return toDisposable(() => {
|
|
||||||
const idx = this._notebookKernelProviders.indexOf(provider);
|
|
||||||
if (idx >= 0) {
|
|
||||||
this._notebookKernelProviders.splice(idx, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._updateProviderExtensionsInfo();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
get(viewType: string, resource: URI) {
|
|
||||||
return this._notebookKernelProviders.filter(provider => notebookDocumentFilterMatch(provider.selector, viewType, resource));
|
|
||||||
}
|
|
||||||
|
|
||||||
getContributedKernelProviders() {
|
|
||||||
return [...this._notebookKernelProviders];
|
|
||||||
}
|
|
||||||
|
|
||||||
private _updateProviderExtensionsInfo() {
|
|
||||||
NotebookKernelProviderAssociationRegistry.extensionIds.length = 0;
|
|
||||||
NotebookKernelProviderAssociationRegistry.extensionDescriptions.length = 0;
|
|
||||||
|
|
||||||
this._notebookKernelProviders.forEach(provider => {
|
|
||||||
NotebookKernelProviderAssociationRegistry.extensionIds.push(provider.providerExtensionId);
|
|
||||||
NotebookKernelProviderAssociationRegistry.extensionDescriptions.push(provider.providerDescription || '');
|
|
||||||
});
|
|
||||||
|
|
||||||
updateNotebookKernelProvideAssociationSchema();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class NotebookProviderInfoStore extends Disposable {
|
export class NotebookProviderInfoStore extends Disposable {
|
||||||
|
|
||||||
private static readonly CUSTOM_EDITORS_STORAGE_ID = 'notebookEditors';
|
private static readonly CUSTOM_EDITORS_STORAGE_ID = 'notebookEditors';
|
||||||
@@ -338,7 +298,6 @@ export class NotebookService extends Disposable implements INotebookService, IEd
|
|||||||
private readonly _notebookProviderInfoStore: NotebookProviderInfoStore;
|
private readonly _notebookProviderInfoStore: NotebookProviderInfoStore;
|
||||||
private readonly _notebookRenderersInfoStore = this._instantiationService.createInstance(NotebookOutputRendererInfoStore);
|
private readonly _notebookRenderersInfoStore = this._instantiationService.createInstance(NotebookOutputRendererInfoStore);
|
||||||
private readonly _markdownRenderersInfos = new Set<INotebookMarkdownRendererInfo>();
|
private readonly _markdownRenderersInfos = new Set<INotebookMarkdownRendererInfo>();
|
||||||
private readonly _notebookKernelProviderInfoStore: NotebookKernelProviderInfoStore = new NotebookKernelProviderInfoStore();
|
|
||||||
private readonly _models = new ResourceMap<ModelData>();
|
private readonly _models = new ResourceMap<ModelData>();
|
||||||
|
|
||||||
private readonly _onDidAddNotebookDocument = this._register(new Emitter<NotebookTextModel>());
|
private readonly _onDidAddNotebookDocument = this._register(new Emitter<NotebookTextModel>());
|
||||||
@@ -577,36 +536,6 @@ export class NotebookService extends Disposable implements INotebookService, IEd
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
registerNotebookKernelProvider(provider: INotebookKernelProvider): IDisposable {
|
|
||||||
const d = this._notebookKernelProviderInfoStore.add(provider);
|
|
||||||
const kernelChangeEventListener = provider.onDidChangeKernels((e) => {
|
|
||||||
this._onDidChangeKernels.fire(e);
|
|
||||||
});
|
|
||||||
|
|
||||||
this._onDidChangeKernels.fire(undefined);
|
|
||||||
return toDisposable(() => {
|
|
||||||
kernelChangeEventListener.dispose();
|
|
||||||
d.dispose();
|
|
||||||
this._onDidChangeKernels.fire(undefined);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async getNotebookKernels(viewType: string, resource: URI, token: CancellationToken): Promise<INotebookKernel[]> {
|
|
||||||
const filteredProvider = this._notebookKernelProviderInfoStore.get(viewType, resource);
|
|
||||||
const result = new Array<INotebookKernel[]>(filteredProvider.length);
|
|
||||||
const promises = filteredProvider.map(async (provider, index) => {
|
|
||||||
const data = await provider.provideKernels(resource, token);
|
|
||||||
result[index] = data;
|
|
||||||
});
|
|
||||||
await Promise.all(promises);
|
|
||||||
return flatten(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getContributedNotebookKernelProviders(): Promise<INotebookKernelProvider[]> {
|
|
||||||
const kernelProviders = this._notebookKernelProviderInfoStore.getContributedKernelProviders();
|
|
||||||
return kernelProviders;
|
|
||||||
}
|
|
||||||
|
|
||||||
getRendererInfo(rendererId: string): INotebookRendererInfo | undefined {
|
getRendererInfo(rendererId: string): INotebookRendererInfo | undefined {
|
||||||
return this._notebookRenderersInfoStore.get(rendererId);
|
return this._notebookRenderersInfoStore.get(rendererId);
|
||||||
}
|
}
|
||||||
@@ -739,22 +668,6 @@ export class NotebookService extends Disposable implements INotebookService, IEd
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- data provider IPC (deprecated)
|
|
||||||
|
|
||||||
async resolveNotebookEditor(viewType: string, uri: URI, editorId: string): Promise<void> {
|
|
||||||
const entry = this._notebookProviders.get(viewType);
|
|
||||||
if (entry instanceof ComplexNotebookProviderInfo) {
|
|
||||||
entry.controller.resolveNotebookEditor(viewType, uri, editorId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onDidReceiveMessage(viewType: string, editorId: string, rendererType: string | undefined, message: any): void {
|
|
||||||
const provider = this._notebookProviders.get(viewType);
|
|
||||||
if (provider instanceof ComplexNotebookProviderInfo) {
|
|
||||||
return provider.controller.onDidReceiveMessage(editorId, rendererType, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- copy & paste
|
// --- copy & paste
|
||||||
|
|
||||||
setToCopy(items: NotebookCellTextModel[], isCopy: boolean) {
|
setToCopy(items: NotebookCellTextModel[], isCopy: boolean) {
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ export class CellEditorStatusBar extends Disposable {
|
|||||||
private readonly rightContributedItemsContainer: HTMLElement;
|
private readonly rightContributedItemsContainer: HTMLElement;
|
||||||
private readonly itemsDisposable: DisposableStore;
|
private readonly itemsDisposable: DisposableStore;
|
||||||
|
|
||||||
|
private items: CellStatusBarItem[] = [];
|
||||||
|
private width: number = 0;
|
||||||
|
|
||||||
private currentContext: INotebookCellActionContext | undefined;
|
private currentContext: INotebookCellActionContext | undefined;
|
||||||
protected readonly _onDidClick: Emitter<IClickTarget> = this._register(new Emitter<IClickTarget>());
|
protected readonly _onDidClick: Emitter<IClickTarget> = this._register(new Emitter<IClickTarget>());
|
||||||
readonly onDidClick: Event<IClickTarget> = this._onDidClick.event;
|
readonly onDidClick: Event<IClickTarget> = this._onDidClick.event;
|
||||||
@@ -103,7 +106,15 @@ export class CellEditorStatusBar extends Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
layout(width: number): void {
|
layout(width: number): void {
|
||||||
|
this.width = width;
|
||||||
this.statusBarContainer.style.width = `${width}px`;
|
this.statusBarContainer.style.width = `${width}px`;
|
||||||
|
|
||||||
|
const maxItemWidth = this.getMaxItemWidth();
|
||||||
|
this.items.forEach(item => item.maxWidth = maxItemWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getMaxItemWidth() {
|
||||||
|
return this.width / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async updateStatusBarItems() {
|
private async updateStatusBarItems() {
|
||||||
@@ -130,14 +141,15 @@ export class CellEditorStatusBar extends Disposable {
|
|||||||
items.sort((itemA, itemB) => {
|
items.sort((itemA, itemB) => {
|
||||||
return (itemB.priority ?? 0) - (itemA.priority ?? 0);
|
return (itemB.priority ?? 0) - (itemA.priority ?? 0);
|
||||||
});
|
});
|
||||||
items.forEach(item => {
|
|
||||||
const itemView = this.itemsDisposable.add(this.instantiationService.createInstance(CellStatusBarItem, this.currentContext!, item));
|
const maxItemWidth = this.getMaxItemWidth();
|
||||||
if (item.alignment === CellStatusbarAlignment.Left) {
|
const leftItems = items.filter(item => item.alignment === CellStatusbarAlignment.Left)
|
||||||
this.leftContributedItemsContainer.appendChild(itemView.container);
|
.map(item => this.itemsDisposable.add(this.instantiationService.createInstance(CellStatusBarItem, this.currentContext!, item, maxItemWidth)));
|
||||||
} else {
|
const rightItems = items.filter(item => item.alignment === CellStatusbarAlignment.Right).reverse()
|
||||||
this.rightContributedItemsContainer.appendChild(itemView.container);
|
.map(item => this.itemsDisposable.add(this.instantiationService.createInstance(CellStatusBarItem, this.currentContext!, item, maxItemWidth)));
|
||||||
}
|
leftItems.forEach(itemView => this.leftContributedItemsContainer.appendChild(itemView.container));
|
||||||
});
|
rightItems.forEach(itemView => this.rightContributedItemsContainer.appendChild(itemView.container));
|
||||||
|
this.items = [...leftItems, ...rightItems];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,15 +157,20 @@ class CellStatusBarItem extends Disposable {
|
|||||||
|
|
||||||
readonly container = $('.cell-status-item');
|
readonly container = $('.cell-status-item');
|
||||||
|
|
||||||
|
set maxWidth(v: number) {
|
||||||
|
this.container.style.maxWidth = v + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _context: INotebookCellActionContext,
|
private readonly _context: INotebookCellActionContext,
|
||||||
private readonly _itemModel: INotebookCellStatusBarItem,
|
private readonly _itemModel: INotebookCellStatusBarItem,
|
||||||
|
maxWidth: number | undefined,
|
||||||
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
||||||
@ICommandService private readonly commandService: ICommandService,
|
@ICommandService private readonly commandService: ICommandService,
|
||||||
@INotificationService private readonly notificationService: INotificationService
|
@INotificationService private readonly notificationService: INotificationService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
new SimpleIconLabel(this.container).text = this._itemModel.text;
|
new SimpleIconLabel(this.container).text = this._itemModel.text.replace(/\n/g, ' ');
|
||||||
|
|
||||||
if (this._itemModel.opacity) {
|
if (this._itemModel.opacity) {
|
||||||
this.container.style.opacity = this._itemModel.opacity;
|
this.container.style.opacity = this._itemModel.opacity;
|
||||||
@@ -163,6 +180,10 @@ class CellStatusBarItem extends Disposable {
|
|||||||
this.container.classList.add('cell-status-item-show-when-active');
|
this.container.classList.add('cell-status-item-show-when-active');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof maxWidth === 'number') {
|
||||||
|
this.maxWidth = maxWidth;
|
||||||
|
}
|
||||||
|
|
||||||
let ariaLabel: string;
|
let ariaLabel: string;
|
||||||
let role: string | undefined;
|
let role: string | undefined;
|
||||||
if (this._itemModel.accessibilityInformation) {
|
if (this._itemModel.accessibilityInformation) {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { hash } from 'vs/base/common/hash';
|
|||||||
import { PieceTreeTextBuffer } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer';
|
import { PieceTreeTextBuffer } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer';
|
||||||
import { NotebookCellOutputTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellOutputTextModel';
|
import { NotebookCellOutputTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellOutputTextModel';
|
||||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||||
|
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||||
|
|
||||||
export class NotebookCellTextModel extends Disposable implements ICell {
|
export class NotebookCellTextModel extends Disposable implements ICell {
|
||||||
private _onDidChangeOutputs = new Emitter<NotebookCellOutputsSplice[]>();
|
private _onDidChangeOutputs = new Emitter<NotebookCellOutputsSplice[]>();
|
||||||
@@ -88,7 +89,9 @@ export class NotebookCellTextModel extends Disposable implements ICell {
|
|||||||
|
|
||||||
this._register(this._textBuffer.onDidChangeContent(() => {
|
this._register(this._textBuffer.onDidChangeContent(() => {
|
||||||
this._hash = null;
|
this._hash = null;
|
||||||
this._onDidChangeContent.fire();
|
if (!this._textModel) {
|
||||||
|
this._onDidChangeContent.fire();
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return this._textBuffer;
|
return this._textBuffer;
|
||||||
@@ -96,13 +99,19 @@ export class NotebookCellTextModel extends Disposable implements ICell {
|
|||||||
|
|
||||||
private _hash: number | null = null;
|
private _hash: number | null = null;
|
||||||
|
|
||||||
|
private _versionId: number = 1;
|
||||||
|
private _alternativeId: number = 1;
|
||||||
|
get alternativeId(): number {
|
||||||
|
return this._alternativeId;
|
||||||
|
}
|
||||||
|
|
||||||
private _textModelDisposables = new DisposableStore();
|
private _textModelDisposables = new DisposableStore();
|
||||||
private _textModel: model.ITextModel | undefined = undefined;
|
private _textModel: TextModel | undefined = undefined;
|
||||||
get textModel(): model.ITextModel | undefined {
|
get textModel(): TextModel | undefined {
|
||||||
return this._textModel;
|
return this._textModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
set textModel(m: model.ITextModel | undefined) {
|
set textModel(m: TextModel | undefined) {
|
||||||
if (this._textModel === m) {
|
if (this._textModel === m) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -118,6 +127,16 @@ export class NotebookCellTextModel extends Disposable implements ICell {
|
|||||||
this.language = e.newLanguage;
|
this.language = e.newLanguage;
|
||||||
}));
|
}));
|
||||||
this._textModelDisposables.add(this._textModel.onWillDispose(() => this.textModel = undefined));
|
this._textModelDisposables.add(this._textModel.onWillDispose(() => this.textModel = undefined));
|
||||||
|
this._textModelDisposables.add(this._textModel.onDidChangeContent(() => {
|
||||||
|
if (this._textModel) {
|
||||||
|
this._versionId = this._textModel.getVersionId();
|
||||||
|
this._alternativeId = this._textModel.getAlternativeVersionId();
|
||||||
|
}
|
||||||
|
this._onDidChangeContent.fire();
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._textModel._overwriteVersionId(this._versionId);
|
||||||
|
this._textModel._overwriteAlternativeVersionId(this._versionId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { Schemas } from 'vs/base/common/network';
|
|||||||
import { isEqual } from 'vs/base/common/resources';
|
import { isEqual } from 'vs/base/common/resources';
|
||||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||||
import { ITextModel } from 'vs/editor/common/model';
|
import { ITextModel } from 'vs/editor/common/model';
|
||||||
|
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||||
|
|
||||||
|
|
||||||
class StackOperation implements IWorkspaceUndoRedoElement {
|
class StackOperation implements IWorkspaceUndoRedoElement {
|
||||||
@@ -26,17 +27,17 @@ class StackOperation implements IWorkspaceUndoRedoElement {
|
|||||||
private _operations: IUndoRedoElement[] = [];
|
private _operations: IUndoRedoElement[] = [];
|
||||||
private _beginSelectionState: ISelectionState | undefined = undefined;
|
private _beginSelectionState: ISelectionState | undefined = undefined;
|
||||||
private _resultSelectionState: ISelectionState | undefined = undefined;
|
private _resultSelectionState: ISelectionState | undefined = undefined;
|
||||||
private _beginAlternativeVersionId: number;
|
private _beginAlternativeVersionId: string;
|
||||||
private _resultAlternativeVersionId: number;
|
private _resultAlternativeVersionId: string;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly resource: URI,
|
readonly resource: URI,
|
||||||
readonly label: string,
|
readonly label: string,
|
||||||
readonly undoRedoGroup: UndoRedoGroup | undefined,
|
readonly undoRedoGroup: UndoRedoGroup | undefined,
|
||||||
private _delayedEmitter: DelayedEmitter,
|
private _delayedEmitter: DelayedEmitter,
|
||||||
private _postUndoRedo: (alternativeVersionId: number) => void,
|
private _postUndoRedo: (alternativeVersionId: string) => void,
|
||||||
selectionState: ISelectionState | undefined,
|
selectionState: ISelectionState | undefined,
|
||||||
beginAlternativeVersionId: number
|
beginAlternativeVersionId: string
|
||||||
) {
|
) {
|
||||||
this.type = UndoRedoElementType.Workspace;
|
this.type = UndoRedoElementType.Workspace;
|
||||||
this._beginSelectionState = selectionState;
|
this._beginSelectionState = selectionState;
|
||||||
@@ -51,7 +52,7 @@ class StackOperation implements IWorkspaceUndoRedoElement {
|
|||||||
return this._operations.length === 0;
|
return this._operations.length === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pushEndState(alternativeVersionId: number, selectionState: ISelectionState | undefined) {
|
pushEndState(alternativeVersionId: string, selectionState: ISelectionState | undefined) {
|
||||||
this._resultAlternativeVersionId = alternativeVersionId;
|
this._resultAlternativeVersionId = alternativeVersionId;
|
||||||
this._resultSelectionState = selectionState;
|
this._resultSelectionState = selectionState;
|
||||||
}
|
}
|
||||||
@@ -89,11 +90,11 @@ export class NotebookOperationManager {
|
|||||||
private _undoService: IUndoRedoService,
|
private _undoService: IUndoRedoService,
|
||||||
private _resource: URI,
|
private _resource: URI,
|
||||||
private _delayedEmitter: DelayedEmitter,
|
private _delayedEmitter: DelayedEmitter,
|
||||||
private _postUndoRedo: (alternativeVersionId: number) => void
|
private _postUndoRedo: (alternativeVersionId: string) => void
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pushStackElement(label: string, selectionState: ISelectionState | undefined, undoRedoGroup: UndoRedoGroup | undefined, alternativeVersionId: number) {
|
pushStackElement(label: string, selectionState: ISelectionState | undefined, undoRedoGroup: UndoRedoGroup | undefined, alternativeVersionId: string) {
|
||||||
if (this._pendingStackOperation) {
|
if (this._pendingStackOperation) {
|
||||||
this._pendingStackOperation.pushEndState(alternativeVersionId, selectionState);
|
this._pendingStackOperation.pushEndState(alternativeVersionId, selectionState);
|
||||||
if (!this._pendingStackOperation.isEmpty) {
|
if (!this._pendingStackOperation.isEmpty) {
|
||||||
@@ -199,7 +200,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||||||
/**
|
/**
|
||||||
* Unlike, versionId, this can go down (via undo) or go to previous values (via redo)
|
* Unlike, versionId, this can go down (via undo) or go to previous values (via redo)
|
||||||
*/
|
*/
|
||||||
private _alternativeVersionId: number = 0;
|
private _alternativeVersionId: string = '1';
|
||||||
private _operationManager: NotebookOperationManager;
|
private _operationManager: NotebookOperationManager;
|
||||||
private _eventEmitter: DelayedEmitter;
|
private _eventEmitter: DelayedEmitter;
|
||||||
|
|
||||||
@@ -215,7 +216,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||||||
return this._versionId;
|
return this._versionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
get alternativeVersionId(): number {
|
get alternativeVersionId(): string {
|
||||||
return this._alternativeVersionId;
|
return this._alternativeVersionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,7 +236,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||||||
this._initialize(cells);
|
this._initialize(cells);
|
||||||
|
|
||||||
const maybeUpdateCellTextModel = (textModel: ITextModel) => {
|
const maybeUpdateCellTextModel = (textModel: ITextModel) => {
|
||||||
if (textModel.uri.scheme === Schemas.vscodeNotebookCell) {
|
if (textModel.uri.scheme === Schemas.vscodeNotebookCell && textModel instanceof TextModel) {
|
||||||
const cellUri = CellUri.parse(textModel.uri);
|
const cellUri = CellUri.parse(textModel.uri);
|
||||||
if (cellUri && isEqual(cellUri.notebook, this.uri)) {
|
if (cellUri && isEqual(cellUri.notebook, this.uri)) {
|
||||||
const cellIdx = this._getCellIndexByHandle(cellUri.handle);
|
const cellIdx = this._getCellIndexByHandle(cellUri.handle);
|
||||||
@@ -259,7 +260,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||||||
this._undoService,
|
this._undoService,
|
||||||
uri,
|
uri,
|
||||||
this._eventEmitter,
|
this._eventEmitter,
|
||||||
(alternativeVersionId: number) => {
|
(alternativeVersionId: string) => {
|
||||||
this._increaseVersionId();
|
this._increaseVersionId();
|
||||||
this._overwriteAlternativeVersionId(alternativeVersionId);
|
this._overwriteAlternativeVersionId(alternativeVersionId);
|
||||||
}
|
}
|
||||||
@@ -287,6 +288,11 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._cells.splice(0, 0, ...mainCells);
|
this._cells.splice(0, 0, ...mainCells);
|
||||||
|
this._alternativeVersionId = this._generateAlternativeId();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _generateAlternativeId() {
|
||||||
|
return this.cells.map(cell => cell.handle + ',' + cell.alternativeId).join(';');
|
||||||
}
|
}
|
||||||
|
|
||||||
override dispose() {
|
override dispose() {
|
||||||
@@ -327,6 +333,23 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||||||
this._eventEmitter.beginDeferredEmit();
|
this._eventEmitter.beginDeferredEmit();
|
||||||
this.pushStackElement('edit', beginSelectionState, undoRedoGroup);
|
this.pushStackElement('edit', beginSelectionState, undoRedoGroup);
|
||||||
|
|
||||||
|
try {
|
||||||
|
this._doApplyEdits(rawEdits, synchronous, computeUndoRedo);
|
||||||
|
return true;
|
||||||
|
} finally {
|
||||||
|
// Update selection and versionId after applying edits.
|
||||||
|
const endSelections = endSelectionsComputer();
|
||||||
|
this._increaseVersionId();
|
||||||
|
|
||||||
|
// Finalize undo element
|
||||||
|
this.pushStackElement('edit', endSelections, undefined);
|
||||||
|
|
||||||
|
// Broadcast changes
|
||||||
|
this._eventEmitter.endDeferredEmit(endSelections);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _doApplyEdits(rawEdits: ICellEditOperation[], synchronous: boolean, computeUndoRedo: boolean = true): void {
|
||||||
const edits = rawEdits.map((edit, index) => {
|
const edits = rawEdits.map((edit, index) => {
|
||||||
let cellIndex: number = -1;
|
let cellIndex: number = -1;
|
||||||
if ('index' in edit) {
|
if ('index' in edit) {
|
||||||
@@ -368,7 +391,6 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||||||
this._replaceCells(edit.index, edit.count, edit.cells, synchronous, computeUndoRedo);
|
this._replaceCells(edit.index, edit.count, edit.cells, synchronous, computeUndoRedo);
|
||||||
break;
|
break;
|
||||||
case CellEditType.Output:
|
case CellEditType.Output:
|
||||||
//TODO@jrieken,@rebornix no event, no undo stop (?)
|
|
||||||
this._assertIndex(cellIndex);
|
this._assertIndex(cellIndex);
|
||||||
const cell = this._cells[cellIndex];
|
const cell = this._cells[cellIndex];
|
||||||
if (edit.append) {
|
if (edit.append) {
|
||||||
@@ -409,19 +431,6 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update selection and versionId after applying edits.
|
|
||||||
*/
|
|
||||||
const endSelections = endSelectionsComputer();
|
|
||||||
this._increaseVersionId();
|
|
||||||
|
|
||||||
// Finalize undo element
|
|
||||||
this.pushStackElement('edit', endSelections, undefined);
|
|
||||||
|
|
||||||
// Broadcast changes
|
|
||||||
this._eventEmitter.endDeferredEmit(endSelections);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _replaceCells(index: number, count: number, cellDtos: ICellDto2[], synchronous: boolean, computeUndoRedo: boolean): void {
|
private _replaceCells(index: number, count: number, cellDtos: ICellDto2[], synchronous: boolean, computeUndoRedo: boolean): void {
|
||||||
@@ -450,7 +459,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||||||
this._modeService
|
this._modeService
|
||||||
);
|
);
|
||||||
const textModel = this._modelService.getModel(cellUri);
|
const textModel = this._modelService.getModel(cellUri);
|
||||||
if (textModel) {
|
if (textModel && textModel instanceof TextModel) {
|
||||||
cell.textModel = textModel;
|
cell.textModel = textModel;
|
||||||
cell.language = cellDto.language;
|
cell.language = cellDto.language;
|
||||||
}
|
}
|
||||||
@@ -495,10 +504,10 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||||||
|
|
||||||
private _increaseVersionId(): void {
|
private _increaseVersionId(): void {
|
||||||
this._versionId = this._versionId + 1;
|
this._versionId = this._versionId + 1;
|
||||||
this._alternativeVersionId = this.versionId;
|
this._alternativeVersionId = this._generateAlternativeId();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _overwriteAlternativeVersionId(newAlternativeVersionId: number): void {
|
private _overwriteAlternativeVersionId(newAlternativeVersionId: string): void {
|
||||||
this._alternativeVersionId = newAlternativeVersionId;
|
this._alternativeVersionId = newAlternativeVersionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -765,37 +765,36 @@ export function notebookDocumentFilterMatch(filter: INotebookDocumentFilter, vie
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface INotebookKernelChangeEvent {
|
||||||
|
label?: true;
|
||||||
|
description?: true;
|
||||||
|
detail?: true;
|
||||||
|
isPreferred?: true;
|
||||||
|
supportedLanguages?: true;
|
||||||
|
hasExecutionOrder?: true;
|
||||||
|
}
|
||||||
|
|
||||||
export interface INotebookKernel {
|
export interface INotebookKernel {
|
||||||
|
|
||||||
/** @deprecated */
|
readonly id: string;
|
||||||
providerHandle?: number;
|
readonly selector: NotebookSelector;
|
||||||
/** @deprecated */
|
readonly onDidChange: Event<Readonly<INotebookKernelChangeEvent>>;
|
||||||
resolve(uri: URI, editorId: string, token: CancellationToken): Promise<void>;
|
readonly extension: ExtensionIdentifier;
|
||||||
|
|
||||||
|
readonly localResourceRoot: URI;
|
||||||
|
readonly preloadUris: URI[];
|
||||||
|
readonly preloadProvides: string[];
|
||||||
|
|
||||||
id?: string;
|
|
||||||
friendlyId: string;
|
|
||||||
label: string;
|
label: string;
|
||||||
extension: ExtensionIdentifier;
|
|
||||||
localResourceRoot: URI;
|
|
||||||
description?: string;
|
description?: string;
|
||||||
detail?: string;
|
detail?: string;
|
||||||
isPreferred?: boolean;
|
isPreferred?: boolean;
|
||||||
preloadUris: URI[];
|
supportedLanguages: string[]
|
||||||
preloadProvides: string[];
|
|
||||||
supportedLanguages?: string[]
|
|
||||||
implementsInterrupt?: boolean;
|
implementsInterrupt?: boolean;
|
||||||
implementsExecutionOrder?: boolean;
|
implementsExecutionOrder?: boolean;
|
||||||
|
|
||||||
executeNotebookCellsRequest(uri: URI, ranges: ICellRange[]): Promise<void>;
|
executeNotebookCellsRequest(uri: URI, cellHandles: number[]): Promise<void>;
|
||||||
cancelNotebookCellExecution(uri: URI, ranges: ICellRange[]): Promise<void>;
|
cancelNotebookCellExecution(uri: URI, cellHandles: number[]): Promise<void>;
|
||||||
}
|
|
||||||
|
|
||||||
export interface INotebookKernelProvider {
|
|
||||||
providerExtensionId: string;
|
|
||||||
providerDescription?: string;
|
|
||||||
selector: INotebookDocumentFilter;
|
|
||||||
onDidChangeKernels: Event<URI | undefined>;
|
|
||||||
provideKernels(uri: URI, token: CancellationToken): Promise<INotebookKernel[]>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface INotebookCellStatusBarItemProvider {
|
export interface INotebookCellStatusBarItemProvider {
|
||||||
|
|||||||
+11
-21
@@ -16,12 +16,10 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
|
|||||||
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
|
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
|
||||||
import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverService';
|
import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverService';
|
||||||
import { ResourceMap } from 'vs/base/common/map';
|
import { ResourceMap } from 'vs/base/common/map';
|
||||||
import { NO_TYPE_ID } from 'vs/workbench/services/workingCopy/common/workingCopy';
|
|
||||||
|
|
||||||
|
|
||||||
class NotebookModelReferenceCollection extends ReferenceCollection<Promise<IResolvedNotebookEditorModel>> {
|
class NotebookModelReferenceCollection extends ReferenceCollection<Promise<IResolvedNotebookEditorModel>> {
|
||||||
|
|
||||||
private readonly _workingCopyManager: IFileWorkingCopyManager<NotebookFileWorkingCopyModel>;
|
private readonly _workingCopyManagers = new Map<string, IFileWorkingCopyManager<NotebookFileWorkingCopyModel>>();
|
||||||
private readonly _modelListener = new Map<IResolvedNotebookEditorModel, IDisposable>();
|
private readonly _modelListener = new Map<IResolvedNotebookEditorModel, IDisposable>();
|
||||||
|
|
||||||
private readonly _onDidSaveNotebook = new Emitter<URI>();
|
private readonly _onDidSaveNotebook = new Emitter<URI>();
|
||||||
@@ -38,29 +36,13 @@ class NotebookModelReferenceCollection extends ReferenceCollection<Promise<IReso
|
|||||||
@ILogService private readonly _logService: ILogService,
|
@ILogService private readonly _logService: ILogService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this._workingCopyManager = <any>_instantiationService.createInstance(
|
|
||||||
FileWorkingCopyManager,
|
|
||||||
// TODO@jrieken TODO@rebornix consider to enable a `typeId` that is
|
|
||||||
// specific for custom editors. Using a distinct `typeId` allows the
|
|
||||||
// working copy to have any resource (including file based resources)
|
|
||||||
// even if other working copies exist with the same resource.
|
|
||||||
//
|
|
||||||
// IMPORTANT: changing the `typeId` has an impact on backups for this
|
|
||||||
// working copy. Any value that is not the empty string will be used
|
|
||||||
// as seed to the backup. Only change the `typeId` if you have implemented
|
|
||||||
// a fallback solution to resolve any existing backups that do not have
|
|
||||||
// this seed.
|
|
||||||
NO_TYPE_ID,
|
|
||||||
new NotebookFileWorkingCopyModelFactory(_notebookService)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose(): void {
|
dispose(): void {
|
||||||
this._onDidSaveNotebook.dispose();
|
this._onDidSaveNotebook.dispose();
|
||||||
this._onDidChangeDirty.dispose();
|
this._onDidChangeDirty.dispose();
|
||||||
dispose(this._modelListener.values());
|
dispose(this._modelListener.values());
|
||||||
this._workingCopyManager.dispose();
|
dispose(this._workingCopyManagers.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
isDirty(resource: URI): boolean {
|
isDirty(resource: URI): boolean {
|
||||||
@@ -78,7 +60,15 @@ class NotebookModelReferenceCollection extends ReferenceCollection<Promise<IReso
|
|||||||
result = await model.load();
|
result = await model.load();
|
||||||
|
|
||||||
} else if (info instanceof SimpleNotebookProviderInfo) {
|
} else if (info instanceof SimpleNotebookProviderInfo) {
|
||||||
const model = this._instantiationService.createInstance(SimpleNotebookEditorModel, uri, viewType, this._workingCopyManager);
|
let workingCopyManager = this._workingCopyManagers.get(viewType);
|
||||||
|
if (!workingCopyManager) {
|
||||||
|
workingCopyManager = <IFileWorkingCopyManager<NotebookFileWorkingCopyModel>><any>this._instantiationService.createInstance(
|
||||||
|
FileWorkingCopyManager,
|
||||||
|
viewType,
|
||||||
|
new NotebookFileWorkingCopyModelFactory(this._notebookService)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const model = this._instantiationService.createInstance(SimpleNotebookEditorModel, uri, viewType, workingCopyManager);
|
||||||
result = await model.load();
|
result = await model.load();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -6,52 +6,34 @@
|
|||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
|
||||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { INotebookKernel, INotebookTextModel } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
import { INotebookKernel, INotebookTextModel } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||||
import { NotebookSelector } from 'vs/workbench/contrib/notebook/common/notebookSelector';
|
|
||||||
|
|
||||||
export interface INotebookKernel2ChangeEvent {
|
|
||||||
label?: true;
|
|
||||||
description?: true;
|
|
||||||
detail?: true;
|
|
||||||
isPreferred?: true;
|
|
||||||
supportedLanguages?: true;
|
|
||||||
hasExecutionOrder?: true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface INotebookKernel2 extends INotebookKernel {
|
|
||||||
|
|
||||||
readonly id: string;
|
|
||||||
readonly selector: NotebookSelector
|
|
||||||
readonly extension: ExtensionIdentifier;
|
|
||||||
|
|
||||||
readonly onDidChange: Event<INotebookKernel2ChangeEvent>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface INotebookKernelBindEvent {
|
export interface INotebookKernelBindEvent {
|
||||||
notebook: URI;
|
notebook: URI;
|
||||||
oldKernel: INotebookKernel2 | undefined;
|
oldKernel: string | undefined;
|
||||||
newKernel: INotebookKernel2 | undefined;
|
newKernel: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface INotebookTextModelLike { uri: URI; viewType: string; }
|
||||||
|
|
||||||
export const INotebookKernelService = createDecorator<INotebookKernelService>('INotebookKernelService');
|
export const INotebookKernelService = createDecorator<INotebookKernelService>('INotebookKernelService');
|
||||||
|
|
||||||
export interface INotebookKernelService {
|
export interface INotebookKernelService {
|
||||||
_serviceBrand: undefined;
|
_serviceBrand: undefined;
|
||||||
|
|
||||||
readonly onDidAddKernel: Event<INotebookKernel2>;
|
readonly onDidAddKernel: Event<INotebookKernel>;
|
||||||
readonly onDidRemoveKernel: Event<INotebookKernel2>;
|
readonly onDidRemoveKernel: Event<INotebookKernel>;
|
||||||
readonly onDidChangeNotebookKernelBinding: Event<INotebookKernelBindEvent>;
|
readonly onDidChangeNotebookKernelBinding: Event<INotebookKernelBindEvent>;
|
||||||
|
|
||||||
registerKernel(kernel: INotebookKernel2): IDisposable;
|
registerKernel(kernel: INotebookKernel): IDisposable;
|
||||||
getMatchingKernels(notebook: INotebookTextModel): INotebookKernel2[];
|
|
||||||
|
getNotebookKernels(notebook: INotebookTextModelLike): { bound: INotebookKernel | undefined, all: INotebookKernel[] }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind a notebook document to a kernel. A notebook is only bound to one kernel
|
* Bind a notebook document to a kernel. A notebook is only bound to one kernel
|
||||||
* but a kernel can be bound to many notebooks (depending on its configuration)
|
* but a kernel can be bound to many notebooks (depending on its configuration)
|
||||||
*/
|
*/
|
||||||
updateNotebookKernelBinding(notebook: INotebookTextModel, kernel: INotebookKernel2 | undefined): void;
|
updateNotebookKernelBinding(notebook: INotebookTextModel, kernel: INotebookKernel | undefined): void;
|
||||||
|
|
||||||
getBoundKernel(notebook: INotebookTextModel): INotebookKernel2 | undefined
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { URI } from 'vs/base/common/uri';
|
|||||||
import { NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider';
|
import { NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider';
|
||||||
import { NotebookExtensionDescription } from 'vs/workbench/api/common/extHost.protocol';
|
import { NotebookExtensionDescription } from 'vs/workbench/api/common/extHost.protocol';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { INotebookRendererInfo, INotebookKernelProvider, INotebookKernel, NotebookDataDto, TransientOptions, INotebookExclusiveDocumentFilter, IOrderedMimeType, IOutputDto, INotebookMarkdownRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
import { INotebookRendererInfo, NotebookDataDto, TransientOptions, INotebookExclusiveDocumentFilter, IOrderedMimeType, IOutputDto, INotebookMarkdownRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||||
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
|
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
|
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
|
||||||
@@ -22,8 +22,6 @@ export const INotebookService = createDecorator<INotebookService>('notebookServi
|
|||||||
export interface IMainNotebookController {
|
export interface IMainNotebookController {
|
||||||
viewOptions?: { displayName: string; filenamePattern: (string | IRelativePattern | INotebookExclusiveDocumentFilter)[]; exclusive: boolean; };
|
viewOptions?: { displayName: string; filenamePattern: (string | IRelativePattern | INotebookExclusiveDocumentFilter)[]; exclusive: boolean; };
|
||||||
options: TransientOptions;
|
options: TransientOptions;
|
||||||
resolveNotebookEditor(viewType: string, uri: URI, editorId: string): Promise<void>;
|
|
||||||
onDidReceiveMessage(editorId: string, rendererType: string | undefined, message: any): void;
|
|
||||||
|
|
||||||
open(uri: URI, backupId: string | undefined, untitledDocumentData: VSBuffer | undefined, token: CancellationToken): Promise<{ data: NotebookDataDto, transientOptions: TransientOptions; }>;
|
open(uri: URI, backupId: string | undefined, untitledDocumentData: VSBuffer | undefined, token: CancellationToken): Promise<{ data: NotebookDataDto, transientOptions: TransientOptions; }>;
|
||||||
save(uri: URI, token: CancellationToken): Promise<boolean>;
|
save(uri: URI, token: CancellationToken): Promise<boolean>;
|
||||||
@@ -74,9 +72,6 @@ export interface INotebookService {
|
|||||||
|
|
||||||
getMimeTypeInfo(textModel: NotebookTextModel, kernelProvides: readonly string[] | undefined, output: IOutputDto): readonly IOrderedMimeType[];
|
getMimeTypeInfo(textModel: NotebookTextModel, kernelProvides: readonly string[] | undefined, output: IOutputDto): readonly IOrderedMimeType[];
|
||||||
|
|
||||||
registerNotebookKernelProvider(provider: INotebookKernelProvider): IDisposable;
|
|
||||||
getNotebookKernels(viewType: string, resource: URI, token: CancellationToken): Promise<INotebookKernel[]>;
|
|
||||||
getContributedNotebookKernelProviders(): Promise<INotebookKernelProvider[]>;
|
|
||||||
getRendererInfo(id: string): INotebookRendererInfo | undefined;
|
getRendererInfo(id: string): INotebookRendererInfo | undefined;
|
||||||
getMarkdownRendererInfo(): INotebookMarkdownRendererInfo[];
|
getMarkdownRendererInfo(): INotebookMarkdownRendererInfo[];
|
||||||
|
|
||||||
@@ -92,11 +87,6 @@ export interface INotebookService {
|
|||||||
getContributedNotebookProvider(viewType: string): NotebookProviderInfo | undefined;
|
getContributedNotebookProvider(viewType: string): NotebookProviderInfo | undefined;
|
||||||
getNotebookProviderResourceRoots(): URI[];
|
getNotebookProviderResourceRoots(): URI[];
|
||||||
|
|
||||||
onDidReceiveMessage(viewType: string, editorId: string, rendererType: string | undefined, message: unknown): void;
|
|
||||||
setToCopy(items: NotebookCellTextModel[], isCopy: boolean): void;
|
setToCopy(items: NotebookCellTextModel[], isCopy: boolean): void;
|
||||||
getToCopy(): { items: NotebookCellTextModel[], isCopy: boolean; } | undefined;
|
getToCopy(): { items: NotebookCellTextModel[], isCopy: boolean; } | undefined;
|
||||||
|
|
||||||
// editor events
|
|
||||||
|
|
||||||
resolveNotebookEditor(viewType: string, uri: URI, editorId: string): Promise<void>;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,49 +5,41 @@
|
|||||||
|
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import * as sinon from 'sinon';
|
import * as sinon from 'sinon';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { assertThrowsAsync } from 'vs/base/test/common/utils';
|
import { assertThrowsAsync } from 'vs/base/test/common/utils';
|
||||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
|
||||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||||
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
|
|
||||||
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
|
||||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
|
||||||
import { NOTEBOOK_KERNEL_COUNT } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
|
||||||
import { NotebookEditorKernelManager } from 'vs/workbench/contrib/notebook/browser/notebookEditorKernelManager';
|
import { NotebookEditorKernelManager } from 'vs/workbench/contrib/notebook/browser/notebookEditorKernelManager';
|
||||||
import { NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
|
import { NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
|
||||||
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
|
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
|
||||||
import { CellKind, ICellRange, INotebookKernel, IOutputDto, NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
import { CellKind, INotebookKernel, IOutputDto, NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||||
import { setupInstantiationService, withTestNotebook as _withTestNotebook } from 'vs/workbench/contrib/notebook/test/testNotebookEditor';
|
import { setupInstantiationService, withTestNotebook as _withTestNotebook } from 'vs/workbench/contrib/notebook/test/testNotebookEditor';
|
||||||
import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
|
import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||||
import { TestQuickInputService } from 'vs/workbench/test/browser/workbenchTestServices';
|
import { Event } from 'vs/base/common/event';
|
||||||
|
import { INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
|
||||||
|
import { NotebookKernelService } from 'vs/workbench/contrib/notebook/browser/notebookKernelServiceImpl';
|
||||||
|
import { NullLogService } from 'vs/platform/log/common/log';
|
||||||
|
|
||||||
suite('NotebookEditorKernelManager', () => {
|
suite('NotebookEditorKernelManager', () => {
|
||||||
const instantiationService = setupInstantiationService();
|
const instantiationService = setupInstantiationService();
|
||||||
instantiationService.stub(IStorageService, new TestStorageService());
|
const kernelService = new NotebookKernelService(new TestStorageService(), new NullLogService());
|
||||||
instantiationService.stub(IContextKeyService, new MockContextKeyService());
|
instantiationService.set(INotebookKernelService, kernelService);
|
||||||
instantiationService.stub(IQuickInputService, new TestQuickInputService());
|
|
||||||
|
|
||||||
const loadKernelPreloads = async () => { };
|
|
||||||
const onDidChangeViewModel = () => { };
|
|
||||||
const testDelegate = { loadKernelPreloads, onDidChangeViewModel };
|
|
||||||
|
|
||||||
async function withTestNotebook(cells: [string, string, CellKind, IOutputDto[], NotebookCellMetadata][], callback: (viewModel: NotebookViewModel, textModel: NotebookTextModel) => void | Promise<void>) {
|
async function withTestNotebook(cells: [string, string, CellKind, IOutputDto[], NotebookCellMetadata][], callback: (viewModel: NotebookViewModel, textModel: NotebookTextModel) => void | Promise<void>) {
|
||||||
return _withTestNotebook(cells, (editor) => callback(editor.viewModel, editor.viewModel.notebookDocument));
|
return _withTestNotebook(cells, (editor) => callback(editor.viewModel, editor.viewModel.notebookDocument));
|
||||||
}
|
}
|
||||||
|
|
||||||
test('ctor', () => {
|
// test('ctor', () => {
|
||||||
instantiationService.createInstance(NotebookEditorKernelManager, testDelegate);
|
// instantiationService.createInstance(NotebookEditorKernelManager, { activeKernel: undefined, viewModel: undefined });
|
||||||
const contextKeyService = instantiationService.get(IContextKeyService);
|
// const contextKeyService = instantiationService.get(IContextKeyService);
|
||||||
|
|
||||||
assert.strictEqual(contextKeyService.getContextKeyValue(NOTEBOOK_KERNEL_COUNT.key), 0);
|
// assert.strictEqual(contextKeyService.getContextKeyValue(NOTEBOOK_KERNEL_COUNT.key), 0);
|
||||||
});
|
// });
|
||||||
|
|
||||||
test('cell is not runnable when no kernel is selected', async () => {
|
test('cell is not runnable when no kernel is selected', async () => {
|
||||||
await withTestNotebook(
|
await withTestNotebook(
|
||||||
[],
|
[],
|
||||||
async (viewModel) => {
|
async (viewModel) => {
|
||||||
const kernelManager: NotebookEditorKernelManager = instantiationService.createInstance(NotebookEditorKernelManager, { ...testDelegate, ...{ viewModel } });
|
const kernelManager = instantiationService.createInstance(NotebookEditorKernelManager, { activeKernel: undefined, viewModel });
|
||||||
|
|
||||||
const cell = viewModel.createCell(1, 'var c = 3', 'javascript', CellKind.Code, {}, [], true);
|
const cell = viewModel.createCell(1, 'var c = 3', 'javascript', CellKind.Code, {}, [], true);
|
||||||
await assertThrowsAsync(async () => await kernelManager.executeNotebookCell(cell));
|
await assertThrowsAsync(async () => await kernelManager.executeNotebookCell(cell));
|
||||||
@@ -58,11 +50,12 @@ suite('NotebookEditorKernelManager', () => {
|
|||||||
await withTestNotebook(
|
await withTestNotebook(
|
||||||
[],
|
[],
|
||||||
async (viewModel) => {
|
async (viewModel) => {
|
||||||
const kernelManager: NotebookEditorKernelManager = instantiationService.createInstance(NotebookEditorKernelManager, { ...testDelegate, ...{ viewModel } });
|
|
||||||
kernelManager.activeKernel = new TestNotebookKernel({ languages: ['testlang'] });
|
|
||||||
|
|
||||||
|
const d = kernelService.registerKernel(new TestNotebookKernel({ languages: ['testlang'] }));
|
||||||
|
const kernelManager = instantiationService.createInstance(NotebookEditorKernelManager);
|
||||||
const cell = viewModel.createCell(1, 'var c = 3', 'javascript', CellKind.Code, {}, [], true);
|
const cell = viewModel.createCell(1, 'var c = 3', 'javascript', CellKind.Code, {}, [], true);
|
||||||
await assertThrowsAsync(async () => await kernelManager.executeNotebookCell(cell));
|
await assertThrowsAsync(async () => await kernelManager.executeNotebookCell(cell));
|
||||||
|
d.dispose();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -70,41 +63,41 @@ suite('NotebookEditorKernelManager', () => {
|
|||||||
await withTestNotebook(
|
await withTestNotebook(
|
||||||
[],
|
[],
|
||||||
async (viewModel) => {
|
async (viewModel) => {
|
||||||
const kernelManager: NotebookEditorKernelManager = instantiationService.createInstance(NotebookEditorKernelManager, { ...testDelegate, ...{ viewModel } });
|
|
||||||
const kernel = new TestNotebookKernel({ languages: ['javascript'] });
|
const kernel = new TestNotebookKernel({ languages: ['javascript'] });
|
||||||
|
const d = kernelService.registerKernel(kernel);
|
||||||
|
const kernelManager = instantiationService.createInstance(NotebookEditorKernelManager);
|
||||||
const executeSpy = sinon.spy();
|
const executeSpy = sinon.spy();
|
||||||
kernel.executeNotebookCellsRequest = executeSpy;
|
kernel.executeNotebookCellsRequest = executeSpy;
|
||||||
kernelManager.activeKernel = kernel;
|
|
||||||
|
|
||||||
const cell = viewModel.createCell(0, 'var c = 3', 'javascript', CellKind.Code, {}, [], true);
|
const cell = viewModel.createCell(0, 'var c = 3', 'javascript', CellKind.Code, {}, [], true);
|
||||||
await kernelManager.executeNotebookCell(cell);
|
await kernelManager.executeNotebookCells(viewModel.notebookDocument, [cell]);
|
||||||
assert.strictEqual(executeSpy.calledOnce, true);
|
assert.strictEqual(executeSpy.calledOnce, true);
|
||||||
|
d.dispose();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
class TestNotebookKernel implements INotebookKernel {
|
class TestNotebookKernel implements INotebookKernel {
|
||||||
id?: string | undefined;
|
id: string = 'test';
|
||||||
friendlyId: string = '';
|
|
||||||
label: string = '';
|
label: string = '';
|
||||||
|
selector = '*';
|
||||||
|
onDidChange = Event.None;
|
||||||
extension: ExtensionIdentifier = new ExtensionIdentifier('test');
|
extension: ExtensionIdentifier = new ExtensionIdentifier('test');
|
||||||
localResourceRoot: URI = URI.file('/test');
|
localResourceRoot: URI = URI.file('/test');
|
||||||
providerHandle?: number | undefined;
|
|
||||||
description?: string | undefined;
|
description?: string | undefined;
|
||||||
detail?: string | undefined;
|
detail?: string | undefined;
|
||||||
isPreferred?: boolean | undefined;
|
isPreferred?: boolean | undefined;
|
||||||
preloadUris: URI[] = [];
|
preloadUris: URI[] = [];
|
||||||
preloadProvides: string[] = [];
|
preloadProvides: string[] = [];
|
||||||
supportedLanguages?: string[] | undefined;
|
supportedLanguages: string[] = [];
|
||||||
async resolve(uri: URI, editorId: string, token: CancellationToken): Promise<void> { }
|
executeNotebookCellsRequest(): Promise<void> {
|
||||||
executeNotebookCellsRequest(uri: URI, ranges: ICellRange[]): Promise<void> {
|
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
cancelNotebookCellExecution(): Promise<void> {
|
cancelNotebookCellExecution(): Promise<void> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(opts?: { languages?: string[] }) {
|
constructor(opts?: { languages: string[] }) {
|
||||||
this.supportedLanguages = opts?.languages;
|
this.supportedLanguages = opts?.languages ?? ['text/plain'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ suite('NotebookCell#Document', function () {
|
|||||||
return URI.from({ scheme: 'test', path: generateUuid() });
|
return URI.from({ scheme: 'test', path: generateUuid() });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
extHostNotebooks = new ExtHostNotebookController(rpcProtocol, new ExtHostCommands(rpcProtocol, new NullLogService()), extHostDocumentsAndEditors, extHostDocuments, { isExtensionDevelopmentDebug: false, webviewCspSource: '', webviewResourceRoot: '' }, new NullLogService(), extHostStoragePaths);
|
extHostNotebooks = new ExtHostNotebookController(rpcProtocol, new ExtHostCommands(rpcProtocol, new NullLogService()), extHostDocumentsAndEditors, extHostDocuments, new NullLogService(), extHostStoragePaths);
|
||||||
let reg = extHostNotebooks.registerNotebookContentProvider(nullExtensionDescription, 'test', new class extends mock<vscode.NotebookContentProvider>() {
|
let reg = extHostNotebooks.registerNotebookContentProvider(nullExtensionDescription, 'test', new class extends mock<vscode.NotebookContentProvider>() {
|
||||||
// async openNotebook() { }
|
// async openNotebook() { }
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ suite('NotebookConcatDocument', function () {
|
|||||||
return URI.from({ scheme: 'test', path: generateUuid() });
|
return URI.from({ scheme: 'test', path: generateUuid() });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
extHostNotebooks = new ExtHostNotebookController(rpcProtocol, new ExtHostCommands(rpcProtocol, new NullLogService()), extHostDocumentsAndEditors, extHostDocuments, { isExtensionDevelopmentDebug: false, webviewCspSource: '', webviewResourceRoot: '' }, new NullLogService(), extHostStoragePaths);
|
extHostNotebooks = new ExtHostNotebookController(rpcProtocol, new ExtHostCommands(rpcProtocol, new NullLogService()), extHostDocumentsAndEditors, extHostDocuments, new NullLogService(), extHostStoragePaths);
|
||||||
let reg = extHostNotebooks.registerNotebookContentProvider(nullExtensionDescription, 'test', new class extends mock<vscode.NotebookContentProvider>() {
|
let reg = extHostNotebooks.registerNotebookContentProvider(nullExtensionDescription, 'test', new class extends mock<vscode.NotebookContentProvider>() {
|
||||||
// async openNotebook() { }
|
// async openNotebook() { }
|
||||||
});
|
});
|
||||||
@@ -70,14 +70,12 @@ suite('NotebookConcatDocument', function () {
|
|||||||
}],
|
}],
|
||||||
versionId: 0
|
versionId: 0
|
||||||
}],
|
}],
|
||||||
addedEditors: [
|
addedEditors: [{
|
||||||
{
|
documentUri: notebookUri,
|
||||||
documentUri: notebookUri,
|
id: '_notebook_editor_0',
|
||||||
id: '_notebook_editor_0',
|
selections: [{ start: 0, end: 1 }],
|
||||||
selections: [{ start: 0, end: 1 }],
|
visibleRanges: []
|
||||||
visibleRanges: []
|
}]
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
});
|
||||||
extHostNotebooks.$acceptDocumentAndEditorsDelta({ newActiveEditor: '_notebook_editor_0' });
|
extHostNotebooks.$acceptDocumentAndEditorsDelta({ newActiveEditor: '_notebook_editor_0' });
|
||||||
|
|
||||||
|
|||||||
@@ -1,109 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
import * as assert from 'assert';
|
|
||||||
import { TestRPCProtocol } from 'vs/workbench/test/browser/api/testRPCProtocol';
|
|
||||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
|
||||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
|
||||||
import { NullLogService } from 'vs/platform/log/common/log';
|
|
||||||
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
|
|
||||||
import { ExtHostNotebookDocument } from 'vs/workbench/api/common/extHostNotebookDocument';
|
|
||||||
import { URI } from 'vs/base/common/uri';
|
|
||||||
import { CellKind, CellUri } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
|
||||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
|
||||||
import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
|
||||||
import * as vscode from 'vscode';
|
|
||||||
import { mock } from 'vs/workbench/test/common/workbenchTestServices';
|
|
||||||
import { MainContext, MainThreadCommandsShape, MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol';
|
|
||||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
|
||||||
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
|
|
||||||
import { generateUuid } from 'vs/base/common/uuid';
|
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
|
||||||
|
|
||||||
suite('NotebookKernel', function () {
|
|
||||||
|
|
||||||
let rpcProtocol: TestRPCProtocol;
|
|
||||||
let notebook: ExtHostNotebookDocument;
|
|
||||||
let extHostDocumentsAndEditors: ExtHostDocumentsAndEditors;
|
|
||||||
let extHostDocuments: ExtHostDocuments;
|
|
||||||
let extHostNotebooks: ExtHostNotebookController;
|
|
||||||
const notebookUri = URI.parse('test:///notebook.file');
|
|
||||||
const disposables = new DisposableStore();
|
|
||||||
|
|
||||||
setup(async function () {
|
|
||||||
disposables.clear();
|
|
||||||
|
|
||||||
rpcProtocol = new TestRPCProtocol();
|
|
||||||
rpcProtocol.set(MainContext.MainThreadCommands, new class extends mock<MainThreadCommandsShape>() {
|
|
||||||
override $registerCommand() { }
|
|
||||||
});
|
|
||||||
rpcProtocol.set(MainContext.MainThreadNotebook, new class extends mock<MainThreadNotebookShape>() {
|
|
||||||
async override $registerNotebookProvider() { }
|
|
||||||
async override $unregisterNotebookProvider() { }
|
|
||||||
async override $registerNotebookKernelProvider() { }
|
|
||||||
async override $unregisterNotebookKernelProvider() { }
|
|
||||||
});
|
|
||||||
extHostDocumentsAndEditors = new ExtHostDocumentsAndEditors(rpcProtocol, new NullLogService());
|
|
||||||
extHostDocuments = new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors);
|
|
||||||
const extHostStoragePaths = new class extends mock<IExtensionStoragePaths>() {
|
|
||||||
override workspaceValue() {
|
|
||||||
return URI.from({ scheme: 'test', path: generateUuid() });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
extHostNotebooks = new ExtHostNotebookController(rpcProtocol, new ExtHostCommands(rpcProtocol, new NullLogService()), extHostDocumentsAndEditors, extHostDocuments, { isExtensionDevelopmentDebug: false, webviewCspSource: '', webviewResourceRoot: '' }, new NullLogService(), extHostStoragePaths);
|
|
||||||
let reg = extHostNotebooks.registerNotebookContentProvider(nullExtensionDescription, 'test', new class extends mock<vscode.NotebookContentProvider>() {
|
|
||||||
// async openNotebook() { }
|
|
||||||
});
|
|
||||||
|
|
||||||
const kernels = [new class extends mock<vscode.NotebookKernel>() {
|
|
||||||
override id = 'first';
|
|
||||||
}, new class extends mock<vscode.NotebookKernel>() {
|
|
||||||
override id = 'second';
|
|
||||||
}];
|
|
||||||
|
|
||||||
let kernelReg = extHostNotebooks.registerNotebookKernelProvider(nullExtensionDescription, { viewType: 'test' }, new class extends mock<vscode.NotebookKernelProvider>() {
|
|
||||||
async override provideKernels() { return kernels; }
|
|
||||||
});
|
|
||||||
|
|
||||||
// init
|
|
||||||
extHostNotebooks.$acceptDocumentAndEditorsDelta({
|
|
||||||
addedDocuments: [{
|
|
||||||
uri: notebookUri,
|
|
||||||
viewType: 'test',
|
|
||||||
cells: [{
|
|
||||||
handle: 0,
|
|
||||||
uri: CellUri.generate(notebookUri, 0),
|
|
||||||
source: ['console.log'],
|
|
||||||
eol: '\n',
|
|
||||||
language: 'javascript',
|
|
||||||
cellKind: CellKind.Code,
|
|
||||||
outputs: [],
|
|
||||||
}],
|
|
||||||
versionId: 0
|
|
||||||
}],
|
|
||||||
addedEditors: [
|
|
||||||
{
|
|
||||||
documentUri: notebookUri,
|
|
||||||
id: '_notebook_editor_0',
|
|
||||||
selections: [{ start: 0, end: 1 }],
|
|
||||||
visibleRanges: []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
extHostNotebooks.$acceptDocumentAndEditorsDelta({ newActiveEditor: '_notebook_editor_0' });
|
|
||||||
|
|
||||||
notebook = extHostNotebooks.notebookDocuments[0]!;
|
|
||||||
|
|
||||||
disposables.add(reg);
|
|
||||||
disposables.add(kernelReg);
|
|
||||||
disposables.add(notebook);
|
|
||||||
disposables.add(extHostDocuments);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('provide kernels', async function () {
|
|
||||||
const dto = await extHostNotebooks.$provideNotebookKernels(0, notebook.uri, CancellationToken.None);
|
|
||||||
assert.deepStrictEqual(dto.map(kernel => kernel.id), ['first', 'second']);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
Reference in New Issue
Block a user