From 3ddca955fe7f9b371c94086871838c0c99d1a870 Mon Sep 17 00:00:00 2001 From: Anatoliy Bazko Date: Fri, 26 Apr 2019 14:10:33 +0300 Subject: [PATCH] Fix Signed-off-by: Anatoliy Bazko --- .../browser/frontend-application-module.ts | 3 ++ packages/core/src/browser/mime-service.ts | 30 ++++++++++++++ .../filesystem-frontend-contribution.ts | 24 ++++++++++- .../src/browser/filesystem-preferences.ts | 6 +++ .../src/browser/monaco-frontend-module.ts | 5 +++ packages/monaco/src/browser/monaco-loader.ts | 4 +- .../monaco/src/browser/monaco-mime-service.ts | 41 +++++++++++++++++++ packages/monaco/src/typings/monaco/index.d.ts | 16 ++++++++ .../src/plugin/preference-registry.ts | 1 - 9 files changed, 127 insertions(+), 3 deletions(-) create mode 100644 packages/core/src/browser/mime-service.ts create mode 100644 packages/monaco/src/browser/monaco-mime-service.ts diff --git a/packages/core/src/browser/frontend-application-module.ts b/packages/core/src/browser/frontend-application-module.ts index 4368107cd719a..622607fd662f3 100644 --- a/packages/core/src/browser/frontend-application-module.ts +++ b/packages/core/src/browser/frontend-application-module.ts @@ -72,6 +72,7 @@ import { QuickPickService, quickPickServicePath } from '../common/quick-pick-ser import { ContextKeyService } from './context-key-service'; import { ResourceContextKey } from './resource-context-key'; import { KeyboardLayoutService } from './keyboard/keyboard-layout-service'; +import { MimeService } from './mime-service'; export const frontendApplicationModule = new ContainerModule((bind, unbind, isBound, rebind) => { const themeService = ThemeService.get(); @@ -249,4 +250,6 @@ export const frontendApplicationModule = new ContainerModule((bind, unbind, isBo ); bindCorePreferences(bind); + + bind(MimeService).toSelf().inSingletonScope(); }); diff --git a/packages/core/src/browser/mime-service.ts b/packages/core/src/browser/mime-service.ts new file mode 100644 index 0000000000000..bab21ecde7667 --- /dev/null +++ b/packages/core/src/browser/mime-service.ts @@ -0,0 +1,30 @@ +/******************************************************************************** + * Copyright (C) 2019 Red Hat, Inc. and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ********************************************************************************/ + +import { injectable } from 'inversify'; + +export interface MimeAssociation { + readonly id: string; + readonly filepattern: string; +} + +@injectable() +export class MimeService { + // should be overridden by an implementation + setAssociations(associations: MimeAssociation[]): void { + /* no-op by default */ + } +} diff --git a/packages/filesystem/src/browser/filesystem-frontend-contribution.ts b/packages/filesystem/src/browser/filesystem-frontend-contribution.ts index dee024de70f37..a4dcdf54ebb95 100644 --- a/packages/filesystem/src/browser/filesystem-frontend-contribution.ts +++ b/packages/filesystem/src/browser/filesystem-frontend-contribution.ts @@ -20,9 +20,11 @@ import { MaybePromise } from '@theia/core/lib/common'; import { FrontendApplicationContribution, ApplicationShell, NavigatableWidget, NavigatableWidgetOptions, - Saveable, WidgetManager, StatefulWidget + Saveable, WidgetManager, StatefulWidget, FrontendApplication } from '@theia/core/lib/browser'; import { FileSystemWatcher, FileChangeEvent, FileMoveEvent, FileChangeType } from './filesystem-watcher'; +import { MimeService } from '@theia/core/lib/browser/mime-service'; +import { FileSystemPreferences } from './filesystem-preferences'; @injectable() export class FileSystemFrontendContribution implements FrontendApplicationContribution { @@ -36,11 +38,26 @@ export class FileSystemFrontendContribution implements FrontendApplicationContri @inject(FileSystemWatcher) protected readonly fileSystemWatcher: FileSystemWatcher; + @inject(MimeService) + protected readonly mimeService: MimeService; + + @inject(FileSystemPreferences) + protected readonly preferences: FileSystemPreferences; + initialize(): void { this.fileSystemWatcher.onFilesChanged(event => this.run(() => this.updateWidgets(event))); this.fileSystemWatcher.onDidMove(event => this.run(() => this.moveWidgets(event))); } + onStart?(app: FrontendApplication): MaybePromise { + this.updateAssociations(); + this.preferences.onPreferenceChanged(e => { + if (e.preferenceName === 'files.associations') { + this.updateAssociations(); + } + }); + } + protected pendingOperation = Promise.resolve(); protected run(operation: () => MaybePromise): Promise { return this.pendingOperation = this.pendingOperation.then(async () => { @@ -141,4 +158,9 @@ export class FileSystemFrontendContribution implements FrontendApplicationContri } } + protected updateAssociations(): void { + const fileAssociations = this.preferences['files.associations']; + const mimeAssociations = Object.keys(fileAssociations).map(filepattern => ({ id: fileAssociations[filepattern], filepattern })); + this.mimeService.setAssociations(mimeAssociations); + } } diff --git a/packages/filesystem/src/browser/filesystem-preferences.ts b/packages/filesystem/src/browser/filesystem-preferences.ts index aee86e22f7fd9..9d6bf6b147ba0 100644 --- a/packages/filesystem/src/browser/filesystem-preferences.ts +++ b/packages/filesystem/src/browser/filesystem-preferences.ts @@ -48,6 +48,11 @@ export const filesystemPreferenceSchema: PreferenceSchema = { 'type': 'boolean', 'default': true, 'description': 'Moves files/folders to the OS trash (recycle bin on Windows) when deleting. Disabling this will delete files/folders permanently.' + }, + 'files.associations': { + 'type': 'object', + 'description': 'Configure file associations to languages (e.g. \"*.extension\": \"html\"). \ +These have precedence over the default associations of the languages installed.' } } }; @@ -56,6 +61,7 @@ export interface FileSystemConfiguration { 'files.watcherExclude': { [globPattern: string]: boolean }; 'files.exclude': { [key: string]: boolean }; 'files.enableTrash': boolean; + 'files.associations': { [filepattern: string]: string }; } export const FileSystemPreferences = Symbol('FileSystemPreferences'); diff --git a/packages/monaco/src/browser/monaco-frontend-module.ts b/packages/monaco/src/browser/monaco-frontend-module.ts index e886fc431b3df..8d7f86881be49 100644 --- a/packages/monaco/src/browser/monaco-frontend-module.ts +++ b/packages/monaco/src/browser/monaco-frontend-module.ts @@ -52,6 +52,8 @@ import { OutlineTreeDecorator } from '@theia/outline-view/lib/browser/outline-de import { MonacoSnippetSuggestProvider } from './monaco-snippet-suggest-provider'; import { ContextKeyService } from '@theia/core/lib/browser/context-key-service'; import { MonacoContextKeyService } from './monaco-context-key-service'; +import { MonacoMimeService } from './monaco-mime-service'; +import { MimeService } from '@theia/core/lib/browser/mime-service'; const deepmerge: (args: object[]) => object = require('deepmerge').default.all; @@ -119,6 +121,9 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => { bind(MonacoOutlineDecorator).toSelf().inSingletonScope(); bind(OutlineTreeDecorator).toService(MonacoOutlineDecorator); + + bind(MonacoMimeService).toSelf().inSingletonScope(); + rebind(MimeService).toService(MonacoMimeService); }); export const MonacoConfigurationService = Symbol('MonacoConfigurationService'); diff --git a/packages/monaco/src/browser/monaco-loader.ts b/packages/monaco/src/browser/monaco-loader.ts index fe12963d6d8c8..b6e7fd0814474 100644 --- a/packages/monaco/src/browser/monaco-loader.ts +++ b/packages/monaco/src/browser/monaco-loader.ts @@ -53,6 +53,7 @@ export function loadMonaco(vsRequire: any): Promise { 'vs/platform/keybinding/common/usLayoutResolvedKeybinding', 'vs/base/common/keybindingLabels', 'vs/base/common/keyCodes', + 'vs/base/common/mime', 'vs/editor/browser/editorExtensions', 'vs/editor/standalone/browser/simpleServices', 'vs/editor/standalone/browser/standaloneServices', @@ -76,7 +77,7 @@ export function loadMonaco(vsRequire: any): Promise { 'vs/platform/contextkey/browser/contextKeyService' ], (css: any, html: any, commands: any, actions: any, keybindingsRegistry: any, keybindingResolver: any, resolvedKeybinding: any, keybindingLabels: any, - keyCodes: any, editorExtensions: any, simpleServices: any, standaloneServices: any, quickOpen: any, quickOpenWidget: any, quickOpenModel: any, + keyCodes: any, mime: any, editorExtensions: any, simpleServices: any, standaloneServices: any, quickOpen: any, quickOpenWidget: any, quickOpenModel: any, filters: any, styler: any, platform: any, modes: any, suggest: any, suggestController: any, findController: any, rename: any, snippetParser: any, configuration: any, configurationModels: any, codeEditorService: any, codeEditorServiceImpl: any, @@ -99,6 +100,7 @@ export function loadMonaco(vsRequire: any): Promise { global.monaco.snippetParser = snippetParser; global.monaco.contextkey = contextKey; global.monaco.contextKeyService = contextKeyService; + global.monaco.mime = mime; resolve(); }); }); diff --git a/packages/monaco/src/browser/monaco-mime-service.ts b/packages/monaco/src/browser/monaco-mime-service.ts new file mode 100644 index 0000000000000..9af0b54185c78 --- /dev/null +++ b/packages/monaco/src/browser/monaco-mime-service.ts @@ -0,0 +1,41 @@ +/******************************************************************************** + * Copyright (C) 2019 Red Hat, Inc. and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ********************************************************************************/ + +import { MimeAssociation, MimeService } from '@theia/core/lib/browser/mime-service'; +import { injectable } from 'inversify'; + +@injectable() +export class MonacoMimeService extends MimeService { + + setAssociations(associations: MimeAssociation[]): void { + monaco.mime.clearTextMimes(true); + + for (const association of associations) { + const mimetype = this.getMimeForMode(association.id) || `text/x-${association.id}`; + monaco.mime.registerTextMime({ id: association.id, mime: mimetype, filepattern: association.filepattern, userConfigured: true }, false); + } + } + + protected getMimeForMode(langId: string): string | undefined { + for (const language of monaco.languages.getLanguages()) { + if (language.id === langId && language.mimetypes) { + return language.mimetypes[0]; + } + } + + return undefined; + } +} diff --git a/packages/monaco/src/typings/monaco/index.d.ts b/packages/monaco/src/typings/monaco/index.d.ts index 2e73713e57baa..b44fbae6b9670 100644 --- a/packages/monaco/src/typings/monaco/index.d.ts +++ b/packages/monaco/src/typings/monaco/index.d.ts @@ -1112,3 +1112,19 @@ declare module monaco.contextkey { static deserialize(when: string): ContextKeyExpr; } } + +declare module monaco.mime { + export interface ITextMimeAssociation { + readonly id: string; + readonly mime: string; + readonly filename?: string; + readonly extension?: string; + readonly filepattern?: string; + readonly firstline?: RegExp; + readonly userConfigured?: boolean; + } + + export function registerTextMime(association: monaco.mime.ITextMimeAssociation, warnOnOverwrite: boolean): void + + export function clearTextMimes(onlyUserConfigured?: boolean): void; +} diff --git a/packages/plugin-ext/src/plugin/preference-registry.ts b/packages/plugin-ext/src/plugin/preference-registry.ts index 0e4385f51ef7f..fa74a71b15418 100644 --- a/packages/plugin-ext/src/plugin/preference-registry.ts +++ b/packages/plugin-ext/src/plugin/preference-registry.ts @@ -80,7 +80,6 @@ export class PreferenceRegistryExtImpl implements PreferenceRegistryExt { } init(data: PreferenceData): void { - data[PreferenceScope.Default]['files.associations'] = {}; this._preferences = this.parse(data); }