From 7544095c9548c329c697577d97cd4177b3892480 Mon Sep 17 00:00:00 2001 From: Federico Bozzini Date: Fri, 25 Sep 2020 14:27:25 +0100 Subject: [PATCH] Fixed race condition on monaco editor initialization Signed-off-by: Federico Bozzini --- .../src/browser/monaco-editor-provider.ts | 21 +--------- .../src/browser/monaco-text-model-service.ts | 41 ++++++++++++++++++- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/packages/monaco/src/browser/monaco-editor-provider.ts b/packages/monaco/src/browser/monaco-editor-provider.ts index 73334783beef1..36ccafaf09d6e 100644 --- a/packages/monaco/src/browser/monaco-editor-provider.ts +++ b/packages/monaco/src/browser/monaco-editor-provider.ts @@ -35,7 +35,7 @@ import { MonacoBulkEditService } from './monaco-bulk-edit-service'; import IEditorOverrideServices = monaco.editor.IEditorOverrideServices; import { ApplicationServer } from '@theia/core/lib/common/application-protocol'; -import { OS, ContributionProvider } from '@theia/core'; +import { ContributionProvider } from '@theia/core'; import { KeybindingRegistry, OpenerService, open, WidgetOpenerOptions, FormatType } from '@theia/core/lib/browser'; import { MonacoResolvedKeybinding } from './monaco-resolved-keybinding'; import { HttpOpenHandlerOptions } from '@theia/core/lib/browser/http-open-handler'; @@ -67,8 +67,6 @@ export class MonacoEditorProvider { @inject(OpenerService) protected readonly openerService: OpenerService; - private isWindowsBackend: boolean = false; - protected _current: MonacoEditor | undefined; /** * Returns the last focused MonacoEditor. @@ -90,28 +88,13 @@ export class MonacoEditorProvider { @inject(EditorPreferences) protected readonly editorPreferences: EditorPreferences, @inject(MonacoQuickOpenService) protected readonly quickOpenService: MonacoQuickOpenService, @inject(MonacoDiffNavigatorFactory) protected readonly diffNavigatorFactory: MonacoDiffNavigatorFactory, + /** @deprecated since 1.6.0 */ @inject(ApplicationServer) protected readonly applicationServer: ApplicationServer, @inject(monaco.contextKeyService.ContextKeyService) protected readonly contextKeyService: monaco.contextKeyService.ContextKeyService ) { const staticServices = monaco.services.StaticServices; const init = staticServices.init.bind(monaco.services.StaticServices); - this.applicationServer.getBackendOS().then(os => { - this.isWindowsBackend = os === OS.Type.Windows; - }); - if (staticServices.resourcePropertiesService) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const original = staticServices.resourcePropertiesService.get() as any; - original.getEOL = () => { - const eol = this.editorPreferences['files.eol']; - if (eol) { - if (eol !== 'auto') { - return eol; - } - } - return this.isWindowsBackend ? '\r\n' : '\n'; - }; - } monaco.services.StaticServices.init = o => { const result = init(o); result[0].set(monaco.services.ICodeEditorService, codeEditorService); diff --git a/packages/monaco/src/browser/monaco-text-model-service.ts b/packages/monaco/src/browser/monaco-text-model-service.ts index 5b97678e4dc67..ecaa9e5c3458e 100644 --- a/packages/monaco/src/browser/monaco-text-model-service.ts +++ b/packages/monaco/src/browser/monaco-text-model-service.ts @@ -14,15 +14,17 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { inject, injectable, named } from 'inversify'; +import { inject, injectable, named, postConstruct } from 'inversify'; import URI from '@theia/core/lib/common/uri'; -import { ResourceProvider, ReferenceCollection, Event, MaybePromise, Resource, ContributionProvider } from '@theia/core'; +import { ResourceProvider, ReferenceCollection, Event, MaybePromise, Resource, ContributionProvider, OS } from '@theia/core'; import { EditorPreferences, EditorPreferenceChange } from '@theia/editor/lib/browser'; import { MonacoEditorModel } from './monaco-editor-model'; import IReference = monaco.editor.IReference; import { MonacoToProtocolConverter } from './monaco-to-protocol-converter'; import { ProtocolToMonacoConverter } from './protocol-to-monaco-converter'; import { ILogger } from '@theia/core/lib/common/logger'; +import { ApplicationServer } from '@theia/core/lib/common/application-protocol'; +import { Deferred } from '@theia/core/lib/common/promise-util'; export { IReference }; export const MonacoEditorModelFactory = Symbol('MonacoEditorModelFactory'); @@ -39,6 +41,12 @@ export interface MonacoEditorModelFactory { @injectable() export class MonacoTextModelService implements monaco.editor.ITextModelService { + protected readonly _ready = new Deferred(); + /** + * This component does some asynchronous work before being fully initialized. + */ + readonly ready: Promise = this._ready.promise; + protected readonly _models = new ReferenceCollection( uri => this.loadModel(new URI(uri)) ); @@ -62,6 +70,34 @@ export class MonacoTextModelService implements monaco.editor.ITextModelService { @inject(ILogger) protected readonly logger: ILogger; + @inject(ApplicationServer) + protected readonly applicationServer!: ApplicationServer; + + @postConstruct() + public init(): void { + let isWindowsBackend = false; + + this.applicationServer.getBackendOS().then(os => { + isWindowsBackend = os === OS.Type.Windows; + }, () => undefined).then(() => this._ready.resolve()); + + const staticServices = monaco.services.StaticServices; + + if (staticServices.resourcePropertiesService) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const original = staticServices.resourcePropertiesService.get() as any; + original.getEOL = () => { + const eol = this.editorPreferences['files.eol']; + if (eol) { + if (eol !== 'auto') { + return eol; + } + } + return isWindowsBackend ? '\r\n' : '\n'; + }; + } + } + get models(): MonacoEditorModel[] { return this._models.values(); } @@ -79,6 +115,7 @@ export class MonacoTextModelService implements monaco.editor.ITextModelService { } protected async loadModel(uri: URI): Promise { + await this.ready; await this.editorPreferences.ready; const resource = await this.resourceProvider(uri); const model = await (await this.createModel(resource)).load();