Skip to content

Commit

Permalink
adopt PauseableEmitter in ContextKeyService and for EditorModeContext,
Browse files Browse the repository at this point in the history
  • Loading branch information
jrieken committed Apr 3, 2019
1 parent 1c1ff99 commit ae83621
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 76 deletions.
125 changes: 63 additions & 62 deletions src/vs/editor/browser/widget/codeEditorWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1628,8 +1628,6 @@ class EditorContextKeysManager extends Disposable {

export class EditorModeContext extends Disposable {

private readonly _editor: CodeEditorWidget;

private readonly _langId: IContextKey<string>;
private readonly _hasCompletionItemProvider: IContextKey<boolean>;
private readonly _hasCodeActionsProvider: IContextKey<boolean>;
Expand All @@ -1651,37 +1649,36 @@ export class EditorModeContext extends Disposable {
private readonly _isInWalkThrough: IContextKey<boolean>;

constructor(
editor: CodeEditorWidget,
contextKeyService: IContextKeyService
private readonly _editor: CodeEditorWidget,
private readonly _contextKeyService: IContextKeyService
) {
super();
this._editor = editor;

this._langId = EditorContextKeys.languageId.bindTo(contextKeyService);
this._hasCompletionItemProvider = EditorContextKeys.hasCompletionItemProvider.bindTo(contextKeyService);
this._hasCodeActionsProvider = EditorContextKeys.hasCodeActionsProvider.bindTo(contextKeyService);
this._hasCodeLensProvider = EditorContextKeys.hasCodeLensProvider.bindTo(contextKeyService);
this._hasDefinitionProvider = EditorContextKeys.hasDefinitionProvider.bindTo(contextKeyService);
this._hasDeclarationProvider = EditorContextKeys.hasDeclarationProvider.bindTo(contextKeyService);
this._hasImplementationProvider = EditorContextKeys.hasImplementationProvider.bindTo(contextKeyService);
this._hasTypeDefinitionProvider = EditorContextKeys.hasTypeDefinitionProvider.bindTo(contextKeyService);
this._hasHoverProvider = EditorContextKeys.hasHoverProvider.bindTo(contextKeyService);
this._hasDocumentHighlightProvider = EditorContextKeys.hasDocumentHighlightProvider.bindTo(contextKeyService);
this._hasDocumentSymbolProvider = EditorContextKeys.hasDocumentSymbolProvider.bindTo(contextKeyService);
this._hasReferenceProvider = EditorContextKeys.hasReferenceProvider.bindTo(contextKeyService);
this._hasRenameProvider = EditorContextKeys.hasRenameProvider.bindTo(contextKeyService);
this._hasSignatureHelpProvider = EditorContextKeys.hasSignatureHelpProvider.bindTo(contextKeyService);
this._hasDocumentFormattingProvider = EditorContextKeys.hasDocumentFormattingProvider.bindTo(contextKeyService);
this._hasDocumentSelectionFormattingProvider = EditorContextKeys.hasDocumentSelectionFormattingProvider.bindTo(contextKeyService);
this._hasMultipleDocumentFormattingProvider = EditorContextKeys.hasMultipleDocumentFormattingProvider.bindTo(contextKeyService);
this._hasMultipleDocumentSelectionFormattingProvider = EditorContextKeys.hasMultipleDocumentSelectionFormattingProvider.bindTo(contextKeyService);
this._isInWalkThrough = EditorContextKeys.isInEmbeddedEditor.bindTo(contextKeyService);
this._langId = EditorContextKeys.languageId.bindTo(_contextKeyService);
this._hasCompletionItemProvider = EditorContextKeys.hasCompletionItemProvider.bindTo(_contextKeyService);
this._hasCodeActionsProvider = EditorContextKeys.hasCodeActionsProvider.bindTo(_contextKeyService);
this._hasCodeLensProvider = EditorContextKeys.hasCodeLensProvider.bindTo(_contextKeyService);
this._hasDefinitionProvider = EditorContextKeys.hasDefinitionProvider.bindTo(_contextKeyService);
this._hasDeclarationProvider = EditorContextKeys.hasDeclarationProvider.bindTo(_contextKeyService);
this._hasImplementationProvider = EditorContextKeys.hasImplementationProvider.bindTo(_contextKeyService);
this._hasTypeDefinitionProvider = EditorContextKeys.hasTypeDefinitionProvider.bindTo(_contextKeyService);
this._hasHoverProvider = EditorContextKeys.hasHoverProvider.bindTo(_contextKeyService);
this._hasDocumentHighlightProvider = EditorContextKeys.hasDocumentHighlightProvider.bindTo(_contextKeyService);
this._hasDocumentSymbolProvider = EditorContextKeys.hasDocumentSymbolProvider.bindTo(_contextKeyService);
this._hasReferenceProvider = EditorContextKeys.hasReferenceProvider.bindTo(_contextKeyService);
this._hasRenameProvider = EditorContextKeys.hasRenameProvider.bindTo(_contextKeyService);
this._hasSignatureHelpProvider = EditorContextKeys.hasSignatureHelpProvider.bindTo(_contextKeyService);
this._hasDocumentFormattingProvider = EditorContextKeys.hasDocumentFormattingProvider.bindTo(_contextKeyService);
this._hasDocumentSelectionFormattingProvider = EditorContextKeys.hasDocumentSelectionFormattingProvider.bindTo(_contextKeyService);
this._hasMultipleDocumentFormattingProvider = EditorContextKeys.hasMultipleDocumentFormattingProvider.bindTo(_contextKeyService);
this._hasMultipleDocumentSelectionFormattingProvider = EditorContextKeys.hasMultipleDocumentSelectionFormattingProvider.bindTo(_contextKeyService);
this._isInWalkThrough = EditorContextKeys.isInEmbeddedEditor.bindTo(_contextKeyService);

const update = () => this._update();

// update when model/mode changes
this._register(editor.onDidChangeModel(update));
this._register(editor.onDidChangeModelLanguage(update));
this._register(_editor.onDidChangeModel(update));
this._register(_editor.onDidChangeModelLanguage(update));

// update when registries change
this._register(modes.CompletionProviderRegistry.onDidChange(update));
Expand All @@ -1708,23 +1705,25 @@ export class EditorModeContext extends Disposable {
}

reset() {
this._langId.reset();
this._hasCompletionItemProvider.reset();
this._hasCodeActionsProvider.reset();
this._hasCodeLensProvider.reset();
this._hasDefinitionProvider.reset();
this._hasDeclarationProvider.reset();
this._hasImplementationProvider.reset();
this._hasTypeDefinitionProvider.reset();
this._hasHoverProvider.reset();
this._hasDocumentHighlightProvider.reset();
this._hasDocumentSymbolProvider.reset();
this._hasReferenceProvider.reset();
this._hasRenameProvider.reset();
this._hasDocumentFormattingProvider.reset();
this._hasDocumentSelectionFormattingProvider.reset();
this._hasSignatureHelpProvider.reset();
this._isInWalkThrough.reset();
this._contextKeyService.bufferChangeEvents(() => {
this._langId.reset();
this._hasCompletionItemProvider.reset();
this._hasCodeActionsProvider.reset();
this._hasCodeLensProvider.reset();
this._hasDefinitionProvider.reset();
this._hasDeclarationProvider.reset();
this._hasImplementationProvider.reset();
this._hasTypeDefinitionProvider.reset();
this._hasHoverProvider.reset();
this._hasDocumentHighlightProvider.reset();
this._hasDocumentSymbolProvider.reset();
this._hasReferenceProvider.reset();
this._hasRenameProvider.reset();
this._hasDocumentFormattingProvider.reset();
this._hasDocumentSelectionFormattingProvider.reset();
this._hasSignatureHelpProvider.reset();
this._isInWalkThrough.reset();
});
}

private _update() {
Expand All @@ -1733,25 +1732,27 @@ export class EditorModeContext extends Disposable {
this.reset();
return;
}
this._langId.set(model.getLanguageIdentifier().language);
this._hasCompletionItemProvider.set(modes.CompletionProviderRegistry.has(model));
this._hasCodeActionsProvider.set(modes.CodeActionProviderRegistry.has(model));
this._hasCodeLensProvider.set(modes.CodeLensProviderRegistry.has(model));
this._hasDefinitionProvider.set(modes.DefinitionProviderRegistry.has(model));
this._hasDeclarationProvider.set(modes.DeclarationProviderRegistry.has(model));
this._hasImplementationProvider.set(modes.ImplementationProviderRegistry.has(model));
this._hasTypeDefinitionProvider.set(modes.TypeDefinitionProviderRegistry.has(model));
this._hasHoverProvider.set(modes.HoverProviderRegistry.has(model));
this._hasDocumentHighlightProvider.set(modes.DocumentHighlightProviderRegistry.has(model));
this._hasDocumentSymbolProvider.set(modes.DocumentSymbolProviderRegistry.has(model));
this._hasReferenceProvider.set(modes.ReferenceProviderRegistry.has(model));
this._hasRenameProvider.set(modes.RenameProviderRegistry.has(model));
this._hasSignatureHelpProvider.set(modes.SignatureHelpProviderRegistry.has(model));
this._hasDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.has(model) || modes.DocumentRangeFormattingEditProviderRegistry.has(model));
this._hasDocumentSelectionFormattingProvider.set(modes.DocumentRangeFormattingEditProviderRegistry.has(model));
this._hasMultipleDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.all(model).length > 1 || modes.DocumentRangeFormattingEditProviderRegistry.all(model).length > 1);
this._hasMultipleDocumentSelectionFormattingProvider.set(modes.DocumentRangeFormattingEditProviderRegistry.all(model).length > 1);
this._isInWalkThrough.set(model.uri.scheme === Schemas.walkThroughSnippet);
this._contextKeyService.bufferChangeEvents(() => {
this._langId.set(model.getLanguageIdentifier().language);
this._hasCompletionItemProvider.set(modes.CompletionProviderRegistry.has(model));
this._hasCodeActionsProvider.set(modes.CodeActionProviderRegistry.has(model));
this._hasCodeLensProvider.set(modes.CodeLensProviderRegistry.has(model));
this._hasDefinitionProvider.set(modes.DefinitionProviderRegistry.has(model));
this._hasDeclarationProvider.set(modes.DeclarationProviderRegistry.has(model));
this._hasImplementationProvider.set(modes.ImplementationProviderRegistry.has(model));
this._hasTypeDefinitionProvider.set(modes.TypeDefinitionProviderRegistry.has(model));
this._hasHoverProvider.set(modes.HoverProviderRegistry.has(model));
this._hasDocumentHighlightProvider.set(modes.DocumentHighlightProviderRegistry.has(model));
this._hasDocumentSymbolProvider.set(modes.DocumentSymbolProviderRegistry.has(model));
this._hasReferenceProvider.set(modes.ReferenceProviderRegistry.has(model));
this._hasRenameProvider.set(modes.RenameProviderRegistry.has(model));
this._hasSignatureHelpProvider.set(modes.SignatureHelpProviderRegistry.has(model));
this._hasDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.has(model) || modes.DocumentRangeFormattingEditProviderRegistry.has(model));
this._hasDocumentSelectionFormattingProvider.set(modes.DocumentRangeFormattingEditProviderRegistry.has(model));
this._hasMultipleDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.all(model).length > 1 || modes.DocumentRangeFormattingEditProviderRegistry.all(model).length > 1);
this._hasMultipleDocumentSelectionFormattingProvider.set(modes.DocumentRangeFormattingEditProviderRegistry.all(model).length > 1);
this._isInWalkThrough.set(model.uri.scheme === Schemas.walkThroughSnippet);
});
}
}

Expand Down
51 changes: 37 additions & 14 deletions src/vs/platform/contextkey/browser/contextKeyService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { Emitter, Event } from 'vs/base/common/event';
import { Emitter, Event, PauseableEmitter } from 'vs/base/common/event';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { keys } from 'vs/base/common/map';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
Expand Down Expand Up @@ -165,44 +165,45 @@ class ConfigAwareContextValuesContainer extends Context {

class ContextKey<T> implements IContextKey<T> {

private _parent: AbstractContextKeyService;
private _service: AbstractContextKeyService;
private _key: string;
private _defaultValue: T | undefined;

constructor(parent: AbstractContextKeyService, key: string, defaultValue: T | undefined) {
this._parent = parent;
constructor(service: AbstractContextKeyService, key: string, defaultValue: T | undefined) {
this._service = service;
this._key = key;
this._defaultValue = defaultValue;
this.reset();
}

public set(value: T): void {
this._parent.setContext(this._key, value);
this._service.setContext(this._key, value);
}

public reset(): void {
if (typeof this._defaultValue === 'undefined') {
this._parent.removeContext(this._key);
this._service.removeContext(this._key);
} else {
this._parent.setContext(this._key, this._defaultValue);
this._service.setContext(this._key, this._defaultValue);
}
}

public get(): T | undefined {
return this._parent.getContextKeyValue<T>(this._key);
return this._service.getContextKeyValue<T>(this._key);
}
}

class SimpleContextKeyChangeEvent implements IContextKeyChangeEvent {
constructor(private readonly _key: string) { }
constructor(readonly key: string) { }
affectsSome(keys: IReadableSet<string>): boolean {
return keys.has(this._key);
return keys.has(this.key);
}
}

class ArrayContextKeyChangeEvent implements IContextKeyChangeEvent {
constructor(private readonly _keys: string[]) { }
constructor(readonly keys: string[]) { }
affectsSome(keys: IReadableSet<string>): boolean {
for (const key of this._keys) {
for (const key of this.keys) {
if (keys.has(key)) {
return true;
}
Expand All @@ -211,11 +212,23 @@ class ArrayContextKeyChangeEvent implements IContextKeyChangeEvent {
}
}

class CompositeContextKeyChangeEvent implements IContextKeyChangeEvent {
constructor(readonly events: IContextKeyChangeEvent[]) { }
affectsSome(keys: IReadableSet<string>): boolean {
for (const e of this.events) {
if (e.affectsSome(keys)) {
return true;
}
}
return false;
}
}

export abstract class AbstractContextKeyService implements IContextKeyService {
public _serviceBrand: any;

protected _isDisposed: boolean;
protected _onDidChangeContext = new Emitter<IContextKeyChangeEvent>();
protected _onDidChangeContext = new PauseableEmitter<IContextKeyChangeEvent>({ merge: input => new CompositeContextKeyChangeEvent(input) });
protected _myContextId: number;

constructor(myContextId: number) {
Expand All @@ -235,6 +248,16 @@ export abstract class AbstractContextKeyService implements IContextKeyService {
public get onDidChangeContext(): Event<IContextKeyChangeEvent> {
return this._onDidChangeContext.event;
}

bufferChangeEvents(callback: Function): void {
this._onDidChangeContext.pause();
try {
callback();
} finally {
this._onDidChangeContext.resume();
}
}

public createScoped(domNode: IContextKeyServiceTarget): IContextKeyService {
if (this._isDisposed) {
throw new Error(`AbstractContextKeyService has been disposed`);
Expand Down Expand Up @@ -356,7 +379,7 @@ class ScopedContextKeyService extends AbstractContextKeyService {
private _parent: AbstractContextKeyService;
private _domNode: IContextKeyServiceTarget | undefined;

constructor(parent: AbstractContextKeyService, emitter: Emitter<IContextKeyChangeEvent>, domNode?: IContextKeyServiceTarget) {
constructor(parent: AbstractContextKeyService, emitter: PauseableEmitter<IContextKeyChangeEvent>, domNode?: IContextKeyServiceTarget) {
super(parent.createChildContext());
this._parent = parent;
this._onDidChangeContext = emitter;
Expand Down
3 changes: 3 additions & 0 deletions src/vs/platform/contextkey/common/contextkey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,9 @@ export interface IContextKeyService {
dispose(): void;

onDidChangeContext: Event<IContextKeyChangeEvent>;
bufferChangeEvents(callback: Function): void;


createKey<T>(key: string, defaultValue: T | undefined): IContextKey<T>;
contextMatchesRules(rules: ContextKeyExpr | undefined): boolean;
getContextKeyValue<T>(key: string): T | undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ suite('AbstractKeybindingService', () => {
_serviceBrand: undefined,
dispose: undefined!,
onDidChangeContext: undefined!,
bufferChangeEvents() { },
createKey: undefined!,
contextMatchesRules: undefined!,
getContextKeyValue: undefined!,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export class MockContextKeyService implements IContextKeyService {
public get onDidChangeContext(): Event<IContextKeyChangeEvent> {
return Event.None;
}
public bufferChangeEvents() { }
public getContextKeyValue(key: string) {
const value = this._keys.get(key);
if (value) {
Expand Down

0 comments on commit ae83621

Please sign in to comment.