diff --git a/src/vs/workbench/api/browser/mainThreadNotebook.ts b/src/vs/workbench/api/browser/mainThreadNotebook.ts index 8b994acf80e..0f47f970516 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebook.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebook.ts @@ -260,7 +260,7 @@ export class MainThreadNotebooks implements MainThreadNotebookShape { return; } const disposableStore = new DisposableStore(); - disposableStore.add(textModel!.onDidChangeContent(event => { + disposableStore.add(textModel.onDidChangeContent(event => { const dto = event.rawEvents.map(e => { const data = e.kind === NotebookCellsChangeType.ModelChange || e.kind === NotebookCellsChangeType.Initialize @@ -285,18 +285,14 @@ export class MainThreadNotebooks implements MainThreadNotebookShape { return data; }); - /** - * TODO@rebornix, @jrieken - * When a document is modified, it will trigger onDidChangeContent events. - * The first event listener is this one, which doesn't know if the text model is dirty or not. It can ask `workingCopyService` but get the wrong result - * The second event listener is `NotebookEditorModel`, which will then set `isDirty` to `true`. - * Since `e.transient` decides if the model should be dirty or not, we will use the same logic here. - */ - const hasNonTransientEvent = event.rawEvents.find(e => !e.transient); - this._proxy.$acceptModelChanged(textModel.uri, { - rawEvents: dto, - versionId: event.versionId - }, !!hasNonTransientEvent); + // using the model resolver service to know if the model is dirty or not. + // assuming this is the first listener it can mean that at first the model + // is marked as dirty and that another event is fired + this._proxy.$acceptModelChanged( + textModel.uri, + { rawEvents: dto, versionId: event.versionId }, + this._notebookEditorModelResolverService.isDirty(textModel.uri) + ); const hasDocumentMetadataChangeEvent = event.rawEvents.find(e => e.kind === NotebookCellsChangeType.ChangeDocumentMetadata); if (!!hasDocumentMetadataChangeEvent) { diff --git a/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverService.ts b/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverService.ts index 52c13ae3031..fe2fb23f0e1 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverService.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverService.ts @@ -17,5 +17,7 @@ export interface INotebookEditorModelResolverService { readonly onDidSaveNotebook: Event; readonly onDidChangeDirty: Event<{ resource: URI, isDirty: boolean }>; + isDirty(resource: URI): boolean; + resolve(resource: URI, viewType?: string): Promise>; } diff --git a/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverServiceImpl.ts b/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverServiceImpl.ts index 1daf24a0f39..bf9b8f9f7a1 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverServiceImpl.ts @@ -15,6 +15,7 @@ import { FileWorkingCopyManager, IFileWorkingCopyManager } from 'vs/workbench/se import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverService'; +import { ResourceMap } from 'vs/base/common/map'; class NotebookModelReferenceCollection extends ReferenceCollection> { @@ -28,6 +29,8 @@ class NotebookModelReferenceCollection extends ReferenceCollection(); readonly onDidChangeDirty: Event<{ resource: URI, isDirty: boolean }> = this._onDidChangeDirty.event; + private readonly _dirtyStates = new ResourceMap(); + constructor( @IInstantiationService readonly _instantiationService: IInstantiationService, @INotebookService private readonly _notebookService: INotebookService, @@ -48,6 +51,10 @@ class NotebookModelReferenceCollection extends ReferenceCollection { const uri = URI.parse(key); const info = await this._notebookService.withNotebookDataProvider(uri, viewType); @@ -68,7 +75,11 @@ class NotebookModelReferenceCollection extends ReferenceCollection this._onDidSaveNotebook.fire(result.resource)), - result.onDidChangeDirty(() => this._onDidChangeDirty.fire({ resource: result.resource, isDirty: result.isDirty() })), + result.onDidChangeDirty(() => { + const isDirty = result.isDirty(); + this._dirtyStates.set(result.resource, isDirty); + this._onDidChangeDirty.fire({ resource: result.resource, isDirty }); + }), )); return result; } @@ -108,6 +119,10 @@ export class NotebookModelResolverServiceImpl implements INotebookEditorModelRes this._data.dispose(); } + isDirty(resource: URI): boolean { + return this._data.isDirty(resource); + } + async resolve(resource: URI, viewType?: string): Promise> { if (resource.scheme === CellUri.scheme) {