diff --git a/src/vs/workbench/api/browser/mainThreadDocuments.ts b/src/vs/workbench/api/browser/mainThreadDocuments.ts index 5b0102492caefef24de6b0438661c94161abf5ef..f49040e3ad1bf6962aa7ba9db9f10e154d3c6835 100644 --- a/src/vs/workbench/api/browser/mainThreadDocuments.ts +++ b/src/vs/workbench/api/browser/mainThreadDocuments.ts @@ -20,6 +20,7 @@ import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/commo import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; import { Emitter } from 'vs/base/common/event'; import { IPathService } from 'vs/workbench/services/path/common/pathService'; +import { ResourceMap } from 'vs/base/common/map'; export class BoundModelReferenceCollection { @@ -105,52 +106,39 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen private _onIsCaughtUpWithContentChanges = this._register(new Emitter()); public readonly onIsCaughtUpWithContentChanges = this._onIsCaughtUpWithContentChanges.event; - private readonly _modelService: IModelService; - private readonly _textModelResolverService: ITextModelService; - private readonly _textFileService: ITextFileService; - private readonly _fileService: IFileService; - private readonly _environmentService: IWorkbenchEnvironmentService; - private readonly _uriIdentityService: IUriIdentityService; - - private _modelTrackers: { [modelUrl: string]: ModelTracker; }; private readonly _proxy: ExtHostDocumentsShape; - private readonly _modelIsSynced = new Set(); + private readonly _modelTrackers = new ResourceMap(); + private readonly _modelIsSynced = new ResourceMap(); private readonly _modelReferenceCollection: BoundModelReferenceCollection; constructor( documentsAndEditors: MainThreadDocumentsAndEditors, extHostContext: IExtHostContext, - @IModelService modelService: IModelService, - @ITextFileService textFileService: ITextFileService, - @IFileService fileService: IFileService, - @ITextModelService textModelResolverService: ITextModelService, - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, - @IUriIdentityService uriIdentityService: IUriIdentityService, + @IModelService private readonly _modelService: IModelService, + @ITextFileService private readonly _textFileService: ITextFileService, + @IFileService private readonly _fileService: IFileService, + @ITextModelService private readonly _textModelResolverService: ITextModelService, + @IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService, + @IUriIdentityService private readonly _uriIdentityService: IUriIdentityService, @IWorkingCopyFileService workingCopyFileService: IWorkingCopyFileService, @IPathService private readonly _pathService: IPathService ) { super(); - this._modelService = modelService; - this._textModelResolverService = textModelResolverService; - this._textFileService = textFileService; - this._fileService = fileService; - this._environmentService = environmentService; - this._uriIdentityService = uriIdentityService; - this._modelReferenceCollection = this._register(new BoundModelReferenceCollection(uriIdentityService.extUri)); + this._modelReferenceCollection = this._register(new BoundModelReferenceCollection(_uriIdentityService.extUri)); this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocuments); this._register(documentsAndEditors.onDocumentAdd(models => models.forEach(this._onModelAdded, this))); this._register(documentsAndEditors.onDocumentRemove(urls => urls.forEach(this._onModelRemoved, this))); - this._register(modelService.onModelModeChanged(this._onModelModeChanged, this)); + this._register(_modelService.onModelModeChanged(this._onModelModeChanged, this)); - this._register(textFileService.files.onDidSave(e => { + this._register(_textFileService.files.onDidSave(e => { if (this._shouldHandleFileEvent(e.model.resource)) { this._proxy.$acceptModelSaved(e.model.resource); } })); - this._register(textFileService.files.onDidChangeDirty(m => { + this._register(_textFileService.files.onDidChangeDirty(m => { if (this._shouldHandleFileEvent(m.resource)) { this._proxy.$acceptDirtyStateChanged(m.resource, m.isDirty()); } @@ -167,22 +155,18 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen } } })); - - this._modelTrackers = Object.create(null); } public override dispose(): void { - Object.keys(this._modelTrackers).forEach((modelUrl) => { - this._modelTrackers[modelUrl].dispose(); - }); - this._modelTrackers = Object.create(null); + dispose(this._modelTrackers.values()); + this._modelTrackers.clear(); super.dispose(); } public isCaughtUpWithContentChanges(resource: URI): boolean { - const modelUrl = resource.toString(); - if (this._modelTrackers[modelUrl]) { - return this._modelTrackers[modelUrl].isCaughtUpWithContentChanges(); + const tracker = this._modelTrackers.get(resource); + if (tracker) { + return tracker.isCaughtUpWithContentChanges(); } return true; } @@ -198,28 +182,25 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen // don't synchronize too large models return; } - const modelUrl = model.uri; - this._modelIsSynced.add(modelUrl.toString()); - this._modelTrackers[modelUrl.toString()] = new ModelTracker(model, this._onIsCaughtUpWithContentChanges, this._proxy, this._textFileService); + this._modelIsSynced.set(model.uri, undefined); + this._modelTrackers.set(model.uri, new ModelTracker(model, this._onIsCaughtUpWithContentChanges, this._proxy, this._textFileService)); } private _onModelModeChanged(event: { model: ITextModel; oldModeId: string; }): void { let { model } = event; - const modelUrl = model.uri; - if (!this._modelIsSynced.has(modelUrl.toString())) { + if (!this._modelIsSynced.has(model.uri)) { return; } this._proxy.$acceptModelModeChanged(model.uri, model.getLanguageIdentifier().language); } private _onModelRemoved(modelUrl: URI): void { - const strModelUrl = modelUrl.toString(); - if (!this._modelIsSynced.has(strModelUrl)) { + if (!this._modelIsSynced.has(modelUrl)) { return; } - this._modelIsSynced.delete(strModelUrl); - this._modelTrackers[strModelUrl].dispose(); - delete this._modelTrackers[strModelUrl]; + this._modelIsSynced.delete(modelUrl); + this._modelTrackers.get(modelUrl)!.dispose(); + this._modelTrackers.delete(modelUrl); } // --- from extension host process @@ -252,7 +233,7 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen return Promise.reject(new Error(`cannot open ${canonicalUri.toString()}`)); } else if (!extUri.isEqual(documentUri, canonicalUri)) { return Promise.reject(new Error(`cannot open ${canonicalUri.toString()}. Detail: Actual document opened as ${documentUri.toString()}`)); - } else if (!this._modelIsSynced.has(canonicalUri.toString())) { + } else if (!this._modelIsSynced.has(canonicalUri)) { return Promise.reject(new Error(`cannot open ${canonicalUri.toString()}. Detail: Files above 50MB cannot be synchronized with extensions.`)); } else { return canonicalUri; @@ -291,7 +272,7 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen }).then(model => { const resource = model.resource; - if (!this._modelIsSynced.has(resource.toString())) { + if (!this._modelIsSynced.has(resource)) { throw new Error(`expected URI ${resource.toString()} to have come to LIFE`); }