mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
Notebooks: Add Command + Keyboard Shortcut to Clear Outputs of Active Cell (#6169)
* Add command to clear cell output with test * Fix typo * PR Comments
This commit is contained in:
@@ -36,6 +36,10 @@ if (context.RunTest) {
|
|||||||
await (new NotebookTester()).sqlNbMultipleCellsTest(this.test.title);
|
await (new NotebookTester()).sqlNbMultipleCellsTest(this.test.title);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Clear cell output - SQL notebook', async function () {
|
||||||
|
await (new NotebookTester()).sqlNbClearOutputs(this.test.title);
|
||||||
|
});
|
||||||
|
|
||||||
test('Clear all outputs - SQL notebook ', async function () {
|
test('Clear all outputs - SQL notebook ', async function () {
|
||||||
await (new NotebookTester()).sqlNbClearAllOutputs(this.test.title);
|
await (new NotebookTester()).sqlNbClearAllOutputs(this.test.title);
|
||||||
});
|
});
|
||||||
@@ -133,6 +137,11 @@ class NotebookTester {
|
|||||||
await this.verifyClearAllOutputs(notebook);
|
await this.verifyClearAllOutputs(notebook);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async sqlNbClearOutputs(title: string): Promise<void> {
|
||||||
|
let notebook = await this.openNotebook(sqlNotebookContent, sqlKernelMetadata, title + this.invocationCount++);
|
||||||
|
await this.verifyClearOutputs(notebook);
|
||||||
|
}
|
||||||
|
|
||||||
@stressify({ dop: NotebookTester.ParallelCount })
|
@stressify({ dop: NotebookTester.ParallelCount })
|
||||||
async sqlNbMultipleCellsTest(title: string): Promise<void> {
|
async sqlNbMultipleCellsTest(title: string): Promise<void> {
|
||||||
let notebook = await this.openNotebook(sqlNotebookMultipleCellsContent, sqlKernelMetadata, title + this.invocationCount++, true);
|
let notebook = await this.openNotebook(sqlNotebookMultipleCellsContent, sqlKernelMetadata, title + this.invocationCount++, true);
|
||||||
@@ -380,15 +389,22 @@ class NotebookTester {
|
|||||||
assert(clearedOutputs, 'Outputs of all the code cells from Python notebook should be cleared');
|
assert(clearedOutputs, 'Outputs of all the code cells from Python notebook should be cleared');
|
||||||
console.log('After clearing cell outputs');
|
console.log('After clearing cell outputs');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async verifyClearOutputs(notebook: azdata.nb.NotebookEditor): Promise<void> {
|
||||||
|
let cellWithOutputs = notebook.document.cells[0].contents && notebook.document.cells[0].contents.outputs && notebook.document.cells[0].contents.outputs.length > 0;
|
||||||
|
assert(cellWithOutputs === true, 'Expected first cell to have outputs');
|
||||||
|
let clearedOutputs = await notebook.clearOutput(notebook.document.cells[0]);
|
||||||
|
let firstCell = notebook.document.cells[0];
|
||||||
|
assert(firstCell.contents && firstCell.contents.outputs && firstCell.contents.outputs.length === 0, `Expected Output: 0, Actual: '${firstCell.contents.outputs.length}'`);
|
||||||
|
assert(clearedOutputs, 'Outputs of requested code cell should be cleared');
|
||||||
|
}
|
||||||
|
|
||||||
async cellLanguageTest(content: azdata.nb.INotebookContents, testName: string, languageConfigured: string, metadataInfo: any) {
|
async cellLanguageTest(content: azdata.nb.INotebookContents, testName: string, languageConfigured: string, metadataInfo: any) {
|
||||||
let notebookJson = Object.assign({}, content, { metadata: metadataInfo });
|
let notebookJson = Object.assign({}, content, { metadata: metadataInfo });
|
||||||
let uri = writeNotebookToFile(notebookJson, testName);
|
let uri = writeNotebookToFile(notebookJson, testName);
|
||||||
console.log('Notebook uri ' + uri);
|
|
||||||
let notebook = await azdata.nb.showNotebookDocument(uri);
|
let notebook = await azdata.nb.showNotebookDocument(uri);
|
||||||
console.log('Notebook is opened');
|
|
||||||
await notebook.document.save();
|
await notebook.document.save();
|
||||||
let languageInNotebook = notebook.document.cells[0].contents.metadata.language;
|
let languageInNotebook = notebook.document.cells[0].contents.metadata.language;
|
||||||
console.log('Language set in cell: ' + languageInNotebook);
|
|
||||||
assert(languageInNotebook === languageConfigured, `Expected cell language is: ${languageConfigured}, Actual: ${languageInNotebook}`);
|
assert(languageInNotebook === languageConfigured, `Expected cell language is: ${languageConfigured}, Actual: ${languageInNotebook}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,10 @@
|
|||||||
"title": "%notebook.command.runactivecell%",
|
"title": "%notebook.command.runactivecell%",
|
||||||
"icon": "resources/dark/touchbar_run_cell.png"
|
"icon": "resources/dark/touchbar_run_cell.png"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "notebook.command.clearactivecellresult",
|
||||||
|
"title": "%notebook.command.clearactivecellresult%"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "notebook.command.runallcells",
|
"command": "notebook.command.runallcells",
|
||||||
"title": "%notebook.command.runallcells%"
|
"title": "%notebook.command.runallcells%"
|
||||||
@@ -155,6 +159,10 @@
|
|||||||
"command": "notebook.command.runactivecell",
|
"command": "notebook.command.runactivecell",
|
||||||
"when": "notebookEditorVisible"
|
"when": "notebookEditorVisible"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "notebook.command.clearactivecellresult",
|
||||||
|
"when": "notebookEditorVisible"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "notebook.command.runallcells",
|
"command": "notebook.command.runallcells",
|
||||||
"when": "notebookEditorVisible"
|
"when": "notebookEditorVisible"
|
||||||
@@ -234,6 +242,11 @@
|
|||||||
"key": "F5",
|
"key": "F5",
|
||||||
"when": "activeEditor == workbench.editor.notebookEditor"
|
"when": "activeEditor == workbench.editor.notebookEditor"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "notebook.command.clearactivecellresult",
|
||||||
|
"key": "Ctrl+Shift+R",
|
||||||
|
"when": "activeEditor == workbench.editor.notebookEditor"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "notebook.command.runallcells",
|
"command": "notebook.command.runallcells",
|
||||||
"key": "Ctrl+Shift+F5",
|
"key": "Ctrl+Shift+F5",
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
"notebook.command.open": "Open Notebook",
|
"notebook.command.open": "Open Notebook",
|
||||||
"notebook.analyzeJupyterNotebook": "Analyze in Notebook",
|
"notebook.analyzeJupyterNotebook": "Analyze in Notebook",
|
||||||
"notebook.command.runactivecell": "Run Cell",
|
"notebook.command.runactivecell": "Run Cell",
|
||||||
|
"notebook.command.clearactivecellresult": "Clear Cell Result",
|
||||||
"notebook.command.runallcells": "Run Cells",
|
"notebook.command.runallcells": "Run Cells",
|
||||||
"notebook.command.addcode": "Add Code Cell",
|
"notebook.command.addcode": "Add Code Cell",
|
||||||
"notebook.command.addtext": "Add Text Cell",
|
"notebook.command.addtext": "Add Text Cell",
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ export async function activate(extensionContext: vscode.ExtensionContext): Promi
|
|||||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.runallcells', () => {
|
extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.runallcells', () => {
|
||||||
runAllCells();
|
runAllCells();
|
||||||
}));
|
}));
|
||||||
|
extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.clearactivecellresult', () => {
|
||||||
|
clearActiveCellOutput();
|
||||||
|
}));
|
||||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.addcell', async () => {
|
extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.addcell', async () => {
|
||||||
let cellType: CellType;
|
let cellType: CellType;
|
||||||
try {
|
try {
|
||||||
@@ -152,6 +155,19 @@ async function runActiveCell(): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function clearActiveCellOutput(): Promise<void> {
|
||||||
|
try {
|
||||||
|
let notebook = azdata.nb.activeNotebookEditor;
|
||||||
|
if (notebook) {
|
||||||
|
await notebook.clearOutput();
|
||||||
|
} else {
|
||||||
|
throw new Error(noNotebookVisible);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
vscode.window.showErrorMessage(getErrorMessage(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function runAllCells(): Promise<void> {
|
async function runAllCells(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
let notebook = azdata.nb.activeNotebookEditor;
|
let notebook = azdata.nb.activeNotebookEditor;
|
||||||
|
|||||||
5
src/sql/azdata.proposed.d.ts
vendored
5
src/sql/azdata.proposed.d.ts
vendored
@@ -4418,6 +4418,11 @@ declare module 'azdata' {
|
|||||||
*/
|
*/
|
||||||
runAllCells(): Thenable<boolean>;
|
runAllCells(): Thenable<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the outputs of the active code cell in a notebook.
|
||||||
|
*/
|
||||||
|
clearOutput(cell?: NotebookCell): Thenable<boolean>;
|
||||||
|
|
||||||
/** Clears the outputs of all code cells in a Notebook
|
/** Clears the outputs of all code cells in a Notebook
|
||||||
* @return A promise that resolves with a value indicating if the outputs are cleared or not.
|
* @return A promise that resolves with a value indicating if the outputs are cleared or not.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -159,6 +159,11 @@ export class ExtHostNotebookEditor implements azdata.nb.NotebookEditor, IDisposa
|
|||||||
return this._proxy.$runAllCells(this._id);
|
return this._proxy.$runAllCells(this._id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public clearOutput(cell: azdata.nb.NotebookCell): Thenable<boolean> {
|
||||||
|
let uri = cell ? cell.uri : undefined;
|
||||||
|
return this._proxy.$clearOutput(this._id, uri);
|
||||||
|
}
|
||||||
|
|
||||||
public clearAllOutputs(): Thenable<boolean> {
|
public clearAllOutputs(): Thenable<boolean> {
|
||||||
return this._proxy.$clearAllOutputs(this._id);
|
return this._proxy.$clearAllOutputs(this._id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,6 +139,13 @@ class MainThreadNotebookEditor extends Disposable {
|
|||||||
return this.editor.runAllCells();
|
return this.editor.runAllCells();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public clearOutput(cell: ICellModel): Promise<boolean> {
|
||||||
|
if (!this.editor) {
|
||||||
|
return Promise.resolve(false);
|
||||||
|
}
|
||||||
|
return this.editor.clearOutput(cell);
|
||||||
|
}
|
||||||
|
|
||||||
public clearAllOutputs(): Promise<boolean> {
|
public clearAllOutputs(): Promise<boolean> {
|
||||||
if (!this.editor) {
|
if (!this.editor) {
|
||||||
return Promise.resolve(false);
|
return Promise.resolve(false);
|
||||||
@@ -384,6 +391,28 @@ export class MainThreadNotebookDocumentsAndEditors extends Disposable implements
|
|||||||
return editor.runAllCells();
|
return editor.runAllCells();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$clearOutput(id: string, cellUri: UriComponents): Promise<boolean> {
|
||||||
|
// Requires an editor and the matching cell in that editor
|
||||||
|
let editor = this.getEditor(id);
|
||||||
|
if (!editor) {
|
||||||
|
return Promise.reject(disposed(`TextEditor(${id})`));
|
||||||
|
}
|
||||||
|
let cell: ICellModel;
|
||||||
|
if (cellUri) {
|
||||||
|
let uriString = URI.revive(cellUri).toString();
|
||||||
|
cell = editor.cells.find(c => c.cellUri.toString() === uriString);
|
||||||
|
// If it's markdown what should we do? Show notification??
|
||||||
|
} else {
|
||||||
|
// Use the active cell in this case, or 1st cell if there's none active
|
||||||
|
cell = editor.model.activeCell;
|
||||||
|
}
|
||||||
|
if (!cell || (cell && cell.cellType !== CellTypes.Code)) {
|
||||||
|
return Promise.reject(localize('clearResultActiveCell', "Clear result requires a code cell to be selected. Please select a code cell to run."));
|
||||||
|
}
|
||||||
|
|
||||||
|
return editor.clearOutput(cell);
|
||||||
|
}
|
||||||
|
|
||||||
$clearAllOutputs(id: string): Promise<boolean> {
|
$clearAllOutputs(id: string): Promise<boolean> {
|
||||||
let editor = this.getEditor(id);
|
let editor = this.getEditor(id);
|
||||||
if (!editor) {
|
if (!editor) {
|
||||||
|
|||||||
@@ -920,6 +920,7 @@ export interface MainThreadNotebookDocumentsAndEditorsShape extends IDisposable
|
|||||||
$tryApplyEdits(id: string, modelVersionId: number, edits: ISingleNotebookEditOperation[], opts: IUndoStopOptions): Promise<boolean>;
|
$tryApplyEdits(id: string, modelVersionId: number, edits: ISingleNotebookEditOperation[], opts: IUndoStopOptions): Promise<boolean>;
|
||||||
$runCell(id: string, cellUri: UriComponents): Promise<boolean>;
|
$runCell(id: string, cellUri: UriComponents): Promise<boolean>;
|
||||||
$runAllCells(id: string): Promise<boolean>;
|
$runAllCells(id: string): Promise<boolean>;
|
||||||
|
$clearOutput(id: string, cellUri: UriComponents): Promise<boolean>;
|
||||||
$clearAllOutputs(id: string): Promise<boolean>;
|
$clearAllOutputs(id: string): Promise<boolean>;
|
||||||
$changeKernel(id: string, kernel: azdata.nb.IKernelInfo): Promise<boolean>;
|
$changeKernel(id: string, kernel: azdata.nb.IKernelInfo): Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -535,6 +535,26 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async clearOutput(cell: ICellModel): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
await this.modelReady;
|
||||||
|
let uriString = cell.cellUri.toString();
|
||||||
|
if (this._model.cells.findIndex(c => c.cellUri.toString() === uriString) > -1) {
|
||||||
|
this.selectCell(cell);
|
||||||
|
// Clear outputs of the requested cell if cell type is code cell.
|
||||||
|
// If cell is markdown cell, clearOutputs() is a no-op
|
||||||
|
if (cell.cellType === CellTypes.Code) {
|
||||||
|
(cell as CellModel).clearOutputs();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return Promise.reject(new Error(localize('cellNotFound', "cell with URI {0} was not found in this model", uriString)));
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return Promise.reject(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async clearAllOutputs(): Promise<boolean> {
|
public async clearAllOutputs(): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
await this.modelReady;
|
await this.modelReady;
|
||||||
|
|||||||
@@ -129,5 +129,6 @@ export interface INotebookEditor {
|
|||||||
executeEdits(edits: ISingleNotebookEditOperation[]): boolean;
|
executeEdits(edits: ISingleNotebookEditOperation[]): boolean;
|
||||||
runCell(cell: ICellModel): Promise<boolean>;
|
runCell(cell: ICellModel): Promise<boolean>;
|
||||||
runAllCells(): Promise<boolean>;
|
runAllCells(): Promise<boolean>;
|
||||||
|
clearOutput(cell: ICellModel): Promise<boolean>;
|
||||||
clearAllOutputs(): Promise<boolean>;
|
clearAllOutputs(): Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user