add NotebookDocument.save().

This commit is contained in:
rebornix 2021-02-18 11:50:25 -08:00
parent df04e1388d
commit 9c77f4d86a
6 changed files with 64 additions and 2 deletions

View file

@ -293,4 +293,37 @@ suite('Notebook Document', function () {
assert.deepStrictEqual(data.cells[0].outputs, [thirdOutput]);
}
});
test('document save API', async function () {
const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest');
const notebook = await vscode.notebook.openNotebookDocument(uri);
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.viewType, 'notebook.nbdtest');
const edit = new vscode.WorkspaceEdit();
edit.replaceNotebookCells(notebook.uri, 0, 0, [{
cellKind: vscode.NotebookCellKind.Markdown,
language: 'markdown',
metadata: undefined,
outputs: [],
source: 'new_markdown'
}, {
cellKind: vscode.NotebookCellKind.Code,
language: 'fooLang',
metadata: undefined,
outputs: [],
source: 'new_code'
}]);
const success = await vscode.workspace.applyEdit(edit);
assert.strictEqual(success, true);
assert.strictEqual(notebook.isDirty, true);
await notebook.save();
assert.strictEqual(notebook.isDirty, false);
});
});

View file

@ -1281,6 +1281,15 @@ declare module 'vscode' {
readonly cells: ReadonlyArray<NotebookCell>;
readonly contentOptions: NotebookDocumentContentOptions;
readonly metadata: NotebookDocumentMetadata;
/**
* Save the document. The saving will be handled by the corresponding content provider
*
* @return A promise that will resolve to true when the document
* has been saved. If the file was not dirty or the save failed,
* will return false.
*/
save(): Thenable<boolean>;
}
// todo@API maybe have a NotebookCellPosition sibling

View file

@ -669,6 +669,15 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
return uri;
}
async $trySaveDocument(uriComponents: UriComponents) {
const uri = URI.revive(uriComponents);
const ref = await this._notebookModelResolverService.resolve(uri);
const saveResult = await ref.object.save();
ref.dispose();
return saveResult;
}
async $tryShowNotebookDocument(resource: UriComponents, viewType: string, options: INotebookDocumentShowOptions): Promise<string> {
const editorOptions: ITextEditorOptions = {
preserveFocus: options.preserveFocus,

View file

@ -790,6 +790,7 @@ export interface MainThreadNotebookShape extends IDisposable {
$registerNotebookKernelProvider(extension: NotebookExtensionDescription, handle: number, documentFilter: INotebookDocumentFilter): Promise<void>;
$unregisterNotebookKernelProvider(handle: number): Promise<void>;
$onNotebookKernelChange(handle: number, uri: UriComponents | undefined): void;
$trySaveDocument(uri: UriComponents): Promise<boolean>;
$tryApplyEdits(viewType: string, resource: UriComponents, modelVersionId: number, edits: ICellEditOperation[]): Promise<boolean>;
$postMessage(editorId: string, forRendererId: string | undefined, value: any): Promise<boolean>;
$setStatusBarEntry(id: number, statusBarEntry: INotebookCellStatusBarEntryDto): Promise<void>;

View file

@ -715,6 +715,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
const that = this;
const document = new ExtHostNotebookDocument(
this._proxy,
this._documentsAndEditors,
{
emitModelChange(event: vscode.NotebookCellsChangeEvent): void {

View file

@ -9,7 +9,7 @@ import { Disposable, DisposableStore, dispose } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
import { joinPath } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import { CellKind, INotebookDocumentPropertiesChangeData } from 'vs/workbench/api/common/extHost.protocol';
import { CellKind, INotebookDocumentPropertiesChangeData, MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostDocumentsAndEditors, IExtHostModelAddedData } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
@ -146,6 +146,7 @@ export class ExtHostNotebookDocument extends Disposable {
private _disposed = false;
constructor(
private readonly _proxy: MainThreadNotebookShape,
private readonly _documentsAndEditors: ExtHostDocumentsAndEditors,
private readonly _emitter: INotebookEventEmitter,
private readonly _viewType: string,
@ -177,7 +178,8 @@ export class ExtHostNotebookDocument extends Disposable {
get cells(): ReadonlyArray<vscode.NotebookCell> { return that._cells.map(cell => cell.cell); },
get metadata() { return that._metadata; },
set metadata(_value: Required<vscode.NotebookDocumentMetadata>) { throw new Error('Use WorkspaceEdit to update metadata.'); },
get contentOptions() { return that._contentOptions; }
get contentOptions() { return that._contentOptions; },
save() { return that._save(); }
});
}
return this._notebook;
@ -232,6 +234,13 @@ export class ExtHostNotebookDocument extends Disposable {
});
}
private async _save(): Promise<boolean> {
if (this._disposed) {
return Promise.reject(new Error('Document has been closed'));
}
return this._proxy.$trySaveDocument(this.uri);
}
private _spliceNotebookCells(splices: NotebookCellsSplice2[], initialization: boolean): void {
if (this._disposed) {
return;