first cut of IFileWorkingCopy adoption, misses saveAs and backsnapshot are improper...

上级 8af8a869
......@@ -1384,8 +1384,25 @@ declare module 'vscode' {
//#endregion
//#region https://github.com/microsoft/vscode/issues/106744, NotebookSerializer
export interface NotebookSerializer {
dataToNotebook(data: Uint8Array): NotebookData | Thenable<NotebookData>;
notebookToData(data: NotebookData): Uint8Array | Thenable<Uint8Array>;
}
export namespace notebook {
// TODO@api use NotebookDocumentFilter instead of just notebookType:string?
// TODO@API options duplicates the more powerful variant on NotebookContentProvider
export function registerNotebookSerializer(notebookType: string, provider: NotebookSerializer, options?: NotebookDocumentContentOptions): Disposable;
}
//#endregion
//#region https://github.com/microsoft/vscode/issues/106744, NotebookContentProvider
interface NotebookDocumentBackup {
/**
* Unique identifier for the backup.
......
......@@ -457,10 +457,10 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
$registerNotebookSerializer(handle: number, extension: NotebookExtensionDescription, viewType: string, options: TransientOptions): void {
const registration = this._notebookService.registerNotebookSerializer(viewType, extension, {
options,
dataToNotebook: (data: Uint8Array): Promise<NotebookDataDto> => {
dataToNotebook: (data: VSBuffer): Promise<NotebookDataDto> => {
return this._proxy.$dataToNotebook(handle, data);
},
notebookToData: (data: NotebookDataDto): Promise<Uint8Array> => {
notebookToData: (data: NotebookDataDto): Promise<VSBuffer> => {
return this._proxy.$notebookToData(handle, data);
}
});
......
......@@ -1051,6 +1051,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
checkProposedApiEnabled(extension);
return extHostNotebook.onDidChangeActiveNotebookKernel;
},
registerNotebookSerializer(viewType, serializer, options) {
checkProposedApiEnabled(extension);
return extHostNotebook.registerNotebookSerializer(extension, viewType, serializer, options);
},
registerNotebookContentProvider: (viewType: string, provider: vscode.NotebookContentProvider, options?: {
transientOutputs: boolean;
transientMetadata: { [K in keyof vscode.NotebookCellMetadata]?: boolean }
......
......@@ -1870,8 +1870,8 @@ export interface ExtHostNotebookShape {
$saveNotebookAs(viewType: string, uri: UriComponents, target: UriComponents, token: CancellationToken): Promise<boolean>;
$backupNotebook(viewType: string, uri: UriComponents, cancellation: CancellationToken): Promise<string>;
$dataToNotebook(handle: number, data: Uint8Array): Promise<NotebookDataDto>;
$notebookToData(handle: number, data: NotebookDataDto): Promise<Uint8Array>;
$dataToNotebook(handle: number, data: VSBuffer): Promise<NotebookDataDto>;
$notebookToData(handle: number, data: NotebookDataDto): Promise<VSBuffer>;
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEventDto, isDirty: boolean): void;
$acceptDirtyStateChanged(uriComponents: UriComponents, isDirty: boolean): void;
......
......@@ -209,10 +209,6 @@ export class NotebookEditorDecorationType {
}
}
export interface NotebookSerializer {
dataToNotebook(data: Uint8Array): vscode.NotebookData | Thenable<vscode.NotebookData>;
notebookToData(data: vscode.NotebookData): Uint8Array | Thenable<Uint8Array>;
}
type NotebookContentProviderData = {
readonly provider: vscode.NotebookContentProvider;
......@@ -504,38 +500,44 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
// --- serialize/deserialize
private _handlePool = 0;
private readonly _notebookSerializer = new Map<number, NotebookSerializer>();
private readonly _notebookSerializer = new Map<number, vscode.NotebookSerializer>();
registerNotebookSerializer(extension: IExtensionDescription, viewType: string, serializer: NotebookSerializer, options: TransientOptions): vscode.Disposable {
registerNotebookSerializer(extension: IExtensionDescription, viewType: string, serializer: vscode.NotebookSerializer, options?: TransientOptions): vscode.Disposable {
const handle = this._handlePool++;
this._notebookSerializer.set(handle, serializer);
this._proxy.$registerNotebookSerializer(handle, { id: extension.identifier, location: extension.extensionLocation, description: extension.description }, viewType, options);
this._proxy.$registerNotebookSerializer(
handle,
{ id: extension.identifier, location: extension.extensionLocation, description: extension.description },
viewType,
options ?? { transientOutputs: false, transientMetadata: {} }
);
return toDisposable(() => {
this._proxy.$unregisterNotebookSerializer(handle);
});
}
async $dataToNotebook(handle: number, bytes: Uint8Array): Promise<NotebookDataDto> {
async $dataToNotebook(handle: number, bytes: VSBuffer): Promise<NotebookDataDto> {
const serializer = this._notebookSerializer.get(handle);
if (!serializer) {
throw new Error('NO serializer found');
}
const data = await serializer.dataToNotebook(bytes);
const data = await serializer.dataToNotebook(bytes.buffer);
return {
metadata: typeConverters.NotebookDocumentMetadata.from(data.metadata),
cells: data.cells.map(typeConverters.NotebookCellData.from),
};
}
async $notebookToData(handle: number, data: NotebookDataDto): Promise<Uint8Array> {
async $notebookToData(handle: number, data: NotebookDataDto): Promise<VSBuffer> {
const serializer = this._notebookSerializer.get(handle);
if (!serializer) {
throw new Error('NO serializer found');
}
return await serializer.notebookToData({
const bytes = await serializer.notebookToData({
metadata: typeConverters.NotebookDocumentMetadata.to(data.metadata),
cells: data.cells.map(typeConverters.NotebookCellData.to)
});
return VSBuffer.wrap(bytes);
}
// --- open, save, saveAs, backup
......
......@@ -29,7 +29,7 @@ export class NotebookEditorInput extends EditorInput {
private readonly _name: string;
private _textModel: IReference<IResolvedNotebookEditorModel> | null = null;
private _editorModelReference: IReference<IResolvedNotebookEditorModel> | null = null;
private _defaultDirtyState: boolean = false;
constructor(
......@@ -56,14 +56,14 @@ export class NotebookEditorInput extends EditorInput {
}
isDirty() {
if (!this._textModel) {
return !!this._defaultDirtyState;
if (!this._editorModelReference) {
return this._defaultDirtyState;
}
return this._textModel.object.isDirty();
return this._editorModelReference.object.isDirty();
}
isUntitled(): boolean {
return this._textModel?.object.isUntitled() || false;
return this._editorModelReference?.object.isUntitled() || false;
}
isReadonly() {
......@@ -71,12 +71,12 @@ export class NotebookEditorInput extends EditorInput {
}
async save(group: GroupIdentifier, options?: ISaveOptions): Promise<IEditorInput | undefined> {
if (this._textModel) {
if (this._editorModelReference) {
if (this.isUntitled()) {
return this.saveAs(group, options);
} else {
await this._textModel.object.save();
await this._editorModelReference.object.save(options);
}
return this;
......@@ -86,7 +86,7 @@ export class NotebookEditorInput extends EditorInput {
}
async saveAs(group: GroupIdentifier, options?: ISaveOptions): Promise<IEditorInput | undefined> {
if (!this._textModel) {
if (!this._editorModelReference) {
return undefined;
}
......@@ -96,7 +96,7 @@ export class NotebookEditorInput extends EditorInput {
return undefined;
}
const dialogPath = this.isUntitled() ? await this._suggestName(this._name) : this._textModel.object.resource;
const dialogPath = this.isUntitled() ? await this._suggestName(this._name) : this._editorModelReference.object.resource;
const target = await this._fileDialogService.pickFileToSave(dialogPath, options?.availableFileSystems);
if (!target) {
......@@ -122,7 +122,7 @@ ${patterns}
`);
}
if (!await this._textModel.object.saveAs(target)) {
if (!await this._editorModelReference.object.saveAs(target)) {
return undefined;
}
......@@ -135,27 +135,25 @@ ${patterns}
// called when users rename a notebook document
rename(group: GroupIdentifier, target: URI): IMoveResult | undefined {
if (this._textModel) {
if (this._editorModelReference) {
const contributedNotebookProviders = this._notebookService.getContributedNotebookProviders(target);
if (contributedNotebookProviders.find(provider => provider.id === this._textModel!.object.viewType)) {
if (contributedNotebookProviders.find(provider => provider.id === this._editorModelReference!.object.viewType)) {
return this._move(group, target);
}
}
return undefined;
}
private _move(group: GroupIdentifier, newResource: URI): { editor: IEditorInput } | undefined {
private _move(_group: GroupIdentifier, newResource: URI): { editor: IEditorInput } {
const editorInput = NotebookEditorInput.create(this._instantiationService, newResource, this.viewType);
return { editor: editorInput };
}
async revert(group: GroupIdentifier, options?: IRevertOptions): Promise<void> {
if (this._textModel && this._textModel.object.isDirty()) {
await this._textModel.object.revert(options);
async revert(_group: GroupIdentifier, options?: IRevertOptions): Promise<void> {
if (this._editorModelReference && this._editorModelReference.object.isDirty()) {
await this._editorModelReference.object.revert(options);
}
return;
}
async resolve(): Promise<IResolvedNotebookEditorModel | null> {
......@@ -163,20 +161,20 @@ ${patterns}
return null;
}
if (!this._textModel) {
this._textModel = await this._notebookModelResolverService.resolve(this.resource, this.viewType);
if (!this._editorModelReference) {
this._editorModelReference = await this._notebookModelResolverService.resolve(this.resource, this.viewType);
if (this.isDisposed()) {
this._textModel.dispose();
this._textModel = null;
this._editorModelReference.dispose();
this._editorModelReference = null;
return null;
}
this._register(this._textModel.object.onDidChangeDirty(() => this._onDidChangeDirty.fire()));
if (this._textModel.object.isDirty()) {
this._register(this._editorModelReference.object.onDidChangeDirty(() => this._onDidChangeDirty.fire()));
if (this._editorModelReference.object.isDirty()) {
this._onDidChangeDirty.fire();
}
}
return this._textModel.object;
return this._editorModelReference.object;
}
matches(otherInput: unknown): boolean {
......@@ -190,8 +188,8 @@ ${patterns}
}
dispose() {
this._textModel?.dispose();
this._textModel = null;
this._editorModelReference?.dispose();
this._editorModelReference = null;
super.dispose();
}
}
......@@ -31,7 +31,7 @@ import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, BUILTIN_RENDERER_ID, DisplayOrderKey
import { NotebookMarkdownRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookMarkdownRenderer';
import { NotebookOutputRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookOutputRenderer';
import { NotebookEditorDescriptor, NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider';
import { IMainNotebookController, INotebookSerializer, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { ComplexNotebookProviderInfo, IMainNotebookController, INotebookSerializer, INotebookService, SimpleNotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookService';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { Extensions as EditorExtensions, IEditorTypesHandler, IEditorType, IEditorAssociationsRegistry } from 'vs/workbench/browser/editor';
......@@ -234,25 +234,12 @@ class ModelData implements IDisposable {
}
class ComplexNotebookProviderData {
constructor(
readonly controller: IMainNotebookController,
readonly extensionData: NotebookExtensionDescription
) { }
}
class SimpleNotebookProviderData {
constructor(
readonly serializer: INotebookSerializer,
readonly extensionData: NotebookExtensionDescription
) { }
}
export class NotebookService extends Disposable implements INotebookService, IEditorTypesHandler {
declare readonly _serviceBrand: undefined;
private readonly _notebookProviders = new Map<string, ComplexNotebookProviderData | SimpleNotebookProviderData>();
private readonly _notebookProviders = new Map<string, ComplexNotebookProviderInfo | SimpleNotebookProviderInfo>();
private readonly _notebookProviderInfoStore: NotebookProviderInfoStore;
private readonly _notebookRenderersInfoStore: NotebookOutputRendererInfoStore = new NotebookOutputRendererInfoStore();
private readonly _markdownRenderersInfos = new Set<INotebookMarkdownRendererInfo>();
......@@ -440,7 +427,7 @@ export class NotebookService extends Disposable implements INotebookService, IEd
return this._notebookProviders.has(viewType);
}
private _registerProviderData(viewType: string, data: SimpleNotebookProviderData | ComplexNotebookProviderData): void {
private _registerProviderData(viewType: string, data: SimpleNotebookProviderInfo | ComplexNotebookProviderInfo): void {
if (this._notebookProviders.has(viewType)) {
throw new Error(`notebook controller for viewtype '${viewType}' already exists`);
}
......@@ -448,7 +435,7 @@ export class NotebookService extends Disposable implements INotebookService, IEd
}
registerNotebookController(viewType: string, extensionData: NotebookExtensionDescription, controller: IMainNotebookController): IDisposable {
this._registerProviderData(viewType, new ComplexNotebookProviderData(controller, extensionData));
this._registerProviderData(viewType, new ComplexNotebookProviderInfo(viewType, controller, extensionData));
if (controller.viewOptions && !this._notebookProviderInfoStore.get(viewType)) {
// register this content provider to the static contribution, if it does not exist
......@@ -480,12 +467,20 @@ export class NotebookService extends Disposable implements INotebookService, IEd
}
registerNotebookSerializer(viewType: string, extensionData: NotebookExtensionDescription, serializer: INotebookSerializer): IDisposable {
this._registerProviderData(viewType, new SimpleNotebookProviderData(serializer, extensionData));
this._registerProviderData(viewType, new SimpleNotebookProviderInfo(viewType, serializer, extensionData));
return toDisposable(() => {
this._notebookProviders.delete(viewType);
});
}
getNotebookDataProvider(resource: URI): ComplexNotebookProviderInfo | SimpleNotebookProviderInfo | undefined {
const [first] = this._notebookProviderInfoStore.getContributedNotebook(resource);
if (!first) {
return undefined;
}
return this._notebookProviders.get(first.id);
}
registerNotebookKernelProvider(provider: INotebookKernelProvider): IDisposable {
const d = this._notebookKernelProviderInfoStore.add(provider);
const kernelChangeEventListener = provider.onDidChangeKernels((e) => {
......@@ -526,9 +521,9 @@ export class NotebookService extends Disposable implements INotebookService, IEd
// --- notebook documents: IO
private _withComplexProvider(viewType: string): ComplexNotebookProviderData {
private _withComplexProvider(viewType: string): ComplexNotebookProviderInfo {
const result = this._notebookProviders.get(viewType);
if (!(result instanceof ComplexNotebookProviderData)) {
if (!(result instanceof ComplexNotebookProviderInfo)) {
throw new Error(`having NO provider for ${viewType}`);
}
return result;
......@@ -700,14 +695,14 @@ export class NotebookService extends Disposable implements INotebookService, IEd
async resolveNotebookEditor(viewType: string, uri: URI, editorId: string): Promise<void> {
const entry = this._notebookProviders.get(viewType);
if (entry instanceof ComplexNotebookProviderData) {
if (entry instanceof ComplexNotebookProviderInfo) {
entry.controller.resolveNotebookEditor(viewType, uri, editorId);
}
}
onDidReceiveMessage(viewType: string, editorId: string, rendererType: string | undefined, message: any): void {
const provider = this._notebookProviders.get(viewType);
if (provider instanceof ComplexNotebookProviderData) {
if (provider instanceof ComplexNotebookProviderInfo) {
return provider.controller.onDidReceiveMessage(editorId, rendererType, message);
}
}
......
......@@ -18,7 +18,7 @@ import { IAccessibilityInformation } from 'vs/platform/accessibility/common/acce
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IEditorModel } from 'vs/platform/editor/common/editor';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { IRevertOptions } from 'vs/workbench/common/editor';
import { IRevertOptions, ISaveOptions } from 'vs/workbench/common/editor';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IFileStatWithMetadata } from 'vs/platform/files/common/files';
......@@ -621,9 +621,9 @@ export interface INotebookEditorModel extends IEditorModel {
isDirty(): boolean;
isUntitled(): boolean;
load(options?: INotebookLoadOptions): Promise<IResolvedNotebookEditorModel>;
save(): Promise<boolean>;
save(options?: ISaveOptions): Promise<boolean>;
saveAs(target: URI): Promise<boolean>;
revert(options?: IRevertOptions | undefined): Promise<void>;
revert(options?: IRevertOptions): Promise<void>;
}
export interface INotebookDiffEditorModel extends IEditorModel {
......
......@@ -4,11 +4,11 @@
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { EditorModel, IRevertOptions } from 'vs/workbench/common/editor';
import { EditorModel, IRevertOptions, ISaveOptions } from 'vs/workbench/common/editor';
import { Emitter, Event } from 'vs/base/common/event';
import { CellEditType, CellKind, ICellEditOperation, INotebookEditorModel, INotebookLoadOptions, IResolvedNotebookEditorModel, NotebookCellsChangeType, NotebookDocumentBackupData } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellEditType, CellKind, ICellEditOperation, INotebookEditorModel, INotebookLoadOptions, IResolvedNotebookEditorModel, NotebookCellsChangeType, NotebookDataDto, NotebookDocumentBackupData } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { INotebookSerializer, INotebookService, SimpleNotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookService';
import { URI } from 'vs/base/common/uri';
import { IWorkingCopyService, IWorkingCopy, IWorkingCopyBackup, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService';
import { CancellationToken } from 'vs/base/common/cancellation';
......@@ -19,11 +19,17 @@ import { INotificationService, Severity } from 'vs/platform/notification/common/
import { ILabelService } from 'vs/platform/label/common/label';
import { ILogService } from 'vs/platform/log/common/log';
import { TaskSequentializer } from 'vs/base/common/async';
import { VSBuffer } from 'vs/base/common/buffer';
import { bufferToStream, streamToBuffer, VSBuffer, VSBufferReadableStream } from 'vs/base/common/buffer';
import { assertType } from 'vs/base/common/types';
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
import { IFileWorkingCopyModel, IFileWorkingCopyModelContentChangedEvent, IFileWorkingCopyModelFactory, IResolvedFileWorkingCopy } from 'vs/workbench/services/workingCopy/common/fileWorkingCopy';
import { ITextSnapshot } from 'vs/editor/common/model';
import { IDisposable } from 'vs/base/common/lifecycle';
import { canceled } from 'vs/base/common/errors';
export class NotebookEditorModel extends EditorModel implements INotebookEditorModel {
//#region --- complex content provider
export class ComplexNotebookEditorModel extends EditorModel implements INotebookEditorModel {
private readonly _onDidChangeDirty = this._register(new Emitter<void>());
private readonly _onDidChangeContent = this._register(new Emitter<void>());
......@@ -150,7 +156,7 @@ export class NotebookEditorModel extends EditorModel implements INotebookEditorM
this._onDidChangeDirty.fire();
}
async load(options?: INotebookLoadOptions): Promise<NotebookEditorModel & IResolvedNotebookEditorModel> {
async load(options?: INotebookLoadOptions): Promise<IResolvedNotebookEditorModel> {
if (options?.forceReadFromDisk) {
this._logService.debug('[notebook editor model] load from provider (forceRead)', this.resource.toString());
this._loadFromProvider(undefined);
......@@ -375,3 +381,190 @@ export class NotebookEditorModel extends EditorModel implements INotebookEditorM
}
}
}
//#endregion
//#region --- simple content provider
export class SimpleNotebookEditorModel implements INotebookEditorModel {
readonly onDidChangeDirty: Event<void>;
readonly onDispose: Event<void>;
// todo@rebornix used in diff editor...
lastResolvedFileStat: IFileStatWithMetadata | undefined;
readonly resource: URI;
readonly viewType: string;
readonly notebook: NotebookTextModel;
constructor(
private readonly _workingCopy: IResolvedFileWorkingCopy<NotebookFileWorkingCopyModel>
) {
this.resource = _workingCopy.resource;
this.viewType = _workingCopy.model.notebookModel.viewType;
this.notebook = _workingCopy.model.notebookModel;
this.onDidChangeDirty = _workingCopy.onDidChangeDirty.bind(_workingCopy);
this.onDispose = _workingCopy.onDispose.bind(_workingCopy);
}
dispose(): void {
this._workingCopy.dispose();
}
isDisposed(): boolean {
return this._workingCopy.isDisposed();
}
isDirty(): boolean {
return this._workingCopy.isDirty();
}
revert(options?: IRevertOptions): Promise<void> {
return this._workingCopy.revert(options);
}
save(options?: ISaveOptions): Promise<boolean> {
return this._workingCopy.save(options);
}
isUntitled(): boolean {
return this.resource.scheme === Schemas.untitled;
}
isResolved(): this is IResolvedNotebookEditorModel {
return true;
}
async load(_options?: INotebookLoadOptions): Promise<IResolvedNotebookEditorModel> {
return this;
}
saveAs(target: URI): Promise<boolean> {
throw new Error('Method not implemented.');
}
}
export class NotebookFileWorkingCopyModel implements IFileWorkingCopyModel {
private readonly _onDidChangeContent = new Emitter<IFileWorkingCopyModelContentChangedEvent>();
private readonly _changeListener: IDisposable;
readonly onDidChangeContent = this._onDidChangeContent.event;
readonly onWillDispose: Event<void>;
constructor(
private _notebookModel: NotebookTextModel,
private _notebookSerializer: INotebookSerializer
) {
this.onWillDispose = _notebookModel.onWillDispose.bind(_notebookModel);
this._changeListener = _notebookModel.onDidChangeContent(e => {
for (const rawEvent of e.rawEvents) {
if (rawEvent.kind === NotebookCellsChangeType.Initialize) {
continue;
}
if (rawEvent.transient) {
continue;
}
//todo@jrieken,@rebornix forward this information from notebook model
this._onDidChangeContent.fire({
isRedoing: false,
isUndoing: false
});
break;
}
});
}
dispose(): void {
// todo@jrieken who is disposing this?
this._onDidChangeContent.dispose();
this._changeListener.dispose();
}
get notebookModel() {
return this._notebookModel;
}
async snapshot(token: CancellationToken): Promise<VSBufferReadableStream> {
const data: NotebookDataDto = {
metadata: this._notebookModel.metadata,
cells: [],
};
for (const cell of this._notebookModel.cells) {
data.cells.push({
cellKind: cell.cellKind,
language: cell.language,
source: cell.getValue(),
outputs: cell.outputs
});
}
const bytes = await this._notebookSerializer.notebookToData(data);
if (token.isCancellationRequested) {
throw canceled();
}
return bufferToStream(bytes);
}
async update(stream: VSBufferReadableStream, token: CancellationToken): Promise<void> {
const bytes = await streamToBuffer(stream);
const data = await this._notebookSerializer.dataToNotebook(bytes);
if (token.isCancellationRequested) {
return;
}
this._notebookModel.metadata = data.metadata;
this._notebookModel.transientOptions = this._notebookSerializer.options;
const edits: ICellEditOperation[] = [{ editType: CellEditType.Replace, index: 0, count: this._notebookModel.cells.length, cells: data.cells }];
this._notebookModel.applyEdits(edits, true, undefined, () => undefined, undefined, false);
}
getAlternativeVersionId(): number {
//todo@jrieken,@rebornix -> add alternative version id
return this._notebookModel.versionId;
}
pushStackElement(): void {
//todo@jrieken -> stack element needs a name(?)
this._notebookModel.pushStackElement('', undefined, undefined);
}
_backupSnapshot(): ITextSnapshot | undefined {
// todo@jrieken,@bpasero
// sync
// text based
return undefined;
}
}
export class NotebookFileWorkingCopyModelFactory implements IFileWorkingCopyModelFactory<NotebookFileWorkingCopyModel>{
constructor(
@INotebookService private readonly _notebookService: INotebookService
) { }
async createModel(resource: URI, stream: VSBufferReadableStream, token: CancellationToken): Promise<NotebookFileWorkingCopyModel> {
const info = this._notebookService.getNotebookDataProvider(resource);
if (!(info instanceof SimpleNotebookProviderInfo)) {
throw new Error('CANNOT open file notebook this provider');
}
const data = await info.serializer.dataToNotebook(await streamToBuffer(stream));
if (token.isCancellationRequested) {
throw canceled();
}
const notebookModel = this._notebookService.createNotebookTextModel(info.viewType, resource, data, info.serializer.options);
return new NotebookFileWorkingCopyModel(notebookModel, info.serializer);
}
}
//#endregion
......@@ -6,11 +6,13 @@
import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { URI } from 'vs/base/common/uri';
import { CellUri, IResolvedNotebookEditorModel } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { NotebookEditorModel } from 'vs/workbench/contrib/notebook/common/notebookEditorModel';
import { ComplexNotebookEditorModel, NotebookFileWorkingCopyModel, NotebookFileWorkingCopyModelFactory, SimpleNotebookEditorModel } from 'vs/workbench/contrib/notebook/common/notebookEditorModel';
import { combinedDisposable, DisposableStore, IDisposable, IReference, ReferenceCollection } from 'vs/base/common/lifecycle';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { ComplexNotebookProviderInfo, INotebookService, SimpleNotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookService';
import { ILogService } from 'vs/platform/log/common/log';
import { Event } from 'vs/base/common/event';
import { FileWorkingCopyManager, IFileWorkingCopyManager } from 'vs/workbench/services/workingCopy/common/fileWorkingCopyManager';
import { IResolvedFileWorkingCopy } from 'vs/workbench/services/workingCopy/common/fileWorkingCopy';
export const INotebookEditorModelResolverService = createDecorator<INotebookEditorModelResolverService>('INotebookModelResolverService');
......@@ -22,19 +24,36 @@ export interface INotebookEditorModelResolverService {
export class NotebookModelReferenceCollection extends ReferenceCollection<Promise<IResolvedNotebookEditorModel>> {
private readonly _workingCopyManager: IFileWorkingCopyManager<NotebookFileWorkingCopyModel>;
constructor(
@IInstantiationService readonly _instantiationService: IInstantiationService,
@INotebookService private readonly _notebookService: INotebookService,
@ILogService private readonly _logService: ILogService,
) {
super();
this._workingCopyManager = <any>_instantiationService.createInstance(
FileWorkingCopyManager,
new NotebookFileWorkingCopyModelFactory(_notebookService)
);
}
protected createReferencedObject(key: string, viewType: string): Promise<IResolvedNotebookEditorModel> {
protected async createReferencedObject(key: string, viewType: string): Promise<IResolvedNotebookEditorModel> {
const uri = URI.parse(key);
const model = this._instantiationService.createInstance(NotebookEditorModel, uri, viewType);
const promise = model.load();
return promise;
const info = this._notebookService.getNotebookDataProvider(uri);
if (info instanceof ComplexNotebookProviderInfo) {
const model = this._instantiationService.createInstance(ComplexNotebookEditorModel, uri, viewType);
return model.load();
} else if (info instanceof SimpleNotebookProviderInfo) {
const workingCopy = await this._workingCopyManager.resolve(uri);
return new SimpleNotebookEditorModel(<IResolvedFileWorkingCopy<NotebookFileWorkingCopyModel>>workingCopy);
} else {
throw new Error(`CANNOT open ${key}, no provider found`);
}
}
protected destroyReferencedObject(_key: string, object: Promise<IResolvedNotebookEditorModel>): void {
......
......@@ -34,8 +34,8 @@ export interface IMainNotebookController {
export interface INotebookSerializer {
options: TransientOptions;
dataToNotebook(data: Uint8Array): Promise<NotebookDataDto>
notebookToData(data: NotebookDataDto): Promise<Uint8Array>;
dataToNotebook(data: VSBuffer): Promise<NotebookDataDto>
notebookToData(data: NotebookDataDto): Promise<VSBuffer>;
}
export interface INotebookRawData {
......@@ -43,6 +43,22 @@ export interface INotebookRawData {
transientOptions: TransientOptions;
}
export class ComplexNotebookProviderInfo {
constructor(
readonly viewType: string,
readonly controller: IMainNotebookController,
readonly extensionData: NotebookExtensionDescription
) { }
}
export class SimpleNotebookProviderInfo {
constructor(
readonly viewType: string,
readonly serializer: INotebookSerializer,
readonly extensionData: NotebookExtensionDescription
) { }
}
export interface INotebookService {
readonly _serviceBrand: undefined;
canResolve(viewType: string): Promise<boolean>;
......@@ -55,6 +71,7 @@ export interface INotebookService {
registerNotebookController(viewType: string, extensionData: NotebookExtensionDescription, controller: IMainNotebookController): IDisposable;
registerNotebookSerializer(viewType: string, extensionData: NotebookExtensionDescription, serializer: INotebookSerializer): IDisposable;
getNotebookDataProvider(resource: URI): ComplexNotebookProviderInfo | SimpleNotebookProviderInfo | undefined;
getMimeTypeInfo(textModel: NotebookTextModel, output: IOutputDto): readonly IOrderedMimeType[];
......
......@@ -13,7 +13,7 @@ import { IFileService } from 'vs/platform/files/common/files';
import { ILabelService } from 'vs/platform/label/common/label';
import { NullLogService } from 'vs/platform/log/common/log';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { NotebookEditorModel } from 'vs/workbench/contrib/notebook/common/notebookEditorModel';
import { ComplexNotebookEditorModel } from 'vs/workbench/contrib/notebook/common/notebookEditorModel';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
......@@ -47,8 +47,8 @@ suite('NotebookEditorModel', function () {
}
};
new NotebookEditorModel(r1, 'fff', notebokService, workingCopyService, backupService, fileService, notificationService, new NullLogService(), untitledTextEditorService, labelService);
new NotebookEditorModel(r2, 'fff', notebokService, workingCopyService, backupService, fileService, notificationService, new NullLogService(), untitledTextEditorService, labelService);
new ComplexNotebookEditorModel(r1, 'fff', notebokService, workingCopyService, backupService, fileService, notificationService, new NullLogService(), untitledTextEditorService, labelService);
new ComplexNotebookEditorModel(r2, 'fff', notebokService, workingCopyService, backupService, fileService, notificationService, new NullLogService(), untitledTextEditorService, labelService);
assert.strictEqual(copies.length, 2);
assert.strictEqual(!isEqual(copies[0].resource, copies[1].resource), true);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册