Skip to content

Commit

Permalink
fix #5025: reload plugins on reconnect
Browse files Browse the repository at this point in the history
also fix #5829: ensure that each plugin is loaded only once

Signed-off-by: Anton Kosyakov <anton.kosyakov@typefox.io>
  • Loading branch information
akosyakov committed Sep 16, 2019
1 parent dbb25e0 commit 2a653b5
Show file tree
Hide file tree
Showing 48 changed files with 1,001 additions and 704 deletions.
6 changes: 5 additions & 1 deletion packages/core/src/browser/keybinding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { injectable, inject, named } from 'inversify';
import { isOSX } from '../common/os';
import { Emitter, Event } from '../common/event';
import { CommandRegistry } from '../common/command';
import { Disposable } from '../common/disposable';
import { KeyCode, KeySequence, Key } from './keyboard/keys';
import { KeyboardLayoutService } from './keyboard/keyboard-layout-service';
import { ContributionProvider } from '../common/contribution-provider';
Expand Down Expand Up @@ -639,10 +640,13 @@ export class KeybindingRegistry {
return commandId === KeybindingRegistry.PASSTHROUGH_PSEUDO_COMMAND;
}

setKeymap(scope: KeybindingScope, bindings: Keybinding[]): void {
setKeymap(scope: KeybindingScope, bindings: Keybinding[]): Disposable {
this.resetKeybindingsForScope(scope);
this.doRegisterKeybindings(bindings, scope);
this.keybindingsChanged.fire(undefined);
return Disposable.create(() => {
// TODO
});
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import * as Ajv from 'ajv';
import { inject, injectable, interfaces, named, postConstruct } from 'inversify';
import { ContributionProvider, bindContributionProvider, escapeRegExpCharacters, Emitter, Event } from '../../common';
import { ContributionProvider, bindContributionProvider, escapeRegExpCharacters, Emitter, Event, Disposable } from '../../common';
import { PreferenceScope } from './preference-scope';
import { PreferenceProvider, PreferenceProviderDataChange } from './preference-provider';
import {
Expand Down Expand Up @@ -249,10 +249,15 @@ export class PreferenceSchemaProvider extends PreferenceProvider {
return this.combinedSchema;
}

setSchema(schema: PreferenceSchema): void {
setSchema(schema: PreferenceSchema): Disposable {
const changes = this.doSetSchema(schema);
this.fireDidPreferenceSchemaChanged();
this.emitPreferencesChangedEvent(changes);
return {
dispose: () => {
// TODO: unset schema
}
};
}

getPreferences(): { [name: string]: any } {
Expand Down
10 changes: 8 additions & 2 deletions packages/core/src/browser/quick-open/quick-command-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
********************************************************************************/

import { inject, injectable } from 'inversify';
import { Command, CommandRegistry } from '../../common';
import { Command, CommandRegistry, Disposable } from '../../common';
import { Keybinding, KeybindingRegistry } from '../keybinding';
import { QuickOpenModel, QuickOpenItem, QuickOpenMode, QuickOpenGroupItem, QuickOpenGroupItemOptions } from './quick-open-model';
import { QuickOpenOptions } from './quick-open-service';
Expand Down Expand Up @@ -51,10 +51,16 @@ export class QuickCommandService implements QuickOpenModel, QuickOpenHandler {
protected readonly corePreferences: CorePreferences;

protected readonly contexts = new Map<string, string[]>();
pushCommandContext(commandId: string, when: string): void {
pushCommandContext(commandId: string, when: string): Disposable {
const contexts = this.contexts.get(commandId) || [];
contexts.push(when);
this.contexts.set(commandId, contexts);
return Disposable.create(() => {
const index = contexts.indexOf(when);
if (index !== -1) {
contexts.splice(index, 1);
}
});
}

/** Initialize this quick open model with the commands. */
Expand Down
6 changes: 5 additions & 1 deletion packages/core/src/common/disposable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ export interface Disposable {
}

export namespace Disposable {
// tslint:disable-next-line:no-any
export function is(arg: any): arg is Disposable {
return !!arg && typeof arg === 'object' && 'dispose' in arg && typeof arg['dispose'] === 'function';
}
export function create(func: () => void): Disposable {
return {
dispose: func
Expand Down Expand Up @@ -56,7 +60,7 @@ export class DisposableCollection implements Disposable {

private disposingElements = false;
dispose(): void {
if (this.disposed || this.disposingElements) {
if (this.disposed || this.disposingElements) {
return;
}
this.disposingElements = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import * as jsoncparser from 'jsonc-parser';
import { injectable, inject } from 'inversify';
import URI from '@theia/core/lib/common/uri';
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
import { FileSystem, FileSystemError } from '@theia/filesystem/lib/common';
import { CompletionTriggerKind } from '@theia/languages/lib/browser';

Expand Down Expand Up @@ -114,7 +115,8 @@ export class MonacoSnippetSuggestProvider implements monaco.languages.Completion
}
}

fromURI(uri: string | URI, options: SnippetLoadOptions): Promise<void> {
fromURI(uri: string | URI, options: SnippetLoadOptions): Disposable {
const toDispose = new DisposableCollection();
const pending = this.loadURI(uri, options);
const { language } = options;
const scopes = Array.isArray(language) ? language : !!language ? [language] : ['*'];
Expand All @@ -123,7 +125,8 @@ export class MonacoSnippetSuggestProvider implements monaco.languages.Completion
pendingSnippets.push(pending);
this.pendingSnippets.set(scope, pendingSnippets);
}
return pending;
// TODO unload snippets
return toDispose;
}
/**
* should NOT throw to prevent load erros on suggest
Expand Down
14 changes: 14 additions & 0 deletions packages/monaco/src/browser/textmate/monaco-textmate-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import { LanguageGrammarDefinitionContribution, getEncodedLanguageId } from './t
import { createTextmateTokenizer, TokenizerOption } from './textmate-tokenizer';
import { TextmateRegistry } from './textmate-registry';
import { MonacoThemeRegistry } from './monaco-theme-registry';
import { MonacoEditor } from '../monaco-editor';
import { EditorManager } from '@theia/editor/lib/browser';

export const OnigasmPromise = Symbol('OnigasmPromise');
export type OnigasmPromise = Promise<IOnigLib>;
Expand Down Expand Up @@ -58,6 +60,9 @@ export class MonacoTextmateService implements FrontendApplicationContribution {
@inject(MonacoThemeRegistry)
protected readonly monacoThemeRegistry: MonacoThemeRegistry;

@inject(EditorManager)
private readonly editorManager: EditorManager;

initialize(): void {
if (!isBasicWasmSupported) {
console.log('Textmate support deactivated because WebAssembly is not detected.');
Expand Down Expand Up @@ -104,6 +109,7 @@ export class MonacoTextmateService implements FrontendApplicationContribution {
for (const { id } of monaco.languages.getLanguages()) {
monaco.languages.onLanguage(id, () => this.activateLanguage(id));
}
this.detectLanguages();
}

protected readonly toDisposeOnUpdateTheme = new DisposableCollection();
Expand Down Expand Up @@ -159,4 +165,12 @@ export class MonacoTextmateService implements FrontendApplicationContribution {
this.onDidActivateLanguageEmitter.fire(languageId);
}
}

detectLanguages(): void {
for (const editor of MonacoEditor.getAll(this.editorManager)) {
if (editor.languageAutoDetected) {
editor.detectLanguage();
}
}
}
}
28 changes: 24 additions & 4 deletions packages/monaco/src/browser/textmate/textmate-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import { injectable } from 'inversify';
import { IGrammarConfiguration } from 'vscode-textmate';
import { TokenizerOption } from './textmate-tokenizer';
import { Disposable } from '@theia/core/lib/common/disposable';

export interface TextmateGrammarConfiguration extends IGrammarConfiguration {

Expand Down Expand Up @@ -45,7 +46,7 @@ export class TextmateRegistry {
readonly languageToConfig = new Map<string, TextmateGrammarConfiguration>();
readonly languageIdToScope = new Map<string, string>();

registerTextmateGrammarScope(scope: string, description: GrammarDefinitionProvider): void {
registerTextmateGrammarScope(scope: string, description: GrammarDefinitionProvider): Disposable {
const existingProvider = this.scopeToProvider.get(scope);
if (existingProvider) {
Promise.all([existingProvider.getGrammarDefinition(), description.getGrammarDefinition()]).then(([a, b]) => {
Expand All @@ -55,18 +56,30 @@ export class TextmateRegistry {
});
}
this.scopeToProvider.set(scope, description);
return Disposable.create(() => {
this.scopeToProvider.delete(scope);
if (existingProvider) {
this.scopeToProvider.set(scope, existingProvider);
}
});
}

getProvider(scope: string): GrammarDefinitionProvider | undefined {
return this.scopeToProvider.get(scope);
}

mapLanguageIdToTextmateGrammar(languageId: string, scope: string): void {
mapLanguageIdToTextmateGrammar(languageId: string, scope: string): Disposable {
const existingScope = this.getScope(languageId);
if (typeof existingScope === 'string') {
console.warn(new Error(`'${languageId}' language is remapped from '${existingScope}' to '${scope}' scope`));
}
this.languageIdToScope.set(languageId, scope);
return Disposable.create(() => {
this.languageIdToScope.delete(languageId);
if (typeof existingScope === 'string') {
this.languageIdToScope.set(languageId, existingScope);
}
});
}

getScope(languageId: string): string | undefined {
Expand All @@ -82,11 +95,18 @@ export class TextmateRegistry {
return undefined;
}

registerGrammarConfiguration(languageId: string, config: TextmateGrammarConfiguration): void {
if (this.languageToConfig.has(languageId)) {
registerGrammarConfiguration(languageId: string, config: TextmateGrammarConfiguration): Disposable {
const existignConfig = this.languageToConfig.get(languageId);
if (existignConfig) {
console.warn(new Error(`a registered grammar configuration for '${languageId}' language is overridden`));
}
this.languageToConfig.set(languageId, config);
return Disposable.create(() => {
this.languageToConfig.delete(languageId);
if (existignConfig) {
this.languageToConfig.set(languageId, existignConfig);
}
});
}

getGrammarConfiguration(languageId: string): TextmateGrammarConfiguration {
Expand Down
5 changes: 4 additions & 1 deletion packages/plugin-ext/src/common/plugin-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
import { JsonRpcServer } from '@theia/core/lib/common/messaging/proxy-factory';
import { JsonRpcServer, JsonRpcProxy } from '@theia/core/lib/common/messaging/proxy-factory';
import { RPCProtocol } from './rpc-protocol';
import { Disposable } from '@theia/core/lib/common/disposable';
import { LogPart, KeysToAnyValues, KeysToKeysToAnyValue } from './types';
Expand Down Expand Up @@ -634,6 +634,9 @@ export interface HostedPluginServer extends JsonRpcServer<HostedPluginClient> {

}

export const HostedPluginServerProxy = Symbol('HostedPluginServerProxy');
export type HostedPluginServerProxy = JsonRpcProxy<HostedPluginServer>;

/**
* The JSON-RPC workspace interface.
*/
Expand Down
Loading

0 comments on commit 2a653b5

Please sign in to comment.