Merge branch 'notebook/dev' into main

This commit is contained in:
rebornix
2021-04-06 14:03:18 -07:00
19 changed files with 495 additions and 296 deletions
@@ -83,7 +83,7 @@ suite('Notebook Document', function () {
assert.strictEqual(notebook.uri.toString(), uri.toString());
assert.strictEqual(notebook.isDirty, false);
assert.strictEqual(notebook.isUntitled, false);
assert.strictEqual(notebook.cells.length, 1);
assert.strictEqual(notebook.cellCount, 1);
assert.strictEqual(notebook.viewType, 'notebook.nbdtest');
});
@@ -96,7 +96,7 @@ suite('Notebook Document', function () {
return;
}
const notebook = vscode.notebook.notebookDocuments.find(notebook => {
const cell = notebook.cells.find(cell => cell.document === doc);
const cell = notebook.getCells().find(cell => cell.document === doc);
return Boolean(cell);
});
assert.ok(notebook, `notebook for cell ${doc.uri} NOT found`);
@@ -112,7 +112,9 @@ suite('Notebook Document', function () {
const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest');
const p = utils.asPromise(vscode.notebook.onDidOpenNotebookDocument).then(notebook => {
for (let cell of notebook.cells) {
for (let i = 0; i < notebook.cellCount; i++) {
let cell = notebook.cellAt(i);
const doc = vscode.workspace.textDocuments.find(doc => doc.uri.toString() === cell.document.uri.toString());
assert.ok(doc);
assert.strictEqual(doc.notebook === notebook, true);
@@ -132,7 +134,7 @@ suite('Notebook Document', function () {
const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest');
const document = await vscode.notebook.openNotebookDocument(uri);
assert.strictEqual(document.cells.length, 1);
assert.strictEqual(document.cellCount, 1);
// inserting two new cells
{
@@ -155,9 +157,9 @@ suite('Notebook Document', function () {
assert.strictEqual(success, true);
}
assert.strictEqual(document.cells.length, 3);
assert.strictEqual(document.cells[0].document.getText(), 'new_markdown');
assert.strictEqual(document.cells[1].document.getText(), 'new_code');
assert.strictEqual(document.cellCount, 3);
assert.strictEqual(document.cellAt(0).document.getText(), 'new_markdown');
assert.strictEqual(document.cellAt(1).document.getText(), 'new_code');
// deleting cell 1 and 3
{
@@ -168,8 +170,8 @@ suite('Notebook Document', function () {
assert.strictEqual(success, true);
}
assert.strictEqual(document.cells.length, 1);
assert.strictEqual(document.cells[0].document.getText(), 'new_code');
assert.strictEqual(document.cellCount, 1);
assert.strictEqual(document.cellAt(0).document.getText(), 'new_code');
// replacing all cells
{
@@ -190,24 +192,24 @@ suite('Notebook Document', function () {
const success = await vscode.workspace.applyEdit(edit);
assert.strictEqual(success, true);
}
assert.strictEqual(document.cells.length, 2);
assert.strictEqual(document.cells[0].document.getText(), 'new2_markdown');
assert.strictEqual(document.cells[1].document.getText(), 'new2_code');
assert.strictEqual(document.cellCount, 2);
assert.strictEqual(document.cellAt(0).document.getText(), 'new2_markdown');
assert.strictEqual(document.cellAt(1).document.getText(), 'new2_code');
// remove all cells
{
const edit = new vscode.WorkspaceEdit();
edit.replaceNotebookCells(document.uri, 0, document.cells.length, []);
edit.replaceNotebookCells(document.uri, 0, document.cellCount, []);
const success = await vscode.workspace.applyEdit(edit);
assert.strictEqual(success, true);
}
assert.strictEqual(document.cells.length, 0);
assert.strictEqual(document.cellCount, 0);
});
test('workspace edit API (replaceCells, event)', async function () {
const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest');
const document = await vscode.notebook.openNotebookDocument(uri);
assert.strictEqual(document.cells.length, 1);
assert.strictEqual(document.cellCount, 1);
const edit = new vscode.WorkspaceEdit();
edit.replaceNotebookCells(document.uri, 0, 0, [{
@@ -232,9 +234,9 @@ suite('Notebook Document', function () {
const data = await event;
// check document
assert.strictEqual(document.cells.length, 3);
assert.strictEqual(document.cells[0].document.getText(), 'new_markdown');
assert.strictEqual(document.cells[1].document.getText(), 'new_code');
assert.strictEqual(document.cellCount, 3);
assert.strictEqual(document.cellAt(0).document.getText(), 'new_markdown');
assert.strictEqual(document.cellAt(1).document.getText(), 'new_code');
// check event data
assert.strictEqual(data.document === document, true);
@@ -242,8 +244,8 @@ suite('Notebook Document', function () {
assert.strictEqual(data.changes[0].deletedCount, 0);
assert.strictEqual(data.changes[0].deletedItems.length, 0);
assert.strictEqual(data.changes[0].items.length, 2);
assert.strictEqual(data.changes[0].items[0], document.cells[0]);
assert.strictEqual(data.changes[0].items[1], document.cells[1]);
assert.strictEqual(data.changes[0].items[0], document.cellAt(0));
assert.strictEqual(data.changes[0].items[1], document.cellAt(1));
});
test('workspace edit API (appendNotebookCellOutput, replaceCellOutput, event)', async function () {
@@ -258,9 +260,9 @@ suite('Notebook Document', function () {
const data = await outputChangeEvent;
assert.strictEqual(success, true);
assert.strictEqual(document.cells.length, 1);
assert.strictEqual(document.cells[0].outputs.length, 1);
assert.deepStrictEqual(document.cells[0].outputs, [firstCellOutput]);
assert.strictEqual(document.cellCount, 1);
assert.strictEqual(document.cellAt(0).outputs.length, 1);
assert.deepStrictEqual(document.cellAt(0).outputs, [firstCellOutput]);
assert.strictEqual(data.document === document, true);
assert.strictEqual(data.cells.length, 1);
@@ -277,9 +279,9 @@ suite('Notebook Document', function () {
const data = await outputChangeEvent;
assert.strictEqual(success, true);
assert.strictEqual(document.cells.length, 1);
assert.strictEqual(document.cells[0].outputs.length, 2);
assert.deepStrictEqual(document.cells[0].outputs, [firstCellOutput, secondCellOutput]);
assert.strictEqual(document.cellCount, 1);
assert.strictEqual(document.cellAt(0).outputs.length, 2);
assert.deepStrictEqual(document.cellAt(0).outputs, [firstCellOutput, secondCellOutput]);
assert.strictEqual(data.document === document, true);
assert.strictEqual(data.cells.length, 1);
@@ -296,9 +298,9 @@ suite('Notebook Document', function () {
const data = await outputChangeEvent;
assert.strictEqual(success, true);
assert.strictEqual(document.cells.length, 1);
assert.strictEqual(document.cells[0].outputs.length, 1);
assert.deepStrictEqual(document.cells[0].outputs, [thirdOutput]);
assert.strictEqual(document.cellCount, 1);
assert.strictEqual(document.cellAt(0).outputs.length, 1);
assert.deepStrictEqual(document.cellAt(0).outputs, [thirdOutput]);
assert.strictEqual(data.document === document, true);
assert.strictEqual(data.cells.length, 1);
@@ -314,7 +316,7 @@ suite('Notebook Document', function () {
assert.strictEqual(notebook.uri.toString(), uri.toString());
assert.strictEqual(notebook.isDirty, false);
assert.strictEqual(notebook.isUntitled, false);
assert.strictEqual(notebook.cells.length, 1);
assert.strictEqual(notebook.cellCount, 1);
assert.strictEqual(notebook.viewType, 'notebook.nbdtest');
const edit = new vscode.WorkspaceEdit();
@@ -345,7 +347,7 @@ suite('Notebook Document', function () {
const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest');
const notebook = await vscode.notebook.openNotebookDocument(uri);
const first = notebook.cells[0];
const first = notebook.cellAt(0);
assert.strictEqual(first.document.languageId, 'javascript');
const pclose = utils.asPromise(vscode.workspace.onDidCloseTextDocument);
@@ -378,10 +380,10 @@ suite('Notebook Document', function () {
let success = await vscode.workspace.applyEdit(edit);
assert.ok(success);
assert.strictEqual(document.cells[0].outputs.length, 1);
assert.strictEqual(document.cells[0].outputs[0].outputs.length, 1);
assert.deepStrictEqual(document.cells[0].outputs[0].metadata, { outputType: 'stream', streamName: 'stdout' });
assert.deepStrictEqual(document.cells[0].outputs[0].outputs[0].metadata, { outputType: 'stream', streamName: 'stdout' });
assert.strictEqual(document.cellAt(0).outputs.length, 1);
assert.strictEqual(document.cellAt(0).outputs[0].outputs.length, 1);
assert.deepStrictEqual(document.cellAt(0).outputs[0].metadata, { outputType: 'stream', streamName: 'stdout' });
assert.deepStrictEqual(document.cellAt(0).outputs[0].outputs[0].metadata, { outputType: 'stream', streamName: 'stdout' });
const edit2 = new vscode.WorkspaceEdit();
edit2.appendNotebookCellOutput(document.uri, 0, [
@@ -393,13 +395,13 @@ suite('Notebook Document', function () {
success = await vscode.workspace.applyEdit(edit2);
assert.ok(success);
assert.strictEqual(document.cells[0].outputs.length, 2);
assert.strictEqual(document.cells[0].outputs[0].outputs.length, 1);
assert.strictEqual(document.cells[0].outputs[1].outputs.length, 1);
assert.deepStrictEqual(document.cells[0].outputs[0].metadata, { outputType: 'stream', streamName: 'stdout' });
assert.deepStrictEqual(document.cells[0].outputs[0].outputs[0].metadata, { outputType: 'stream', streamName: 'stdout' });
assert.deepStrictEqual(document.cells[0].outputs[1].metadata, { outputType: 'stream', streamName: 'stderr' });
assert.deepStrictEqual(document.cells[0].outputs[1].outputs[0].metadata, { outputType: 'stream', streamName: 'stderr' });
assert.strictEqual(document.cellAt(0).outputs.length, 2);
assert.strictEqual(document.cellAt(0).outputs[0].outputs.length, 1);
assert.strictEqual(document.cellAt(0).outputs[1].outputs.length, 1);
assert.deepStrictEqual(document.cellAt(0).outputs[0].metadata, { outputType: 'stream', streamName: 'stdout' });
assert.deepStrictEqual(document.cellAt(0).outputs[0].outputs[0].metadata, { outputType: 'stream', streamName: 'stdout' });
assert.deepStrictEqual(document.cellAt(0).outputs[1].metadata, { outputType: 'stream', streamName: 'stderr' });
assert.deepStrictEqual(document.cellAt(0).outputs[1].outputs[0].metadata, { outputType: 'stream', streamName: 'stderr' });
});
test('dirty state - complex', async function () {
@@ -341,7 +341,7 @@ suite('Notebook API tests', function () {
deletedCount: 0,
deletedItems: [],
items: [
vscode.window.activeNotebookEditor!.document.cells[1]
vscode.window.activeNotebookEditor!.document.cellAt(1)
]
});
@@ -354,7 +354,7 @@ suite('Notebook API tests', function () {
const cellOutputsAddedRet = await cellOutputChange;
assert.deepStrictEqual(cellOutputsAddedRet, {
document: vscode.window.activeNotebookEditor!.document,
cells: [vscode.window.activeNotebookEditor!.document.cells[0]]
cells: [vscode.window.activeNotebookEditor!.document.cellAt(0)]
});
assert.strictEqual(cellOutputsAddedRet.cells[0].outputs.length, 1);
@@ -363,7 +363,7 @@ suite('Notebook API tests', function () {
const cellOutputsCleardRet = await cellOutputClear;
assert.deepStrictEqual(cellOutputsCleardRet, {
document: vscode.window.activeNotebookEditor!.document,
cells: [vscode.window.activeNotebookEditor!.document.cells[0]]
cells: [vscode.window.activeNotebookEditor!.document.cellAt(0)]
});
assert.strictEqual(cellOutputsAddedRet.cells[0].outputs.length, 0);
@@ -372,7 +372,7 @@ suite('Notebook API tests', function () {
// const cellChangeLanguageRet = await cellChangeLanguage;
// assert.deepStrictEqual(cellChangeLanguageRet, {
// document: vscode.window.activeNotebookEditor!.document,
// cells: vscode.window.activeNotebookEditor!.document.cells[0],
// cells: vscode.window.activeNotebookEditor!.document.cellAt(0),
// language: 'markdown'
// });
@@ -387,7 +387,7 @@ suite('Notebook API tests', function () {
await vscode.commands.executeCommand('notebook.focusTop');
const activeCell = vscode.window.activeNotebookEditor!.selection;
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.indexOf(activeCell!), 0);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(activeCell!), 0);
const moveChange = asPromise(vscode.notebook.onDidChangeNotebookCells);
await vscode.commands.executeCommand('notebook.cell.moveDown');
await moveChange;
@@ -396,7 +396,7 @@ suite('Notebook API tests', function () {
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
const firstEditor = vscode.window.activeNotebookEditor;
assert.strictEqual(firstEditor?.document.cells.length, 2);
assert.strictEqual(firstEditor?.document.cellCount, 2);
await saveAllFilesAndCloseAll(undefined);
});
@@ -454,8 +454,8 @@ suite('Notebook API tests', function () {
});
const document = vscode.window.activeNotebookEditor?.document!;
assert.strictEqual(document.cells.length, 2);
assert.strictEqual(document.cells[0].metadata.inputCollapsed, true);
assert.strictEqual(document.cellCount, 2);
assert.strictEqual(document.cellAt(0).metadata.inputCollapsed, true);
assert.strictEqual(document.isDirty, true);
await saveFileAndCloseAll(resource);
@@ -511,14 +511,14 @@ suite('Notebook API tests', function () {
await cellsChangeEvent;
await cellMetadataChangeEvent;
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.length, 3);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells[0]?.metadata?.breakpointMargin, false);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellCount, 3);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellAt(0)?.metadata?.breakpointMargin, false);
assert.strictEqual(version + 1, vscode.window.activeNotebookEditor!.document.version);
await vscode.commands.executeCommand('undo');
assert.strictEqual(version + 2, vscode.window.activeNotebookEditor!.document.version);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells[0]?.metadata?.breakpointMargin, undefined);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.length, 2);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellAt(0)?.metadata?.breakpointMargin, undefined);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellCount, 2);
await saveAllFilesAndCloseAll(resource);
});
@@ -549,7 +549,7 @@ suite('Notebook API tests', function () {
assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.document.getText(), 'test');
assert.strictEqual(vscode.window.activeNotebookEditor!.selection?.document.languageId, 'typescript');
const secondCell = vscode.window.activeNotebookEditor!.document.cells[1];
const secondCell = vscode.window.activeNotebookEditor!.document.cellAt(1);
assert.strictEqual(secondCell!.outputs.length, 1);
assert.deepStrictEqual(secondCell!.outputs[0].metadata, { testOutputMetadata: true });
assert.strictEqual(secondCell!.outputs[0].outputs.length, 1);
@@ -566,8 +566,8 @@ suite('Notebook API tests', function () {
const activeCell = vscode.window.activeNotebookEditor!.selection;
assert.notEqual(vscode.window.activeNotebookEditor!.selection, undefined);
assert.strictEqual(activeCell!.document.getText(), '');
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.length, 4);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.indexOf(activeCell!), 1);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellCount, 4);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(activeCell!), 1);
await vscode.commands.executeCommand('workbench.action.files.save');
await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
@@ -589,56 +589,56 @@ suite('Notebook API tests', function () {
let activeCell = vscode.window.activeNotebookEditor!.selection;
assert.notEqual(vscode.window.activeNotebookEditor!.selection, undefined);
assert.strictEqual(activeCell!.document.getText(), '');
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.length, 4);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.indexOf(activeCell!), 1);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellCount, 4);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(activeCell!), 1);
// ---- focus bottom ---- //
await vscode.commands.executeCommand('notebook.focusBottom');
activeCell = vscode.window.activeNotebookEditor!.selection;
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.indexOf(activeCell!), 3);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(activeCell!), 3);
// ---- focus top and then copy down ---- //
await vscode.commands.executeCommand('notebook.focusTop');
activeCell = vscode.window.activeNotebookEditor!.selection;
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.indexOf(activeCell!), 0);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(activeCell!), 0);
await vscode.commands.executeCommand('notebook.cell.copyDown');
activeCell = vscode.window.activeNotebookEditor!.selection;
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.indexOf(activeCell!), 1);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(activeCell!), 1);
assert.strictEqual(activeCell?.document.getText(), 'test');
await vscode.commands.executeCommand('notebook.cell.delete');
activeCell = vscode.window.activeNotebookEditor!.selection;
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.indexOf(activeCell!), 1);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(activeCell!), 1);
assert.strictEqual(activeCell?.document.getText(), '');
// ---- focus top and then copy up ---- //
await vscode.commands.executeCommand('notebook.focusTop');
await vscode.commands.executeCommand('notebook.cell.copyUp');
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.length, 5);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells[0].document.getText(), 'test');
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells[1].document.getText(), 'test');
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells[2].document.getText(), '');
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells[3].document.getText(), '');
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellCount, 5);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellAt(0).document.getText(), 'test');
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellAt(1).document.getText(), 'test');
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellAt(2).document.getText(), '');
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellAt(3).document.getText(), '');
activeCell = vscode.window.activeNotebookEditor!.selection;
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.indexOf(activeCell!), 0);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(activeCell!), 0);
// ---- move up and down ---- //
await vscode.commands.executeCommand('notebook.cell.moveDown');
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.indexOf(vscode.window.activeNotebookEditor!.selection!), 1,
assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(vscode.window.activeNotebookEditor!.selection!), 1,
`first move down, active cell ${vscode.window.activeNotebookEditor!.selection!.document.uri.toString()}, ${vscode.window.activeNotebookEditor!.selection!.document.getText()}`);
// await vscode.commands.executeCommand('notebook.cell.moveDown');
// activeCell = vscode.window.activeNotebookEditor!.selection;
// assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.indexOf(activeCell!), 2,
// assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(activeCell!), 2,
// `second move down, active cell ${vscode.window.activeNotebookEditor!.selection!.uri.toString()}, ${vscode.window.activeNotebookEditor!.selection!.document.getText()}`);
// assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells[0].document.getText(), 'test');
// assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells[1].document.getText(), '');
// assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells[2].document.getText(), 'test');
// assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells[3].document.getText(), '');
// assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellAt(0).document.getText(), 'test');
// assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellAt(1).document.getText(), '');
// assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellAt(2).document.getText(), 'test');
// assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellAt(3).document.getText(), '');
// ---- ---- //
@@ -677,7 +677,7 @@ suite('Notebook API tests', function () {
await vscode.commands.executeCommand('notebook.focusTop');
const activeCell = vscode.window.activeNotebookEditor!.selection;
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.indexOf(activeCell!), 0);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(activeCell!), 0);
await vscode.commands.executeCommand('notebook.cell.moveDown');
await vscode.commands.executeCommand('notebook.cell.moveDown');
@@ -693,7 +693,7 @@ suite('Notebook API tests', function () {
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
const editor = vscode.window.activeNotebookEditor!;
const cell = editor.document.cells[0];
const cell = editor.document.cellAt(0);
assert.strictEqual(cell.outputs.length, 0);
currentKernelProvider.setHasKernels(false);
@@ -718,7 +718,7 @@ suite('Notebook API tests', function () {
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
const editor = vscode.window.activeNotebookEditor!;
const cell = editor.document.cells[0];
const cell = editor.document.cellAt(0);
await vscode.commands.executeCommand('notebook.execute');
assert.strictEqual(cell.outputs.length, 0, 'should not execute'); // not runnable, didn't work
@@ -731,7 +731,7 @@ suite('Notebook API tests', function () {
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
const editor = vscode.window.activeNotebookEditor!;
const cell = editor.document.cells[0];
const cell = editor.document.cellAt(0);
await withEvent(vscode.notebook.onDidChangeCellOutputs, async (event) => {
await vscode.commands.executeCommand('notebook.execute');
@@ -763,7 +763,7 @@ suite('Notebook API tests', function () {
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
const editor = vscode.window.activeNotebookEditor!;
const cell = editor.document.cells[0];
const cell = editor.document.cellAt(0);
await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs, async (event) => {
await vscode.commands.executeCommand('notebook.execute');
@@ -794,7 +794,7 @@ suite('Notebook API tests', function () {
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
const editor = vscode.window.activeNotebookEditor!;
const cell = editor.document.cells[0];
const cell = editor.document.cellAt(0);
vscode.commands.executeCommand('notebook.cell.execute');
await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs, async (event) => {
@@ -851,7 +851,7 @@ suite('Notebook API tests', function () {
const resource = await createRandomFile('', undefined, '.vsctestnb');
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
const editor = vscode.window.activeNotebookEditor!;
const cell = editor.document.cells[0];
const cell = editor.document.cellAt(0);
await vscode.commands.executeCommand('notebook.selectKernel', { extension: 'vscode.vscode-api-tests', id: cancelableKernel.id });
await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs, async (event) => {
@@ -901,7 +901,7 @@ suite('Notebook API tests', function () {
const resource = await createRandomFile('', undefined, '.vsctestnb');
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
const editor = vscode.window.activeNotebookEditor!;
const cell = editor.document.cells[0];
const cell = editor.document.cellAt(0);
await vscode.commands.executeCommand('notebook.selectKernel', { extension: 'vscode.vscode-api-tests', id: interruptableKernel.id });
await withEvent<vscode.NotebookCellOutputsChangeEvent>(vscode.notebook.onDidChangeCellOutputs, async (event) => {
@@ -923,7 +923,7 @@ suite('Notebook API tests', function () {
const resource = await createRandomFile('', undefined, '.vsctestnb');
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
const editor = vscode.window.activeNotebookEditor!;
const cell = editor.document.cells[0];
const cell = editor.document.cellAt(0);
vscode.commands.executeCommand('notebook.cell.execute');
let eventCount = 0;
@@ -964,8 +964,8 @@ suite('Notebook API tests', function () {
const activeCell = vscode.window.activeNotebookEditor!.selection;
assert.notStrictEqual(vscode.window.activeNotebookEditor!.selection, undefined);
assert.strictEqual(activeCell!.document.getText(), '');
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.length, 4);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.indexOf(activeCell!), 1);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellCount, 4);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(activeCell!), 1);
await withEvent(vscode.workspace.onDidChangeTextDocument, async event => {
const edit = new vscode.WorkspaceEdit();
@@ -974,7 +974,7 @@ suite('Notebook API tests', function () {
await event;
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true);
assert.strictEqual(vscode.window.activeNotebookEditor?.selection !== undefined, true);
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cells[1], vscode.window.activeNotebookEditor?.selection);
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellAt(1), vscode.window.activeNotebookEditor?.selection);
assert.strictEqual(vscode.window.activeNotebookEditor?.selection?.document.getText(), 'var abc = 0;');
});
@@ -997,8 +997,8 @@ suite('Notebook API tests', function () {
const activeCell = vscode.window.activeNotebookEditor!.selection;
assert.notStrictEqual(vscode.window.activeNotebookEditor!.selection, undefined);
assert.strictEqual(activeCell!.document.getText(), '');
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.length, 4);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.indexOf(activeCell!), 1);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellCount, 4);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(activeCell!), 1);
// modify the second cell, delete it
@@ -1006,20 +1006,20 @@ suite('Notebook API tests', function () {
edit.insert(vscode.window.activeNotebookEditor!.selection!.document.uri, new vscode.Position(0, 0), 'var abc = 0;');
await vscode.workspace.applyEdit(edit);
await vscode.commands.executeCommand('notebook.cell.delete');
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.length, 3);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.indexOf(vscode.window.activeNotebookEditor!.selection!), 1);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellCount, 3);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(vscode.window.activeNotebookEditor!.selection!), 1);
// undo should bring back the deleted cell, and revert to previous content and selection
await vscode.commands.executeCommand('undo');
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.length, 4);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.indexOf(vscode.window.activeNotebookEditor!.selection!), 1);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellCount, 4);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(vscode.window.activeNotebookEditor!.selection!), 1);
assert.strictEqual(vscode.window.activeNotebookEditor?.selection?.document.getText(), 'var abc = 0;');
// redo
// await vscode.commands.executeCommand('notebook.redo');
// assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.length, 2);
// assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.indexOf(vscode.window.activeNotebookEditor!.selection!), 1);
// assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellCount, 2);
// assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(vscode.window.activeNotebookEditor!.selection!), 1);
// assert.strictEqual(vscode.window.activeNotebookEditor?.selection?.document.getText(), 'test');
await saveFileAndCloseAll(resource);
@@ -1064,8 +1064,8 @@ suite('Notebook API tests', function () {
// make sure that the previous dirty editor is still restored in the extension host and no data loss
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true);
assert.strictEqual(vscode.window.activeNotebookEditor?.selection !== undefined, true);
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cells[1], vscode.window.activeNotebookEditor?.selection);
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cells.length, 4);
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellAt(1), vscode.window.activeNotebookEditor?.selection);
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellCount, 4);
assert.strictEqual(vscode.window.activeNotebookEditor?.selection?.document.getText(), 'var abc = 0;');
await saveFileAndCloseAll(resource);
@@ -1091,16 +1091,16 @@ suite('Notebook API tests', function () {
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true);
assert.strictEqual(vscode.window.activeNotebookEditor?.selection !== undefined, true);
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cells[1], vscode.window.activeNotebookEditor?.selection);
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cells.length, 4);
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellAt(1), vscode.window.activeNotebookEditor?.selection);
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellCount, 4);
assert.strictEqual(vscode.window.activeNotebookEditor?.selection?.document.getText(), 'var abc = 0;');
// switch to the second editor
await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest');
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true);
assert.strictEqual(vscode.window.activeNotebookEditor?.selection !== undefined, true);
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cells[1], vscode.window.activeNotebookEditor?.selection);
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cells.length, 3);
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellAt(1), vscode.window.activeNotebookEditor?.selection);
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellCount, 3);
assert.strictEqual(vscode.window.activeNotebookEditor?.selection?.document.getText(), '');
await saveAllFilesAndCloseAll(secondResource);
@@ -1150,7 +1150,7 @@ suite('Notebook API tests', function () {
// TODO see #101462
// await vscode.commands.executeCommand('notebook.cell.copyDown');
// const activeCell = vscode.window.activeNotebookEditor!.selection;
// assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.indexOf(activeCell!), 1);
// assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(activeCell!), 1);
// assert.strictEqual(activeCell?.metadata.custom!['testCellMetadata'] as number, 123);
await saveFileAndCloseAll(resource);
@@ -1162,7 +1162,7 @@ suite('Notebook API tests', function () {
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
const document = vscode.window.activeNotebookEditor?.document!;
const [cell] = document.cells;
const [cell] = document.getCells();
await saveAllFilesAndCloseAll(document.uri);
assert.strictEqual(vscode.window.activeNotebookEditor, undefined);
@@ -1179,7 +1179,7 @@ suite('Notebook API tests', function () {
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
const document = vscode.window.activeNotebookEditor?.document!;
const [cell] = document.cells;
const [cell] = document.getCells();
await saveAllFilesAndCloseAll(document.uri);
assert.strictEqual(vscode.window.activeNotebookEditor, undefined);
@@ -1245,15 +1245,15 @@ suite('Notebook API tests', function () {
await vscode.commands.executeCommand('notebook.cell.copyDown');
await vscode.commands.executeCommand('notebook.cell.edit');
activeCell = vscode.window.activeNotebookEditor!.selection;
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.indexOf(activeCell!), 1);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(activeCell!), 1);
assert.strictEqual(activeCell?.document.getText(), 'test');
const edit = new vscode.WorkspaceEdit();
edit.insert(vscode.window.activeNotebookEditor!.selection!.document.uri, new vscode.Position(0, 0), 'var abc = 0;');
await vscode.workspace.applyEdit(edit);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells.length, 3);
assert.notEqual(vscode.window.activeNotebookEditor!.document.cells[0].document.getText(), vscode.window.activeNotebookEditor!.document.cells[1].document.getText());
assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().length, 3);
assert.notEqual(vscode.window.activeNotebookEditor!.document.cellAt(0).document.getText(), vscode.window.activeNotebookEditor!.document.cellAt(1).document.getText());
await closeAllEditors();
});
@@ -1269,20 +1269,20 @@ suite('Notebook API tests', function () {
new vscode.NotebookCellOutputItem('application/json', { data: true }, { metadata: true }),
])]);
await vscode.workspace.applyEdit(edit);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells[0].outputs.length, 1);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells[0].outputs[0].outputs.length, 2);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellAt(0).outputs.length, 1);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellAt(0).outputs[0].outputs.length, 2);
const appendEdit = new vscode.WorkspaceEdit();
const newItem = new vscode.NotebookCellOutputItem('text/plain', '1');
appendEdit.appendNotebookCellOutputItems(
resource,
0,
vscode.window.activeNotebookEditor!.document.cells[0].outputs[0].id,
vscode.window.activeNotebookEditor!.document.cellAt(0).outputs[0].id,
[newItem]
);
await vscode.workspace.applyEdit(appendEdit);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cells[0].outputs[0].outputs.length, 3);
assert.deepStrictEqual(vscode.window.activeNotebookEditor!.document.cells[0].outputs[0].outputs[2], newItem);
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellAt(0).outputs[0].outputs.length, 3);
assert.deepStrictEqual(vscode.window.activeNotebookEditor!.document.cellAt(0).outputs[0].outputs[2], newItem);
});
test('#115855 onDidSaveNotebookDocument', async function () {
@@ -1339,8 +1339,8 @@ suite('Notebook API tests', function () {
await task.replaceOutput([new vscode.NotebookCellOutput([
new vscode.NotebookCellOutputItem('text/plain', ['Some output'], undefined)
])]);
assert.strictEqual(document.cells[0].outputs.length, 1);
assert.deepStrictEqual(document.cells[0].outputs[0].outputs[0].value, ['Some output']);
assert.strictEqual(document.cellAt(0).outputs.length, 1);
assert.deepStrictEqual(document.cellAt(0).outputs[0].outputs[0].value, ['Some output']);
task.end({});
}
};
@@ -1359,7 +1359,7 @@ suite('Notebook API tests', function () {
const resource = await createRandomFile('', undefined, '.vsctestnb');
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
const editor = vscode.window.activeNotebookEditor!;
const cell = editor.document.cells[0];
const cell = editor.document.cellAt(0);
assert.strictEqual(cell.latestExecutionSummary?.success, undefined);
assert.strictEqual(cell.latestExecutionSummary?.executionOrder, undefined);
@@ -1376,7 +1376,7 @@ suite('Notebook API tests', function () {
const resource = await createRandomFile('', undefined, '.vsctestnb');
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
const editor = vscode.window.activeNotebookEditor!;
const cell = editor.document.cells[0];
const cell = editor.document.cellAt(0);
assert.strictEqual(cell.latestExecutionSummary?.success, undefined);
assert.strictEqual(cell.latestExecutionSummary?.duration, 25);
-6
View File
@@ -1090,10 +1090,6 @@ declare module 'vscode' {
// todo@API should we really expose this?
readonly viewType: string;
// todo@API cellsAt(range)? getCell(index>)?
/** @deprecated Use `getCells(<...>) instead */
readonly cells: ReadonlyArray<NotebookCell>;
/**
* The number of cells in the notebook document.
*/
@@ -1194,8 +1190,6 @@ declare module 'vscode' {
/**
* The column in which this editor shows.
*/
// @jrieken
// this is not implemented...
readonly viewColumn?: ViewColumn;
/**
@@ -38,7 +38,7 @@ export class MainThreadNotebookDocuments implements MainThreadNotebookDocumentsS
notebooksAndEditors.onDidRemoveNotebooks(this._handleNotebooksRemoved, this, this._disposables);
// forward dirty and save events
this._disposables.add(this._notebookEditorModelResolverService.onDidChangeDirty(model => this._proxy.$acceptDirtyStateChanged(model.resource, model.isDirty)));
this._disposables.add(this._notebookEditorModelResolverService.onDidChangeDirty(model => this._proxy.$acceptDirtyStateChanged(model.resource, model.isDirty())));
this._disposables.add(this._notebookEditorModelResolverService.onDidSaveNotebook(e => this._proxy.$acceptModelSaved(e)));
}
@@ -702,7 +702,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
if (document) {
document.dispose();
this._documents.delete(revivedUri);
this._textDocumentsAndEditors.$acceptDocumentsAndEditorsDelta({ removedDocuments: document.notebookDocument.cells.map(cell => cell.document.uri) });
this._textDocumentsAndEditors.$acceptDocumentsAndEditorsDelta({ removedDocuments: document.notebookDocument.getCells().map(cell => cell.document.uri) });
this._onDidCloseNotebookDocument.fire(document.notebookDocument);
}
@@ -73,7 +73,7 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
this._cellUris = new ResourceMap();
const cellLengths: number[] = [];
const cellLineCounts: number[] = [];
for (const cell of this._notebook.cells) {
for (const cell of this._notebook.getCells()) {
if (cell.kind === types.NotebookCellKind.Code && (!this._selector || score(this._selector, cell.document.uri, cell.document.languageId, true))) {
this._cellUris.set(cell.document.uri, this._cells.length);
this._cells.push(cell);
@@ -179,7 +179,6 @@ export class ExtHostNotebookDocument extends Disposable {
get isUntitled() { return that.uri.scheme === Schemas.untitled; },
get isClosed() { return that._disposed; },
get metadata() { return that._metadata; },
get cells(): ReadonlyArray<vscode.NotebookCell> { return that._cells.map(cell => cell.cell); },
get cellCount() { return that._cells.length; },
cellAt(index) {
index = that._validateIndex(index);
@@ -810,8 +810,8 @@ registerAction2(class extends NotebookAction {
});
}
async run(accessor: ServicesAccessor): Promise<void> {
const context = this.getEditorContextFromArgsOrActive(accessor);
async run(accessor: ServicesAccessor, context?: INotebookActionContext): Promise<void> {
context = context ?? this.getEditorContextFromArgsOrActive(accessor);
if (context) {
this.runWithContext(accessor, context);
}
@@ -835,8 +835,8 @@ registerAction2(class extends NotebookAction {
});
}
async run(accessor: ServicesAccessor): Promise<void> {
const context = this.getEditorContextFromArgsOrActive(accessor);
async run(accessor: ServicesAccessor, context?: INotebookActionContext): Promise<void> {
context = context ?? this.getEditorContextFromArgsOrActive(accessor);
if (context) {
this.runWithContext(accessor, context);
}
@@ -24,13 +24,13 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle
import { Registry } from 'vs/platform/registry/common/platform';
import { EditorDescriptor, EditorsAssociations, editorsAssociationsSettingId, Extensions as EditorExtensions, IEditorRegistry } from 'vs/workbench/browser/editor';
import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
import { EditorInput, Extensions as EditorInputExtensions, ICustomEditorInputFactory, IEditorInput, IEditorInputSerializer, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor';
import { EditorInput, Extensions as EditorInputExtensions, ICustomEditorInputFactory, IEditorInput, IEditorInputSerializer, IEditorInputFactoryRegistry, IEditorInputWithOptions } from 'vs/workbench/common/editor';
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
import { NotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookEditor';
import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebookEditorInput';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { NotebookService } from 'vs/workbench/contrib/notebook/browser/notebookServiceImpl';
import { CellKind, CellToolbarLocKey, CellUri, DisplayOrderKey, ExperimentalUseMarkdownRenderer, getCellUndoRedoComparisonKey, NotebookDocumentBackupData, NotebookEditorPriority, NotebookTextDiffEditorPreview, ShowCellStatusBarKey } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellKind, CellToolbarLocKey, CellUri, DisplayOrderKey, ExperimentalUseMarkdownRenderer, getCellUndoRedoComparisonKey, IResolvedNotebookEditorModel, NotebookDocumentBackupData, NotebookEditorPriority, NotebookTextDiffEditorPreview, ShowCellStatusBarKey } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorService, IOpenEditorOverride } from 'vs/workbench/services/editor/common/editorService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
@@ -694,11 +694,12 @@ class NotebookFileTracker implements IWorkbenchContribution {
private readonly _dirtyListener: IDisposable;
constructor(
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@IEditorService private readonly _editorService: IEditorService,
@INotebookEditorModelResolverService private readonly _notebookEditorModelService: INotebookEditorModelResolverService,
) {
type E = { resource: URI, isDirty: boolean };
type E = IResolvedNotebookEditorModel;
this._dirtyListener = Event.debounce<E, E[]>(
this._notebookEditorModelService.onDidChangeDirty,
(last, current) => !last ? [current] : [...last, current],
@@ -710,13 +711,13 @@ class NotebookFileTracker implements IWorkbenchContribution {
this._dirtyListener.dispose();
}
private _openMissingDirtyNotebookEditors(inputs: { resource: URI, isDirty: boolean }[]): void {
const result: IResourceEditorInput[] = [];
for (let input of inputs) {
if (input.isDirty && !this._editorService.isOpen({ resource: input.resource })) {
private _openMissingDirtyNotebookEditors(models: IResolvedNotebookEditorModel[]): void {
const result: IEditorInputWithOptions[] = [];
for (let model of models) {
if (model.isDirty() && !this._editorService.isOpen({ resource: model.resource })) {
result.push({
resource: input.resource,
options: { inactive: true, preserveFocus: true, pinned: true }
editor: NotebookEditorInput.create(this._instantiationService, model.resource, model.viewType),
options: { inactive: true, preserveFocus: true, pinned: true, }
});
}
}
@@ -55,6 +55,7 @@ export const NOTEBOOK_CELL_EDITABLE = new RawContextKey<boolean>('notebookCellEd
export const NOTEBOOK_CELL_FOCUSED = new RawContextKey<boolean>('notebookCellFocused', false); // bool
export const NOTEBOOK_CELL_EDITOR_FOCUSED = new RawContextKey<boolean>('notebookCellEditorFocused', false); // bool
export const NOTEBOOK_CELL_MARKDOWN_EDIT_MODE = new RawContextKey<boolean>('notebookCellMarkdownEditMode', false); // bool
export const NOTEBOOK_CELL_LINE_NUMBERS = new RawContextKey<'on' | 'off' | 'inherit'>('notebookCellLineNumbers', 'inherit'); // off, none, inherit
export type NotebookCellExecutionStateContext = 'idle' | 'pending' | 'executing' | 'succeeded' | 'failed';
export const NOTEBOOK_CELL_EXECUTION_STATE = new RawContextKey<NotebookCellExecutionStateContext>('notebookCellExecutionState', undefined);
export const NOTEBOOK_CELL_HAS_OUTPUTS = new RawContextKey<boolean>('notebookCellHasOutputs', false); // bool
@@ -248,6 +249,7 @@ export interface ICellViewModel extends IGenericCellViewModel {
language: string;
cellKind: CellKind;
editState: CellEditState;
lineNumbers: 'on' | 'off' | 'inherit';
focusMode: CellFocusMode;
outputIsHovered: boolean;
getText(): string;
@@ -823,6 +825,7 @@ export interface CellViewModelStateChangeEvent {
readonly outputIsHoveredChanged?: boolean;
readonly outputIsFocusedChanged?: boolean;
readonly cellIsHoveredChanged?: boolean;
readonly cellLineNumberChanged?: boolean;
}
export function cellRangesEqual(a: ICellRange[], b: ICellRange[]) {
@@ -9,6 +9,7 @@ import { Emitter, Event } from 'vs/base/common/event';
import { DisposableStore } from 'vs/base/common/lifecycle';
import 'vs/css!./media/notebook';
import { localize } from 'vs/nls';
import { extname } from 'vs/base/common/resources';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IEditorOptions, ITextEditorOptions, EditorOverride } from 'vs/platform/editor/common/editor';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -130,7 +131,7 @@ export class NotebookEditor extends EditorPane {
}
async setInput(input: NotebookEditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise<void> {
const startTime = Date.now();
const group = this.group!;
this._saveEditorViewState(this.input);
@@ -155,6 +156,7 @@ export class NotebookEditor extends EditorPane {
await super.setInput(input, options, context, token);
const model = await input.resolve();
const inputResolveTime = Date.now() - startTime;
// Check for cancellation
if (token.isCancellationRequested) {
return undefined;
@@ -188,6 +190,30 @@ export class NotebookEditor extends EditorPane {
this._widgetDisposableStore.add(this._editorDropService.createEditorDropTarget(this._widget.value!.getDomNode(), {
containsGroup: (group) => this.group?.id === group.group.id
}));
type WorkbenchNotebookOpenClassification = {
scheme: { classification: 'SystemMetaData', purpose: 'FeatureInsight'; };
ext: { classification: 'SystemMetaData', purpose: 'FeatureInsight'; };
viewType: { classification: 'SystemMetaData', purpose: 'FeatureInsight'; };
loadInput: { classification: 'SystemMetaData', purpose: 'FeatureInsight'; };
loadEditor: { classification: 'SystemMetaData', purpose: 'FeatureInsight'; };
};
type WorkbenchNotebookOpenEvent = {
scheme: string;
ext: string;
viewType: string;
loadInput: number;
loadEditor: number;
};
this.telemetryService.publicLog2<WorkbenchNotebookOpenEvent, WorkbenchNotebookOpenClassification>('notebook/editorOpenPerf', {
scheme: model.notebook.uri.scheme,
ext: extname(model.notebook.uri),
viewType: model.notebook.viewType,
loadInput: inputResolveTime,
loadEditor: Date.now() - startTime,
});
}
clearInput(): void {
@@ -5,7 +5,7 @@
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { INotebookTextModel, NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { NOTEBOOK_CELL_TYPE, NOTEBOOK_VIEW_TYPE, NOTEBOOK_CELL_EDITABLE, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_EXECUTION_STATE, NOTEBOOK_CELL_HAS_OUTPUTS, CellViewModelStateChangeEvent, CellEditState, NOTEBOOK_CELL_INPUT_COLLAPSED, NOTEBOOK_CELL_OUTPUT_COLLAPSED, NOTEBOOK_CELL_FOCUSED, INotebookEditor, NOTEBOOK_CELL_EDITOR_FOCUSED, CellFocusMode, NotebookCellExecutionStateContext } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { NOTEBOOK_CELL_TYPE, NOTEBOOK_VIEW_TYPE, NOTEBOOK_CELL_EDITABLE, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_EXECUTION_STATE, NOTEBOOK_CELL_HAS_OUTPUTS, CellViewModelStateChangeEvent, CellEditState, NOTEBOOK_CELL_INPUT_COLLAPSED, NOTEBOOK_CELL_OUTPUT_COLLAPSED, NOTEBOOK_CELL_FOCUSED, INotebookEditor, NOTEBOOK_CELL_EDITOR_FOCUSED, CellFocusMode, NotebookCellExecutionStateContext, NOTEBOOK_CELL_LINE_NUMBERS } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
@@ -21,6 +21,7 @@ export class CellContextKeyManager extends Disposable {
private cellHasOutputs!: IContextKey<boolean>;
private cellContentCollapsed!: IContextKey<boolean>;
private cellOutputCollapsed!: IContextKey<boolean>;
private cellLineNumbers!: IContextKey<'on' | 'off' | 'inherit'>;
private markdownEditMode!: IContextKey<boolean>;
@@ -45,6 +46,7 @@ export class CellContextKeyManager extends Disposable {
this.cellHasOutputs = NOTEBOOK_CELL_HAS_OUTPUTS.bindTo(this.contextKeyService);
this.cellContentCollapsed = NOTEBOOK_CELL_INPUT_COLLAPSED.bindTo(this.contextKeyService);
this.cellOutputCollapsed = NOTEBOOK_CELL_OUTPUT_COLLAPSED.bindTo(this.contextKeyService);
this.cellLineNumbers = NOTEBOOK_CELL_LINE_NUMBERS.bindTo(this.contextKeyService);
this.updateForElement(element);
});
@@ -76,6 +78,7 @@ export class CellContextKeyManager extends Disposable {
this.updateForOutputs();
this.viewType.set(this.element.viewType);
this.cellLineNumbers.set(this.element.lineNumbers);
});
}
@@ -93,6 +96,10 @@ export class CellContextKeyManager extends Disposable {
this.updateForFocusState();
}
if (e.cellLineNumberChanged) {
this.cellLineNumbers.set(this.element.lineNumbers);
}
// if (e.collapseStateChanged) {
// this.updateForCollapseState();
// }
@@ -0,0 +1,221 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Emitter, Event } from 'vs/base/common/event';
import { IDisposable } from 'vs/base/common/lifecycle';
import { deepClone } from 'vs/base/common/objects';
import { Registry } from 'vs/platform/registry/common/platform';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
import { IEditorOptions, LineNumbersType } from 'vs/editor/common/config/editorOptions';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { EDITOR_BOTTOM_PADDING, EDITOR_BOTTOM_PADDING_WITHOUT_STATUSBAR } from 'vs/workbench/contrib/notebook/browser/constants';
import { EditorTopPaddingChangeEvent, getEditorTopPadding, getNotebookEditorFromEditorPane, ICellViewModel, NOTEBOOK_CELL_LINE_NUMBERS, NOTEBOOK_EDITOR_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { ShowCellStatusBarKey } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { localize } from 'vs/nls';
import { Action2, MenuId, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { NOTEBOOK_ACTIONS_CATEGORY } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions';
export class CellEditorOptions {
private static fixedEditorOptions: IEditorOptions = {
scrollBeyondLastLine: false,
scrollbar: {
verticalScrollbarSize: 14,
horizontal: 'auto',
useShadows: true,
verticalHasArrows: false,
horizontalHasArrows: false,
alwaysConsumeMouseWheel: false
},
renderLineHighlightOnlyWhenFocus: true,
overviewRulerLanes: 0,
selectOnLineNumbers: false,
lineNumbers: 'off',
lineDecorationsWidth: 0,
glyphMargin: false,
fixedOverflowWidgets: true,
minimap: { enabled: false },
renderValidationDecorations: 'on'
};
private _value: IEditorOptions;
private _lineNumbers: 'on' | 'off' | 'inherit' = 'inherit';
private disposable: IDisposable;
private readonly _onDidChange = new Emitter<IEditorOptions>();
readonly onDidChange: Event<IEditorOptions> = this._onDidChange.event;
constructor(readonly configurationService: IConfigurationService, language: string) {
this.disposable = configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('editor') || e.affectsConfiguration('notebook') || e.affectsConfiguration(ShowCellStatusBarKey)) {
this._value = computeEditorOptions();
this._onDidChange.fire(this.value);
}
});
EditorTopPaddingChangeEvent(() => {
this._value = computeEditorOptions();
this._onDidChange.fire(this.value);
});
const computeEditorOptions = () => {
const showCellStatusBar = configurationService.getValue<boolean>(ShowCellStatusBarKey);
const editorPadding = {
top: getEditorTopPadding(),
bottom: showCellStatusBar ? EDITOR_BOTTOM_PADDING : EDITOR_BOTTOM_PADDING_WITHOUT_STATUSBAR
};
const renderLiNumbers = configurationService.getValue<'on' | 'off'>('notebook.lineNumbers') === 'on';
const lineNumbers: LineNumbersType = renderLiNumbers ? 'on' : 'off';
const editorOptions = deepClone(configurationService.getValue<IEditorOptions>('editor', { overrideIdentifier: language }));
const computed = {
...editorOptions,
...CellEditorOptions.fixedEditorOptions,
...{ padding: editorPadding, lineNumbers },
};
if (!computed.folding) {
computed.lineDecorationsWidth = 16;
}
return computed;
};
this._value = computeEditorOptions();
}
dispose(): void {
this._onDidChange.dispose();
this.disposable.dispose();
}
get value(): IEditorOptions {
return this._value;
}
setGlyphMargin(gm: boolean): void {
if (gm !== this._value.glyphMargin) {
this._value.glyphMargin = gm;
this._onDidChange.fire(this.value);
}
}
setLineNumbers(lineNumbers: 'on' | 'off' | 'inherit'): void {
this._lineNumbers = lineNumbers;
if (this._lineNumbers === 'inherit') {
const renderLiNumbers = this.configurationService.getValue<'on' | 'off'>('notebook.lineNumbers') === 'on';
const lineNumbers: LineNumbersType = renderLiNumbers ? 'on' : 'off';
this._value.lineNumbers = lineNumbers;
} else {
this._value.lineNumbers = lineNumbers as LineNumbersType;
}
this._onDidChange.fire(this.value);
}
}
Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).registerConfiguration({
id: 'notebook',
order: 100,
type: 'object',
'properties': {
'notebook.lineNumbers': {
type: 'string',
enum: ['off', 'on'],
default: 'off',
markdownDescription: localize('notebook.lineNumbers', "Controls the display of line numbers in the cell editor.")
}
}
});
registerAction2(class ToggleLineNumberAction extends Action2 {
constructor() {
super({
id: 'notebook.toggleLineNumbers',
title: { value: localize('notebook.showLineNumbers', "Show Notebook Line Numbers"), original: 'Toggle Notebook Line Numbers' },
precondition: NOTEBOOK_EDITOR_FOCUSED,
menu: [{
id: MenuId.EditorTitle,
group: 'LineNumber',
order: 0
}],
category: NOTEBOOK_ACTIONS_CATEGORY,
f1: false,
toggled: ContextKeyExpr.notEquals('config.notebook.lineNumbers', 'off')
});
}
async run(accessor: ServicesAccessor): Promise<void> {
const configurationService = accessor.get(IConfigurationService);
const renderLiNumbers = configurationService.getValue<'on' | 'off'>('notebook.lineNumbers') === 'on';
if (renderLiNumbers) {
configurationService.updateValue('notebook.lineNumbers', 'off');
} else {
configurationService.updateValue('notebook.lineNumbers', 'on');
}
}
});
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
command: {
id: 'notebook.toggleLineNumbers',
title: { value: localize('notebook.toggleLineNumbers', "Toggle Notebook Line Numbers"), original: 'Toggle Notebook Line Numbers' }
}
});
registerAction2(class ToggleActiveLineNumberAction extends Action2 {
constructor() {
super({
id: 'notebook.cell.toggleLineNumbers',
title: 'Show Cell Line Numbers',
precondition: NOTEBOOK_EDITOR_FOCUSED,
menu: [{
id: MenuId.NotebookCellTitle,
group: 'LineNumber',
order: 1
}],
toggled: ContextKeyExpr.or(
NOTEBOOK_CELL_LINE_NUMBERS.isEqualTo('on'),
ContextKeyExpr.and(NOTEBOOK_CELL_LINE_NUMBERS.isEqualTo('inherit'), ContextKeyExpr.equals('config.notebook.lineNumbers', 'on'))
)
});
}
async run(accessor: ServicesAccessor, context?: { cell: ICellViewModel; }): Promise<void> {
let cell = context?.cell;
if (!cell) {
const editor = getNotebookEditorFromEditorPane(accessor.get(IEditorService).activeEditorPane);
if (!editor || !editor.hasModel()) {
return;
}
cell = editor.getActiveCell();
}
if (cell) {
const configurationService = accessor.get(IConfigurationService);
const renderLineNumbers = configurationService.getValue<'on' | 'off'>('notebook.lineNumbers') === 'on';
const cellLineNumbers = cell.lineNumbers;
// 'on', 'inherit' -> 'on'
// 'on', 'off' -> 'off'
// 'on', 'on' -> 'on'
// 'off', 'inherit' -> 'off'
// 'off', 'off' -> 'off'
// 'off', 'on' -> 'on'
const currentLineNumberIsOn = cellLineNumbers === 'on' || (cellLineNumbers === 'inherit' && renderLineNumbers);
if (currentLineNumberIsOn) {
cell.lineNumbers = 'off';
} else {
cell.lineNumbers = 'on';
}
}
}
});
@@ -14,9 +14,7 @@ import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
import { IAction } from 'vs/base/common/actions';
import { Color } from 'vs/base/common/color';
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { deepClone } from 'vs/base/common/objects';
import * as platform from 'vs/base/common/platform';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
@@ -37,9 +35,9 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { BOTTOM_CELL_TOOLBAR_GAP, CELL_BOTTOM_MARGIN, CELL_TOP_MARGIN, EDITOR_BOTTOM_PADDING, EDITOR_BOTTOM_PADDING_WITHOUT_STATUSBAR, EDITOR_TOOLBAR_HEIGHT } from 'vs/workbench/contrib/notebook/browser/constants';
import { DeleteCellAction, INotebookCellActionContext } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions';
import { BaseCellRenderTemplate, CellEditState, CodeCellLayoutInfo, CodeCellRenderTemplate, EditorTopPaddingChangeEvent, EXPAND_CELL_INPUT_COMMAND_ID, getEditorTopPadding, ICellViewModel, INotebookEditor, isCodeCellRenderTemplate, MarkdownCellRenderTemplate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { BOTTOM_CELL_TOOLBAR_GAP, CELL_BOTTOM_MARGIN, CELL_TOP_MARGIN, EDITOR_TOOLBAR_HEIGHT } from 'vs/workbench/contrib/notebook/browser/constants';
import { DeleteCellAction, INotebookActionContext, INotebookCellActionContext } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions';
import { BaseCellRenderTemplate, CellEditState, CodeCellLayoutInfo, CodeCellRenderTemplate, EXPAND_CELL_INPUT_COMMAND_ID, ICellViewModel, INotebookEditor, isCodeCellRenderTemplate, MarkdownCellRenderTemplate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellContextKeyManager } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellContextKeys';
import { CellDragAndDropController, DRAGGING_CLASS } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellDnd';
import { CellMenus } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellMenus';
@@ -49,11 +47,12 @@ import { StatefulMarkdownCell } from 'vs/workbench/contrib/notebook/browser/view
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel';
import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
import { CellEditType, CellKind, NotebookCellMetadata, NotebookCellExecutionState, NotebookCellsChangeType, ShowCellStatusBarKey } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellEditType, CellKind, NotebookCellMetadata, NotebookCellExecutionState, NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CodiconActionViewItem, createAndFillInActionBarActionsWithVerticalSeparators, VerticalSeparator, VerticalSeparatorViewItem } from './cellActionView';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { errorStateIcon, successStateIcon, unfoldIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons';
import { syncing } from 'vs/platform/theme/common/iconRegistry';
import { CellEditorOptions } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellEditorOptions';
const $ = DOM.$;
@@ -84,91 +83,6 @@ export class NotebookCellListDelegate implements IListVirtualDelegate<CellViewMo
}
}
export class CellEditorOptions {
private static fixedEditorOptions: IEditorOptions = {
scrollBeyondLastLine: false,
scrollbar: {
verticalScrollbarSize: 14,
horizontal: 'auto',
useShadows: true,
verticalHasArrows: false,
horizontalHasArrows: false,
alwaysConsumeMouseWheel: false
},
renderLineHighlightOnlyWhenFocus: true,
overviewRulerLanes: 0,
selectOnLineNumbers: false,
lineNumbers: 'off',
lineDecorationsWidth: 0,
glyphMargin: false,
fixedOverflowWidgets: true,
minimap: { enabled: false },
renderValidationDecorations: 'on'
};
private _value: IEditorOptions;
private disposable: IDisposable;
private readonly _onDidChange = new Emitter<IEditorOptions>();
readonly onDidChange: Event<IEditorOptions> = this._onDidChange.event;
constructor(configurationService: IConfigurationService, language: string) {
this.disposable = configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('editor') || e.affectsConfiguration(ShowCellStatusBarKey)) {
this._value = computeEditorOptions();
this._onDidChange.fire(this.value);
}
});
EditorTopPaddingChangeEvent(() => {
this._value = computeEditorOptions();
this._onDidChange.fire(this.value);
});
const computeEditorOptions = () => {
const showCellStatusBar = configurationService.getValue<boolean>(ShowCellStatusBarKey);
const editorPadding = {
top: getEditorTopPadding(),
bottom: showCellStatusBar ? EDITOR_BOTTOM_PADDING : EDITOR_BOTTOM_PADDING_WITHOUT_STATUSBAR
};
const editorOptions = deepClone(configurationService.getValue<IEditorOptions>('editor', { overrideIdentifier: language }));
const computed = {
...editorOptions,
...CellEditorOptions.fixedEditorOptions,
...{ padding: editorPadding }
};
if (!computed.folding) {
computed.lineDecorationsWidth = 16;
}
return computed;
};
this._value = computeEditorOptions();
}
dispose(): void {
this._onDidChange.dispose();
this.disposable.dispose();
}
get value(): IEditorOptions {
return this._value;
}
setGlyphMargin(gm: boolean): void {
if (gm !== this._value.glyphMargin) {
this._value.glyphMargin = gm;
this._onDidChange.fire(this.value);
}
}
}
abstract class AbstractCellRenderer {
protected readonly editorOptions: CellEditorOptions;
protected readonly cellMenus: CellMenus;
@@ -552,6 +466,10 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
}));
this.updateForHover(element, templateData);
const cellEditorOptions = new CellEditorOptions(this.configurationService, 'markdown');
cellEditorOptions.setLineNumbers(element.lineNumbers);
elementDisposables.add(cellEditorOptions);
elementDisposables.add(element.onDidChangeState(e => {
if (e.cellIsHoveredChanged) {
this.updateForHover(element, templateData);
@@ -560,6 +478,10 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
if (e.metadataChanged) {
this.updateCollapsedState(element);
}
if (e.cellLineNumberChanged) {
cellEditorOptions.setLineNumbers(element.lineNumbers);
}
}));
// render toolbar first
@@ -578,10 +500,8 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
const scopedInstaService = this.instantiationService.createChild(new ServiceCollection([IContextKeyService, templateData.contextKeyService]));
const markdownCell = scopedInstaService.createInstance(StatefulMarkdownCell, this.notebookEditor, element, templateData, this.editorOptions.value, this.renderedEditors, { useRenderer: templateData.useRenderer });
const cellEditorOptions = new CellEditorOptions(this.configurationService, 'markdown');
elementDisposables.add(cellEditorOptions);
elementDisposables.add(cellEditorOptions.onDidChange(newValue => markdownCell.updateEditorOptions(newValue)));
elementDisposables.add(markdownCell);
elementDisposables.add(cellEditorOptions.onDidChange(newValue => markdownCell.updateEditorOptions(newValue)));
templateData.statusBar.update(toolbarContext);
}
@@ -1033,6 +953,7 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
this.updateForMetadata(element, templateData, cellEditorOptions);
this.updateForHover(element, templateData);
this.updateForFocus(element, templateData);
cellEditorOptions.setLineNumbers(element.lineNumbers);
elementDisposables.add(element.onDidChangeState((e) => {
if (e.metadataChanged) {
this.updateForMetadata(element, templateData, cellEditorOptions);
@@ -1045,6 +966,10 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
if (e.outputIsFocusedChanged) {
this.updateForFocus(element, templateData);
}
if (e.cellLineNumberChanged) {
cellEditorOptions.setLineNumbers(element.lineNumbers);
}
}));
elementDisposables.add(this.notebookEditor.viewModel.notebookDocument.onDidChangeContent(e => {
if (e.rawEvents.find(event => event.kind === NotebookCellsChangeType.ChangeDocumentMetadata)) {
@@ -1229,6 +1154,9 @@ export class ListTopCellToolbar extends Disposable {
return undefined;
}
}));
this.toolbar.context = <INotebookActionContext>{
notebookEditor
};
const cellMenu = this.instantiationService.createInstance(CellMenus);
this.menu = this._register(cellMenu.getCellTopInsertionMenu(contextKeyService));
@@ -63,6 +63,20 @@ export abstract class BaseCellViewModel extends Disposable {
}
}
private _lineNumbers: 'on' | 'off' | 'inherit' = 'inherit';
get lineNumbers(): 'on' | 'off' | 'inherit' {
return this._lineNumbers;
}
set lineNumbers(lineNumbers: 'on' | 'off' | 'inherit') {
if (lineNumbers === this._lineNumbers) {
return;
}
this._lineNumbers = lineNumbers;
this._onDidChangeState.fire({ cellLineNumberChanged: true });
}
private _focusMode: CellFocusMode = CellFocusMode.Container;
get focusMode() {
return this._focusMode;
@@ -122,6 +136,10 @@ export abstract class BaseCellViewModel extends Disposable {
if (e.affectsConfiguration(ShowCellStatusBarKey)) {
this.layoutChange({});
}
if (e.affectsConfiguration('notebook.lineNumbers')) {
this.lineNumbers = 'inherit';
}
}));
}
@@ -15,7 +15,7 @@ export interface INotebookEditorModelResolverService {
readonly _serviceBrand: undefined;
readonly onDidSaveNotebook: Event<URI>;
readonly onDidChangeDirty: Event<{ resource: URI, isDirty: boolean }>;
readonly onDidChangeDirty: Event<IResolvedNotebookEditorModel>;
isDirty(resource: URI): boolean;
@@ -26,8 +26,8 @@ class NotebookModelReferenceCollection extends ReferenceCollection<Promise<IReso
private readonly _onDidSaveNotebook = new Emitter<URI>();
readonly onDidSaveNotebook: Event<URI> = this._onDidSaveNotebook.event;
private readonly _onDidChangeDirty = new Emitter<{ resource: URI, isDirty: boolean }>();
readonly onDidChangeDirty: Event<{ resource: URI, isDirty: boolean }> = this._onDidChangeDirty.event;
private readonly _onDidChangeDirty = new Emitter<IResolvedNotebookEditorModel>();
readonly onDidChangeDirty: Event<IResolvedNotebookEditorModel> = this._onDidChangeDirty.event;
private readonly _dirtyStates = new ResourceMap<boolean>();
@@ -78,7 +78,7 @@ class NotebookModelReferenceCollection extends ReferenceCollection<Promise<IReso
result.onDidChangeDirty(() => {
const isDirty = result.isDirty();
this._dirtyStates.set(result.resource, isDirty);
this._onDidChangeDirty.fire({ resource: result.resource, isDirty });
this._onDidChangeDirty.fire(result);
}),
));
return result;
@@ -102,7 +102,7 @@ export class NotebookModelResolverServiceImpl implements INotebookEditorModelRes
private readonly _data: NotebookModelReferenceCollection;
readonly onDidSaveNotebook: Event<URI>;
readonly onDidChangeDirty: Event<{ resource: URI, isDirty: boolean }>;
readonly onDidChangeDirty: Event<IResolvedNotebookEditorModel>;
constructor(
@IInstantiationService instantiationService: IInstantiationService,
@@ -100,9 +100,9 @@ suite('NotebookCell#Document', function () {
test('cell document is vscode.TextDocument', async function () {
assert.strictEqual(notebook.notebookDocument.cells.length, 2);
assert.strictEqual(notebook.notebookDocument.cellCount, 2);
const [c1, c2] = notebook.notebookDocument.cells;
const [c1, c2] = notebook.notebookDocument.getCells();
const d1 = extHostDocuments.getDocument(c1.document.uri);
assert.ok(d1);
@@ -119,7 +119,7 @@ suite('NotebookCell#Document', function () {
test('cell document goes when notebook closes', async function () {
const cellUris: string[] = [];
for (let cell of notebook.notebookDocument.cells) {
for (let cell of notebook.notebookDocument.getCells()) {
assert.ok(extHostDocuments.getDocument(cell.document.uri));
cellUris.push(cell.document.uri.toString());
}
@@ -196,7 +196,7 @@ suite('NotebookCell#Document', function () {
const docs: vscode.TextDocument[] = [];
const addData: IModelAddedData[] = [];
for (let cell of notebook.notebookDocument.cells) {
for (let cell of notebook.notebookDocument.getCells()) {
const doc = extHostDocuments.getDocument(cell.document.uri);
assert.ok(doc);
assert.strictEqual(extHostDocuments.getDocument(cell.document.uri).isClosed, false);
@@ -218,14 +218,14 @@ suite('NotebookCell#Document', function () {
extHostDocumentsAndEditors.$acceptDocumentsAndEditorsDelta({ removedDocuments: docs.map(d => d.uri) });
// notebook is still open -> cell documents stay open
for (let cell of notebook.notebookDocument.cells) {
for (let cell of notebook.notebookDocument.getCells()) {
assert.ok(extHostDocuments.getDocument(cell.document.uri));
assert.strictEqual(extHostDocuments.getDocument(cell.document.uri).isClosed, false);
}
// close notebook -> docs are closed
extHostNotebooks.$acceptDocumentAndEditorsDelta({ removedDocuments: [notebook.uri] });
for (let cell of notebook.notebookDocument.cells) {
for (let cell of notebook.notebookDocument.getCells()) {
assert.throws(() => extHostDocuments.getDocument(cell.document.uri));
}
for (let doc of docs) {
@@ -235,8 +235,8 @@ suite('NotebookCell#Document', function () {
test('cell document goes when cell is removed', async function () {
assert.strictEqual(notebook.notebookDocument.cells.length, 2);
const [cell1, cell2] = notebook.notebookDocument.cells;
assert.strictEqual(notebook.notebookDocument.cellCount, 2);
const [cell1, cell2] = notebook.notebookDocument.getCells();
extHostNotebooks.$acceptModelChanged(notebook.uri, {
versionId: 2,
@@ -248,7 +248,7 @@ suite('NotebookCell#Document', function () {
]
}, false);
assert.strictEqual(notebook.notebookDocument.cells.length, 1);
assert.strictEqual(notebook.notebookDocument.cellCount, 1);
assert.strictEqual(cell1.document.isClosed, true); // ref still alive!
assert.strictEqual(cell2.document.isClosed, false);
@@ -256,15 +256,15 @@ suite('NotebookCell#Document', function () {
});
test('cell document knows notebook', function () {
for (let cells of notebook.notebookDocument.cells) {
for (let cells of notebook.notebookDocument.getCells()) {
assert.strictEqual(cells.document.notebook === notebook.notebookDocument, true);
}
});
test('cell#index', function () {
assert.strictEqual(notebook.notebookDocument.cells.length, 2);
const [first, second] = notebook.notebookDocument.cells;
assert.strictEqual(notebook.notebookDocument.cellCount, 2);
const [first, second] = notebook.notebookDocument.getCells();
assert.strictEqual(first.index, 0);
assert.strictEqual(second.index, 1);
@@ -277,7 +277,7 @@ suite('NotebookCell#Document', function () {
}]
}, false);
assert.strictEqual(notebook.notebookDocument.cells.length, 1);
assert.strictEqual(notebook.notebookDocument.cellCount, 1);
assert.strictEqual(second.index, 0);
extHostNotebooks.$acceptModelChanged(notebookUri, {
@@ -304,7 +304,7 @@ suite('NotebookCell#Document', function () {
}]
}, false);
assert.strictEqual(notebook.notebookDocument.cells.length, 3);
assert.strictEqual(notebook.notebookDocument.cellCount, 3);
assert.strictEqual(second.index, 2);
});
@@ -313,7 +313,7 @@ suite('NotebookCell#Document', function () {
const p = Event.toPromise(extHostNotebooks.onDidChangeNotebookCells);
// DON'T call this, make sure the cell-documents have not been created yet
// assert.strictEqual(notebook.notebookDocument.cells.length, 2);
// assert.strictEqual(notebook.notebookDocument.cellCount, 2);
extHostNotebooks.$acceptModelChanged(notebook.uri, {
versionId: 100,
@@ -339,7 +339,7 @@ suite('NotebookCell#Document', function () {
}]
}, false);
assert.strictEqual(notebook.notebookDocument.cells.length, 2);
assert.strictEqual(notebook.notebookDocument.cellCount, 2);
const event = await p;
@@ -391,7 +391,7 @@ suite('NotebookCell#Document', function () {
test('change cell language triggers onDidChange events', async function () {
const [first] = notebook.notebookDocument.cells;
const first = notebook.notebookDocument.cellAt(0);
assert.strictEqual(first.document.languageId, 'markdown');
@@ -150,7 +150,7 @@ suite('NotebookConcatDocument', function () {
}, false);
assert.strictEqual(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code
assert.strictEqual(notebook.notebookDocument.cellCount, 1 + 2); // markdown and code
let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.notebookDocument, undefined);
@@ -188,16 +188,16 @@ suite('NotebookConcatDocument', function () {
}, false);
assert.strictEqual(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code
assert.strictEqual(notebook.notebookDocument.cellCount, 1 + 2); // markdown and code
let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.notebookDocument, undefined);
assertLines(doc, 'Hello', 'World', 'Hello World!', 'Hallo', 'Welt', 'Hallo Welt!');
assertLocation(doc, new Position(0, 0), new Location(notebook.notebookDocument.cells[0].document.uri, new Position(0, 0)));
assertLocation(doc, new Position(4, 0), new Location(notebook.notebookDocument.cells[1].document.uri, new Position(1, 0)));
assertLocation(doc, new Position(4, 3), new Location(notebook.notebookDocument.cells[1].document.uri, new Position(1, 3)));
assertLocation(doc, new Position(5, 11), new Location(notebook.notebookDocument.cells[1].document.uri, new Position(2, 11)));
assertLocation(doc, new Position(5, 12), new Location(notebook.notebookDocument.cells[1].document.uri, new Position(2, 11)), false); // don't check identity because position will be clamped
assertLocation(doc, new Position(0, 0), new Location(notebook.notebookDocument.cellAt(0).document.uri, new Position(0, 0)));
assertLocation(doc, new Position(4, 0), new Location(notebook.notebookDocument.cellAt(1).document.uri, new Position(1, 0)));
assertLocation(doc, new Position(4, 3), new Location(notebook.notebookDocument.cellAt(1).document.uri, new Position(1, 3)));
assertLocation(doc, new Position(5, 11), new Location(notebook.notebookDocument.cellAt(1).document.uri, new Position(2, 11)));
assertLocation(doc, new Position(5, 12), new Location(notebook.notebookDocument.cellAt(1).document.uri, new Position(2, 11)), false); // don't check identity because position will be clamped
});
@@ -223,13 +223,13 @@ suite('NotebookConcatDocument', function () {
}
]
}, false);
assert.strictEqual(notebook.notebookDocument.cells.length, 1 + 1);
assert.strictEqual(notebook.notebookDocument.cellCount, 1 + 1);
assert.strictEqual(doc.version, 1);
assertLines(doc, 'Hello', 'World', 'Hello World!');
assertLocation(doc, new Position(0, 0), new Location(notebook.notebookDocument.cells[0].document.uri, new Position(0, 0)));
assertLocation(doc, new Position(2, 2), new Location(notebook.notebookDocument.cells[0].document.uri, new Position(2, 2)));
assertLocation(doc, new Position(4, 0), new Location(notebook.notebookDocument.cells[0].document.uri, new Position(2, 12)), false); // clamped
assertLocation(doc, new Position(0, 0), new Location(notebook.notebookDocument.cellAt(0).document.uri, new Position(0, 0)));
assertLocation(doc, new Position(2, 2), new Location(notebook.notebookDocument.cellAt(0).document.uri, new Position(2, 2)));
assertLocation(doc, new Position(4, 0), new Location(notebook.notebookDocument.cellAt(0).document.uri, new Position(2, 12)), false); // clamped
// UPDATE 2
@@ -251,14 +251,14 @@ suite('NotebookConcatDocument', function () {
]
}, false);
assert.strictEqual(notebook.notebookDocument.cells.length, 1 + 2);
assert.strictEqual(notebook.notebookDocument.cellCount, 1 + 2);
assert.strictEqual(doc.version, 2);
assertLines(doc, 'Hello', 'World', 'Hello World!', 'Hallo', 'Welt', 'Hallo Welt!');
assertLocation(doc, new Position(0, 0), new Location(notebook.notebookDocument.cells[0].document.uri, new Position(0, 0)));
assertLocation(doc, new Position(4, 0), new Location(notebook.notebookDocument.cells[1].document.uri, new Position(1, 0)));
assertLocation(doc, new Position(4, 3), new Location(notebook.notebookDocument.cells[1].document.uri, new Position(1, 3)));
assertLocation(doc, new Position(5, 11), new Location(notebook.notebookDocument.cells[1].document.uri, new Position(2, 11)));
assertLocation(doc, new Position(5, 12), new Location(notebook.notebookDocument.cells[1].document.uri, new Position(2, 11)), false); // don't check identity because position will be clamped
assertLocation(doc, new Position(0, 0), new Location(notebook.notebookDocument.cellAt(0).document.uri, new Position(0, 0)));
assertLocation(doc, new Position(4, 0), new Location(notebook.notebookDocument.cellAt(1).document.uri, new Position(1, 0)));
assertLocation(doc, new Position(4, 3), new Location(notebook.notebookDocument.cellAt(1).document.uri, new Position(1, 3)));
assertLocation(doc, new Position(5, 11), new Location(notebook.notebookDocument.cellAt(1).document.uri, new Position(2, 11)));
assertLocation(doc, new Position(5, 12), new Location(notebook.notebookDocument.cellAt(1).document.uri, new Position(2, 11)), false); // don't check identity because position will be clamped
// UPDATE 3 (remove cell #2 again)
extHostNotebooks.$acceptModelChanged(notebookUri, {
@@ -270,12 +270,12 @@ suite('NotebookConcatDocument', function () {
}
]
}, false);
assert.strictEqual(notebook.notebookDocument.cells.length, 1 + 1);
assert.strictEqual(notebook.notebookDocument.cellCount, 1 + 1);
assert.strictEqual(doc.version, 3);
assertLines(doc, 'Hello', 'World', 'Hello World!');
assertLocation(doc, new Position(0, 0), new Location(notebook.notebookDocument.cells[0].document.uri, new Position(0, 0)));
assertLocation(doc, new Position(2, 2), new Location(notebook.notebookDocument.cells[0].document.uri, new Position(2, 2)));
assertLocation(doc, new Position(4, 0), new Location(notebook.notebookDocument.cells[0].document.uri, new Position(2, 12)), false); // clamped
assertLocation(doc, new Position(0, 0), new Location(notebook.notebookDocument.cellAt(0).document.uri, new Position(0, 0)));
assertLocation(doc, new Position(2, 2), new Location(notebook.notebookDocument.cellAt(0).document.uri, new Position(2, 2)));
assertLocation(doc, new Position(4, 0), new Location(notebook.notebookDocument.cellAt(0).document.uri, new Position(2, 12)), false); // clamped
});
test('location, position mapping, cell-document changes', function () {
@@ -309,21 +309,21 @@ suite('NotebookConcatDocument', function () {
}
]
}, false);
assert.strictEqual(notebook.notebookDocument.cells.length, 1 + 2);
assert.strictEqual(notebook.notebookDocument.cellCount, 1 + 2);
assert.strictEqual(doc.version, 1);
assertLines(doc, 'Hello', 'World', 'Hello World!', 'Hallo', 'Welt', 'Hallo Welt!');
assertLocation(doc, new Position(0, 0), new Location(notebook.notebookDocument.cells[0].document.uri, new Position(0, 0)));
assertLocation(doc, new Position(2, 2), new Location(notebook.notebookDocument.cells[0].document.uri, new Position(2, 2)));
assertLocation(doc, new Position(2, 12), new Location(notebook.notebookDocument.cells[0].document.uri, new Position(2, 12)));
assertLocation(doc, new Position(4, 0), new Location(notebook.notebookDocument.cells[1].document.uri, new Position(1, 0)));
assertLocation(doc, new Position(4, 3), new Location(notebook.notebookDocument.cells[1].document.uri, new Position(1, 3)));
assertLocation(doc, new Position(0, 0), new Location(notebook.notebookDocument.cellAt(0).document.uri, new Position(0, 0)));
assertLocation(doc, new Position(2, 2), new Location(notebook.notebookDocument.cellAt(0).document.uri, new Position(2, 2)));
assertLocation(doc, new Position(2, 12), new Location(notebook.notebookDocument.cellAt(0).document.uri, new Position(2, 12)));
assertLocation(doc, new Position(4, 0), new Location(notebook.notebookDocument.cellAt(1).document.uri, new Position(1, 0)));
assertLocation(doc, new Position(4, 3), new Location(notebook.notebookDocument.cellAt(1).document.uri, new Position(1, 3)));
// offset math
let cell1End = doc.offsetAt(new Position(2, 12));
assert.strictEqual(doc.positionAt(cell1End).isEqual(new Position(2, 12)), true);
extHostDocuments.$acceptModelChanged(notebook.notebookDocument.cells[0].document.uri, {
extHostDocuments.$acceptModelChanged(notebook.notebookDocument.cellAt(0).document.uri, {
versionId: 0,
eol: '\n',
changes: [{
@@ -334,7 +334,7 @@ suite('NotebookConcatDocument', function () {
}]
}, false);
assertLines(doc, 'Hello', 'World', 'Hi World!', 'Hallo', 'Welt', 'Hallo Welt!');
assertLocation(doc, new Position(2, 12), new Location(notebook.notebookDocument.cells[0].document.uri, new Position(2, 9)), false);
assertLocation(doc, new Position(2, 12), new Location(notebook.notebookDocument.cellAt(0).document.uri, new Position(2, 9)), false);
assert.strictEqual(doc.positionAt(cell1End).isEqual(new Position(3, 2)), true);
@@ -440,7 +440,7 @@ suite('NotebookConcatDocument', function () {
]
}, false);
assert.strictEqual(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code
assert.strictEqual(notebook.notebookDocument.cellCount, 1 + 2); // markdown and code
let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.notebookDocument, undefined);
assertLines(doc, 'Hello', 'World', 'Hello World!', 'Hallo', 'Welt', 'Hallo Welt!');
@@ -497,17 +497,17 @@ suite('NotebookConcatDocument', function () {
]
}, false);
assert.strictEqual(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code
assert.strictEqual(notebook.notebookDocument.cellCount, 1 + 2); // markdown and code
let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.notebookDocument, undefined);
assertLines(doc, 'Hello', 'World', 'Hello World!', 'Hallo', 'Welt', 'Hallo Welt!');
assertLocationAtPosition(doc, { line: 0, character: 0 }, { uri: notebook.notebookDocument.cells[0].document.uri, line: 0, character: 0 });
assertLocationAtPosition(doc, { line: 2, character: 0 }, { uri: notebook.notebookDocument.cells[0].document.uri, line: 2, character: 0 });
assertLocationAtPosition(doc, { line: 2, character: 12 }, { uri: notebook.notebookDocument.cells[0].document.uri, line: 2, character: 12 });
assertLocationAtPosition(doc, { line: 3, character: 0 }, { uri: notebook.notebookDocument.cells[1].document.uri, line: 0, character: 0 });
assertLocationAtPosition(doc, { line: 5, character: 0 }, { uri: notebook.notebookDocument.cells[1].document.uri, line: 2, character: 0 });
assertLocationAtPosition(doc, { line: 5, character: 11 }, { uri: notebook.notebookDocument.cells[1].document.uri, line: 2, character: 11 });
assertLocationAtPosition(doc, { line: 0, character: 0 }, { uri: notebook.notebookDocument.cellAt(0).document.uri, line: 0, character: 0 });
assertLocationAtPosition(doc, { line: 2, character: 0 }, { uri: notebook.notebookDocument.cellAt(0).document.uri, line: 2, character: 0 });
assertLocationAtPosition(doc, { line: 2, character: 12 }, { uri: notebook.notebookDocument.cellAt(0).document.uri, line: 2, character: 12 });
assertLocationAtPosition(doc, { line: 3, character: 0 }, { uri: notebook.notebookDocument.cellAt(1).document.uri, line: 0, character: 0 });
assertLocationAtPosition(doc, { line: 5, character: 0 }, { uri: notebook.notebookDocument.cellAt(1).document.uri, line: 2, character: 0 });
assertLocationAtPosition(doc, { line: 5, character: 11 }, { uri: notebook.notebookDocument.cellAt(1).document.uri, line: 2, character: 11 });
});
test('getText(range)', function () {
@@ -538,7 +538,7 @@ suite('NotebookConcatDocument', function () {
]
}, false);
assert.strictEqual(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code
assert.strictEqual(notebook.notebookDocument.cellCount, 1 + 2); // markdown and code
let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.notebookDocument, undefined);
assertLines(doc, 'Hello', 'World', 'Hello World!', 'Hallo', 'Welt', 'Hallo Welt!');
@@ -576,7 +576,7 @@ suite('NotebookConcatDocument', function () {
]
}, false);
assert.strictEqual(notebook.notebookDocument.cells.length, 1 + 2); // markdown and code
assert.strictEqual(notebook.notebookDocument.cellCount, 1 + 2); // markdown and code
let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.notebookDocument, undefined);
assertLines(doc, 'Hello', 'World', 'Hello World!', 'Hallo', 'Welt', 'Hallo Welt!');