diff --git a/src/vs/editor/browser/standalone/standaloneServices.ts b/src/vs/editor/browser/standalone/standaloneServices.ts index 83b60d14711113db9c39df3bf056324ce7f864c4..a0251eb6bf060de437e2e4b68152d2580eaff696 100644 --- a/src/vs/editor/browser/standalone/standaloneServices.ts +++ b/src/vs/editor/browser/standalone/standaloneServices.ts @@ -153,9 +153,9 @@ export function getOrCreateStaticServices(services?: IEditorOverrideServices): I } services = services || {}; - var contextService = services.contextService; + let contextService = services.contextService; if (!contextService) { - var workspaceUri = URI.create('inmemory', 'model', '/'); + let workspaceUri = URI.create('inmemory', 'model', '/'); contextService = new BaseWorkspaceContextService({ resource: workspaceUri, id: null, @@ -165,7 +165,7 @@ export function getOrCreateStaticServices(services?: IEditorOverrideServices): I }, {}); } - var telemetryService = services.telemetryService; + let telemetryService = services.telemetryService; if (!telemetryService) { let config = contextService.getConfiguration(); @@ -179,16 +179,16 @@ export function getOrCreateStaticServices(services?: IEditorOverrideServices): I console.warn('standaloneEditorTelemetryEndpoint is obsolete'); } - var threadService = services.threadService || new mainThreadService.MainThreadService(contextService, 'vs/editor/common/worker/editorWorkerServer'); - var messageService = services.messageService || new SimpleServices.SimpleMessageService(); - var pluginService = services.pluginService || new SimpleServices.SimplePluginService(); - var markerService = services.markerService || new MarkerService.MainProcessMarkerService(threadService); - var requestService = services.requestService || new SimpleServices.SimpleEditorRequestService(contextService, telemetryService); - var modelService = services.modelService || new ModelServiceImpl(threadService, markerService); - var editorWorkerService = services.editorWorkerService || new EditorWorkerServiceImpl(modelService); - var modeService = services.modeService || new MainThreadModeServiceImpl(threadService, pluginService); - var codeEditorService = services.codeEditorService || new CodeEditorServiceImpl(); - var eventService = services.eventService || new _eventService.EventService(); + let threadService = services.threadService || new mainThreadService.MainThreadService(contextService, 'vs/editor/common/worker/editorWorkerServer'); + let messageService = services.messageService || new SimpleServices.SimpleMessageService(); + let pluginService = services.pluginService || new SimpleServices.SimplePluginService(); + let markerService = services.markerService || new MarkerService.MainProcessMarkerService(threadService); + let requestService = services.requestService || new SimpleServices.SimpleEditorRequestService(contextService, telemetryService); + let modeService = services.modeService || new MainThreadModeServiceImpl(threadService, pluginService); + let modelService = services.modelService || new ModelServiceImpl(threadService, markerService, modeService); + let editorWorkerService = services.editorWorkerService || new EditorWorkerServiceImpl(modelService); + let codeEditorService = services.codeEditorService || new CodeEditorServiceImpl(); + let eventService = services.eventService || new _eventService.EventService(); staticServices = { pluginService: pluginService, @@ -206,7 +206,7 @@ export function getOrCreateStaticServices(services?: IEditorOverrideServices): I instantiationService: void 0 }; - var instantiationService = InstantiationService.create(staticServices); + let instantiationService = InstantiationService.create(staticServices); staticServices.instantiationService = InstantiationService.create(staticServices); if (threadService instanceof mainThreadService.MainThreadService) { threadService.setInstantiationService(instantiationService); diff --git a/src/vs/editor/common/services/modeService.ts b/src/vs/editor/common/services/modeService.ts index 8a4585695052034d0e44e1a308a12d8ec4ad3da0..1749d3737c64c3ff45f9ee3a9a28c32e55c00b74 100644 --- a/src/vs/editor/common/services/modeService.ts +++ b/src/vs/editor/common/services/modeService.ts @@ -48,6 +48,7 @@ export interface IModeService { // --- reading isRegisteredMode(mimetypeOrModeId: string): boolean; + isCompatMode(modeId: string): boolean; getRegisteredModes(): string[]; getRegisteredLanguageNames(): string[]; getExtensions(alias: string): string[]; diff --git a/src/vs/editor/common/services/modeServiceImpl.ts b/src/vs/editor/common/services/modeServiceImpl.ts index c661a808572323aa6dea6fa3c2fbfe921e19ff8b..fdb7385cf75f83c689b9cb52ff031521bad30209 100644 --- a/src/vs/editor/common/services/modeServiceImpl.ts +++ b/src/vs/editor/common/services/modeServiceImpl.ts @@ -212,6 +212,11 @@ export class ModeServiceImpl implements IModeService { return this._registry.isRegisteredMode(mimetypeOrModeId); } + public isCompatMode(modeId:string): boolean { + let compatModeData = this._registry.getCompatMode(modeId); + return (compatModeData ? true : false); + } + public getRegisteredModes(): string[] { return this._registry.getRegisteredModes(); } diff --git a/src/vs/editor/common/services/modelServiceImpl.ts b/src/vs/editor/common/services/modelServiceImpl.ts index a2a0249f1c55f70958bd3014385eab88e852b566..0d07d9834bdb3dd360ca7f294f1ba391f8e11320 100644 --- a/src/vs/editor/common/services/modelServiceImpl.ts +++ b/src/vs/editor/common/services/modelServiceImpl.ts @@ -173,6 +173,7 @@ export class ModelServiceImpl implements IModelService { private _markerService: IMarkerService; private _markerServiceSubscription: IDisposable; private _threadService: IThreadService; + private _modeService: IModeService; private _workerHelper: ModelServiceWorkerHelper; private _onModelAdded: Emitter; @@ -184,9 +185,10 @@ export class ModelServiceImpl implements IModelService { */ private _models: {[modelId:string]:ModelData;}; - constructor(threadService: IThreadService, markerService: IMarkerService) { + constructor(threadService: IThreadService, markerService: IMarkerService, modeService:IModeService) { this._threadService = threadService; this._markerService = markerService; + this._modeService = modeService; this._workerHelper = this._threadService.getRemotable(ModelServiceWorkerHelper); this._models = {}; @@ -219,6 +221,14 @@ export class ModelServiceImpl implements IModelService { // --- begin IModelService + private _shouldSyncModelToWorkers(model:EditorCommon.IModel): boolean { + if (model.isTooLargeForHavingARichMode()) { + return false; + } + // Only sync models with compat modes to the workers + return this._modeService.isCompatMode(model.getMode().getId()); + } + private _createModelData(value:string, modeOrPromise:TPromise|Modes.IMode, resource: URI): ModelData { // create & save the model let model = new Model(value, modeOrPromise, resource); @@ -243,10 +253,9 @@ export class ModelServiceImpl implements IModelService { ModelMarkerHandler.setMarkers(modelData, this._markerService.read({ resource: modelData.model.getAssociatedResource() })); } - if (!modelData.model.isTooLargeForHavingARichMode()) { + if (this._shouldSyncModelToWorkers(modelData.model)) { // send this model to the workers - modelData.isSyncedToWorkers = true; - this._workerHelper.$_acceptNewModel(ModelServiceImpl._getBoundModelData(modelData.model)); + this._beginWorkerSync(modelData); } this._onModelAdded.fire(modelData.model); @@ -296,6 +305,23 @@ export class ModelServiceImpl implements IModelService { // --- end IModelService + private _beginWorkerSync(modelData:ModelData): void { + if (modelData.isSyncedToWorkers) { + throw new Error('Model is already being synced to workers!'); + } + + modelData.isSyncedToWorkers = true; + this._workerHelper.$_acceptNewModel(ModelServiceImpl._getBoundModelData(modelData.model)); + } + + private _stopWorkerSync(modelData:ModelData): void { + if (!modelData.isSyncedToWorkers) { + throw new Error('Model is already not being synced to workers!'); + } + modelData.isSyncedToWorkers = false; + this._workerHelper.$_acceptDidDisposeModel(modelData.model.getAssociatedResource()); + } + private _onModelDisposing(model:EditorCommon.IModel): void { let modelId = MODEL_ID(model.getAssociatedResource()); let modelData = this._models[modelId]; @@ -311,7 +337,7 @@ export class ModelServiceImpl implements IModelService { if (modelData.isSyncedToWorkers) { // Dispose model in workers - this._workerHelper.$_acceptDidDisposeModel(model.getAssociatedResource()); + this._stopWorkerSync(modelData); } delete this._models[modelId]; @@ -330,32 +356,63 @@ export class ModelServiceImpl implements IModelService { } private _onModelEvents(modelData:ModelData, events:IEmitterEvent[]): void { - let eventsForWorkers: IMirrorModelEvents = { contentChanged: [] }; + // First look for dispose for (let i = 0, len = events.length; i < len; i++) { let e = events[i]; - let data = e.getData(); - - switch (e.getType()) { - case EditorCommon.EventType.ModelDispose: - this._onModelDisposing(modelData.model); - // no more event processing - return; + if (e.getType() === EditorCommon.EventType.ModelDispose) { + this._onModelDisposing(modelData.model); + // no more processing since model got disposed + return; + } + } - case EditorCommon.EventType.ModelContentChanged: - if (modelData.isSyncedToWorkers) { - eventsForWorkers.contentChanged.push(data); - } - break; + // Second, look for mode change + for (let i = 0, len = events.length; i < len; i++) { + let e = events[i]; + if (e.getType() === EditorCommon.EventType.ModelModeChanged) { + let wasSyncedToWorkers = modelData.isSyncedToWorkers; + let shouldSyncToWorkers = this._shouldSyncModelToWorkers(modelData.model); - case EditorCommon.EventType.ModelModeChanged: - let modeChangedEvent = data; - if (modelData.isSyncedToWorkers) { + if (wasSyncedToWorkers) { + if (shouldSyncToWorkers) { + // true -> true // Forward mode change to all the workers - this._workerHelper.$_acceptDidChangeModelMode(modelData.getModelId(), modeChangedEvent.oldMode.getId(), modeChangedEvent.newMode.getId()); + this._workerHelper.$_acceptDidChangeModelMode(modelData.getModelId(), modelData.model.getMode().getId()); + } else { + // true -> false + // Stop worker sync for this model + this._stopWorkerSync(modelData); + // no more processing since we have removed the model from the workers + return; + } + } else { + if (shouldSyncToWorkers) { + // false -> true + // Begin syncing this model to the workers + this._beginWorkerSync(modelData); + // no more processing since we are sending the latest state + return; + } else { + // false -> false + // no more processing since this model was not synced and will not be synced + return; } - this._onModelModeChanged.fire({ model: modelData.model, oldModeId: modeChangedEvent.oldMode.getId() }); - break; + } + } + } + + if (!modelData.isSyncedToWorkers) { + return; + } + + // Finally, look for model content changes + let eventsForWorkers: IMirrorModelEvents = { contentChanged: [] }; + for (let i = 0, len = events.length; i < len; i++) { + let e = events[i]; + + if (e.getType() === EditorCommon.EventType.ModelContentChanged) { + eventsForWorkers.contentChanged.push(e.getData()); } } @@ -400,7 +457,7 @@ export class ModelServiceWorkerHelper { }); } - public $_acceptDidChangeModelMode(modelId:string, oldModeId:string, newModeId:string): TPromise { + public $_acceptDidChangeModelMode(modelId:string, newModeId:string): TPromise { let mirrorModel = this._resourceService.get(URI.parse(modelId)); // Block worker execution until the mode is instantiated diff --git a/src/vs/editor/test/common/servicesTestUtils.ts b/src/vs/editor/test/common/servicesTestUtils.ts index 5b1f4c6a43149e9b8aced63822cac95ba30f2819..185708cc901ab614cf016388eecf17f3c4c39e0b 100644 --- a/src/vs/editor/test/common/servicesTestUtils.ts +++ b/src/vs/editor/test/common/servicesTestUtils.ts @@ -155,6 +155,14 @@ export function createMockModeService(): IModeService { export function createMockModelService(): IModelService { var threadService = NULL_THREAD_SERVICE; - var modelService = new MockModelService(threadService, null); + var pluginService = new MockPluginService(); + var modeService = new MockModeService(threadService, pluginService); + var modelService = new MockModelService(threadService, null, modeService); + var inst = InstantiationService.create({ + threadService: threadService, + pluginService: pluginService, + modeService: modeService + }); + threadService.setInstantiationService(inst); return modelService; } \ No newline at end of file diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index c71c3696f0a01097a9096e851acc1365044df1ab..953f5cfdd797b168ea2530c454956150473f0efa 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -274,9 +274,9 @@ export class WorkbenchShell { let pluginService = new MainProcessPluginService(this.contextService, this.threadService, this.messageService, this.telemetryService); this.keybindingService.setPluginService(pluginService); - let modelService = new ModelServiceImpl(this.threadService, markerService); - let editorWorkerService = new EditorWorkerServiceImpl(modelService); let modeService = new MainThreadModeServiceImpl(this.threadService, pluginService); + let modelService = new ModelServiceImpl(this.threadService, markerService, modeService); + let editorWorkerService = new EditorWorkerServiceImpl(modelService); let untitledEditorService = new UntitledEditorService(); this.themeService = new ThemeService(pluginService);