提交 4e2d923e 编写于 作者: J Joao Moreno

🔨 create IContext

上级 c5dc5153
......@@ -7,18 +7,19 @@
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver';
import { IContextKey, IContextKeyServiceTarget, IContextKeyService, SET_CONTEXT_COMMAND_ID, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { IContextKey, IContext, IContextKeyServiceTarget, IContextKeyService, SET_CONTEXT_COMMAND_ID, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import Event, { Emitter, debounceEvent } from 'vs/base/common/event';
const KEYBINDING_CONTEXT_ATTR = 'data-keybinding-context';
export class ContextValuesContainer {
protected _parent: ContextValuesContainer;
export class Context implements IContext {
protected _parent: Context;
protected _value: { [key: string]: any; };
protected _id: number;
constructor(id: number, parent: ContextValuesContainer) {
constructor(id: number, parent: Context) {
this._id = id;
this._parent = parent;
this._value = Object.create(null);
......@@ -46,18 +47,9 @@ export class ContextValuesContainer {
}
return ret;
}
public fillInContext(bucket: any): void {
if (this._parent) {
this._parent.fillInContext(bucket);
}
for (let key in this._value) {
bucket[key] = this._value[key];
}
}
}
class ConfigAwareContextValuesContainer extends ContextValuesContainer {
class ConfigAwareContextValuesContainer extends Context {
private _emitter: Emitter<string>;
private _subscription: IDisposable;
......@@ -169,9 +161,8 @@ export abstract class AbstractContextKeyService {
}
public contextMatchesRules(rules: ContextKeyExpr): boolean {
const ctx = Object.create(null);
this.getContextValuesContainer(this._myContextId).fillInContext(ctx);
const result = KeybindingResolver.contextMatchesRules(ctx, rules);
const context = this.getContextValuesContainer(this._myContextId);
const result = KeybindingResolver.contextMatchesRules(context, rules);
// console.group(rules.serialize() + ' -> ' + result);
// rules.keys().forEach(key => { console.log(key, ctx[key]); });
// console.groupEnd();
......@@ -194,13 +185,11 @@ export abstract class AbstractContextKeyService {
}
}
public getContextValue(target: IContextKeyServiceTarget): any {
let res = Object.create(null);
this.getContextValuesContainer(findContextAttr(target)).fillInContext(res);
return res;
public getContext(target: IContextKeyServiceTarget): IContext {
return this.getContextValuesContainer(findContextAttr(target));
}
public abstract getContextValuesContainer(contextId: number): ContextValuesContainer;
public abstract getContextValuesContainer(contextId: number): Context;
public abstract createChildContext(parentContextId?: number): number;
public abstract disposeContext(contextId: number): void;
}
......@@ -209,7 +198,7 @@ export class ContextKeyService extends AbstractContextKeyService implements ICon
private _lastContextId: number;
private _contexts: {
[contextId: string]: ContextValuesContainer;
[contextId: string]: Context;
};
private _toDispose: IDisposable[] = [];
......@@ -239,13 +228,13 @@ export class ContextKeyService extends AbstractContextKeyService implements ICon
this._toDispose = dispose(this._toDispose);
}
public getContextValuesContainer(contextId: number): ContextValuesContainer {
public getContextValuesContainer(contextId: number): Context {
return this._contexts[String(contextId)];
}
public createChildContext(parentContextId: number = this._myContextId): number {
let id = (++this._lastContextId);
this._contexts[String(id)] = new ContextValuesContainer(id, this.getContextValuesContainer(parentContextId));
this._contexts[String(id)] = new Context(id, this.getContextValuesContainer(parentContextId));
return id;
}
......@@ -281,7 +270,7 @@ class ScopedContextKeyService extends AbstractContextKeyService {
return this._parent.onDidChangeContext;
}
public getContextValuesContainer(contextId: number): ContextValuesContainer {
public getContextValuesContainer(contextId: number): Context {
return this._parent.getContextValuesContainer(contextId);
}
......
......@@ -88,7 +88,7 @@ export abstract class ContextKeyExpr {
public abstract getType(): ContextKeyExprType;
public abstract equals(other: ContextKeyExpr): boolean;
public abstract evaluate(context: any): boolean;
public abstract evaluate(context: IContext): boolean;
public abstract normalize(): ContextKeyExpr;
public abstract serialize(): string;
public abstract keys(): string[];
......@@ -139,8 +139,8 @@ export class ContextKeyDefinedExpr implements ContextKeyExpr {
return false;
}
public evaluate(context: any): boolean {
return (!!context[this.key]);
public evaluate(context: IContext): boolean {
return (!!context.getValue(this.key));
}
public normalize(): ContextKeyExpr {
......@@ -187,10 +187,10 @@ export class ContextKeyEqualsExpr implements ContextKeyExpr {
return false;
}
public evaluate(context: any): boolean {
public evaluate(context: IContext): boolean {
/* tslint:disable:triple-equals */
// Intentional ==
return (context[this.key] == this.value);
return (context.getValue(this.key) == this.value);
/* tslint:enable:triple-equals */
}
......@@ -248,10 +248,10 @@ export class ContextKeyNotEqualsExpr implements ContextKeyExpr {
return false;
}
public evaluate(context: any): boolean {
public evaluate(context: IContext): boolean {
/* tslint:disable:triple-equals */
// Intentional !=
return (context[this.key] != this.value);
return (context.getValue(this.key) != this.value);
/* tslint:enable:triple-equals */
}
......@@ -303,8 +303,8 @@ export class ContextKeyNotExpr implements ContextKeyExpr {
return false;
}
public evaluate(context: any): boolean {
return (!context[this.key]);
public evaluate(context: IContext): boolean {
return (!context.getValue(this.key));
}
public normalize(): ContextKeyExpr {
......@@ -346,7 +346,7 @@ export class ContextKeyAndExpr implements ContextKeyExpr {
return false;
}
public evaluate(context: any): boolean {
public evaluate(context: IContext): boolean {
for (let i = 0, len = this.expr.length; i < len; i++) {
if (!this.expr[i].evaluate(context)) {
return false;
......@@ -441,6 +441,10 @@ export class RawContextKey<T> extends ContextKeyDefinedExpr {
}
}
export interface IContext {
getValue<T>(key: string): T;
}
export interface IContextKey<T> {
set(value: T): void;
reset(): void;
......@@ -467,7 +471,7 @@ export interface IContextKeyService {
getContextKeyValue<T>(key: string): T;
createScoped(target?: IContextKeyServiceTarget): IContextKeyService;
getContextValue(target: IContextKeyServiceTarget): any;
getContext(target: IContextKeyServiceTarget): IContext;
}
export const SET_CONTEXT_COMMAND_ID = 'setContext';
......@@ -7,6 +7,8 @@
import * as assert from 'assert';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
const createContext = ctx => ({ getValue: key => ctx[key] });
suite('ContextKeyExpr', () => {
test('ContextKeyExpr.equals', function () {
let a = ContextKeyExpr.and(
......@@ -48,11 +50,11 @@ suite('ContextKeyExpr', () => {
test('evaluate', function () {
/* tslint:disable:triple-equals */
let context = {
let context = createContext({
'a': true,
'b': false,
'c': '5'
};
});
function testExpression(expr: string, expected: boolean): void {
let rules = ContextKeyExpr.deserialize(expr);
assert.equal(rules.evaluate(context), expected, expr);
......
......@@ -230,7 +230,7 @@ export abstract class AbstractKeybindingService implements IKeybindingService {
return null;
}
const contextValue = this._contextKeyService.getContextValue(target);
const contextValue = this._contextKeyService.getContext(target);
const currentChord = this._currentChord ? this._currentChord.keypress : null;
const keypress = keybinding.value.toString();
return this._getResolver().resolve(contextValue, currentChord, keypress);
......@@ -244,7 +244,7 @@ export abstract class AbstractKeybindingService implements IKeybindingService {
return shouldPreventDefault;
}
const contextValue = this._contextKeyService.getContextValue(target);
const contextValue = this._contextKeyService.getContext(target);
const currentChord = this._currentChord ? this._currentChord.keypress : null;
const keypress = keybinding.value.toString();
const keypressLabel = this._createResolvedKeybinding(keybinding).getLabel();
......
......@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ContextKeyExpr, IContext } from 'vs/platform/contextkey/common/contextkey';
import { NormalizedKeybindingItem } from 'vs/platform/keybinding/common/normalizedKeybindingItem';
export interface IResolveResult {
......@@ -227,7 +227,7 @@ export class KeybindingResolver {
return items[items.length - 1];
}
public resolve(context: any, currentChord: string, keypress: string): IResolveResult {
public resolve(context: IContext, currentChord: string, keypress: string): IResolveResult {
let lookupMap: NormalizedKeybindingItem[] = null;
if (currentChord !== null) {
......@@ -278,7 +278,7 @@ export class KeybindingResolver {
};
}
private _findCommand(context: any, matches: NormalizedKeybindingItem[]): NormalizedKeybindingItem {
private _findCommand(context: IContext, matches: NormalizedKeybindingItem[]): NormalizedKeybindingItem {
for (let i = matches.length - 1; i >= 0; i--) {
let k = matches[i];
......@@ -292,7 +292,7 @@ export class KeybindingResolver {
return null;
}
public static contextMatchesRules(context: any, rules: ContextKeyExpr): boolean {
public static contextMatchesRules(context: IContext, rules: ContextKeyExpr): boolean {
if (!rules) {
return true;
}
......
......@@ -11,13 +11,15 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import Severity from 'vs/base/common/severity';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver';
import { ContextKeyExpr, IContextKeyService, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey';
import { IContext, ContextKeyExpr, IContextKeyService, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey';
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
import { IMessageService } from 'vs/platform/message/common/message';
import { TPromise } from 'vs/base/common/winjs.base';
import { NormalizedKeybindingItem } from 'vs/platform/keybinding/common/normalizedKeybindingItem';
import { OS } from 'vs/base/common/platform';
const createContext = ctx => ({ getValue: key => ctx[key] });
suite('AbstractKeybindingService', () => {
class TestKeybindingService extends AbstractKeybindingService {
......@@ -48,7 +50,7 @@ suite('AbstractKeybindingService', () => {
}
let createTestKeybindingService: (items: NormalizedKeybindingItem[], contextValue?: any) => TestKeybindingService = null;
let currentContextValue: any = null;
let currentContextValue: IContext = null;
let executeCommandCalls: { commandId: string; args: any[]; }[] = null;
let showMessageCalls: { sev: Severity, message: any; }[] = null;
let statusMessageCalls: string[] = null;
......@@ -70,7 +72,7 @@ suite('AbstractKeybindingService', () => {
contextMatchesRules: undefined,
getContextKeyValue: undefined,
createScoped: undefined,
getContextValue: (target: IContextKeyServiceTarget): any => {
getContext: (target: IContextKeyServiceTarget): any => {
return currentContextValue;
}
};
......@@ -248,9 +250,9 @@ suite('AbstractKeybindingService', () => {
// send Ctrl/Cmd + K
currentContextValue = {
currentContextValue = createContext({
key1: true
};
});
let shouldPreventDefault = kbService.dispatch(new SimpleKeybinding(KeyMod.CtrlCmd | KeyCode.KEY_K));
assert.equal(shouldPreventDefault, true);
assert.deepEqual(executeCommandCalls, [{
......@@ -266,7 +268,7 @@ suite('AbstractKeybindingService', () => {
statusMessageCallsDisposed = [];
// send Ctrl/Cmd + K
currentContextValue = {};
currentContextValue = createContext({});
shouldPreventDefault = kbService.dispatch(new SimpleKeybinding(KeyMod.CtrlCmd | KeyCode.KEY_K));
assert.equal(shouldPreventDefault, true);
assert.deepEqual(executeCommandCalls, []);
......@@ -281,7 +283,7 @@ suite('AbstractKeybindingService', () => {
statusMessageCallsDisposed = [];
// send Ctrl/Cmd + X
currentContextValue = {};
currentContextValue = createContext({});
shouldPreventDefault = kbService.dispatch(new SimpleKeybinding(KeyMod.CtrlCmd | KeyCode.KEY_X));
assert.equal(shouldPreventDefault, true);
assert.deepEqual(executeCommandCalls, [{
......@@ -310,7 +312,7 @@ suite('AbstractKeybindingService', () => {
// send Ctrl/Cmd + K
currentContextValue = {};
currentContextValue = createContext({});
let shouldPreventDefault = kbService.dispatch(new SimpleKeybinding(KeyMod.CtrlCmd | KeyCode.KEY_K));
assert.equal(shouldPreventDefault, true);
assert.deepEqual(executeCommandCalls, [{
......@@ -326,9 +328,9 @@ suite('AbstractKeybindingService', () => {
statusMessageCallsDisposed = [];
// send Ctrl/Cmd + K
currentContextValue = {
currentContextValue = createContext({
key1: true
};
});
shouldPreventDefault = kbService.dispatch(new SimpleKeybinding(KeyMod.CtrlCmd | KeyCode.KEY_K));
assert.equal(shouldPreventDefault, true);
assert.deepEqual(executeCommandCalls, [{
......@@ -344,9 +346,9 @@ suite('AbstractKeybindingService', () => {
statusMessageCallsDisposed = [];
// send Ctrl/Cmd + X
currentContextValue = {
currentContextValue = createContext({
key1: true
};
});
shouldPreventDefault = kbService.dispatch(new SimpleKeybinding(KeyMod.CtrlCmd | KeyCode.KEY_X));
assert.equal(shouldPreventDefault, false);
assert.deepEqual(executeCommandCalls, []);
......@@ -368,7 +370,7 @@ suite('AbstractKeybindingService', () => {
]);
// send Ctrl/Cmd + K
currentContextValue = {};
currentContextValue = createContext({});
let shouldPreventDefault = kbService.dispatch(new SimpleKeybinding(KeyMod.CtrlCmd | KeyCode.KEY_K));
assert.equal(shouldPreventDefault, false);
assert.deepEqual(executeCommandCalls, [{
......
......@@ -7,9 +7,11 @@
import * as assert from 'assert';
import { createKeybinding, SimpleKeybinding, KeyCode, KeyMod, KeyChord } from 'vs/base/common/keyCodes';
import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver';
import { ContextKeyAndExpr, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { IContext, ContextKeyAndExpr, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { NormalizedKeybindingItem } from 'vs/platform/keybinding/common/normalizedKeybindingItem';
const createContext = ctx => ({ getValue: key => ctx[key] });
suite('KeybindingResolver', () => {
function kbItem(keybinding: number, command: string, commandArgs: any, when: ContextKeyExpr, isDefault: boolean): NormalizedKeybindingItem {
......@@ -28,12 +30,12 @@ suite('KeybindingResolver', () => {
let contextRules = ContextKeyExpr.equals('bar', 'baz');
let keybindingItem = kbItem(keybinding, 'yes', null, contextRules, true);
assert.equal(KeybindingResolver.contextMatchesRules({ bar: 'baz' }, contextRules), true);
assert.equal(KeybindingResolver.contextMatchesRules({ bar: 'bz' }, contextRules), false);
assert.equal(KeybindingResolver.contextMatchesRules(createContext({ bar: 'baz' }), contextRules), true);
assert.equal(KeybindingResolver.contextMatchesRules(createContext({ bar: 'bz' }), contextRules), false);
let resolver = new KeybindingResolver([keybindingItem], []);
assert.equal(resolver.resolve({ bar: 'baz' }, null, new SimpleKeybinding(keybinding).value.toString()).commandId, 'yes');
assert.equal(resolver.resolve({ bar: 'bz' }, null, new SimpleKeybinding(keybinding).value.toString()), null);
assert.equal(resolver.resolve(createContext({ bar: 'baz' }), null, new SimpleKeybinding(keybinding).value.toString()).commandId, 'yes');
assert.equal(resolver.resolve(createContext({ bar: 'bz' }), null, new SimpleKeybinding(keybinding).value.toString()), null);
});
test('resolve key with arguments', function () {
......@@ -43,7 +45,7 @@ suite('KeybindingResolver', () => {
let keybindingItem = kbItem(keybinding, 'yes', commandArgs, contextRules, true);
let resolver = new KeybindingResolver([keybindingItem], []);
assert.equal(resolver.resolve({ bar: 'baz' }, null, new SimpleKeybinding(keybinding).value.toString()).commandArgs, commandArgs);
assert.equal(resolver.resolve(createContext({ bar: 'baz' }), null, new SimpleKeybinding(keybinding).value.toString()).commandArgs, commandArgs);
});
test('KeybindingResolver.combine simple 1', function () {
......@@ -323,7 +325,7 @@ suite('KeybindingResolver', () => {
}
};
let testResolve = (ctx: any, _expectedKey: number, commandId: string) => {
let testResolve = (ctx: IContext, _expectedKey: number, commandId: string) => {
let expectedKey = createKeybinding(_expectedKey);
if (expectedKey.isChord()) {
......@@ -350,30 +352,30 @@ suite('KeybindingResolver', () => {
testKey('first', []);
testKey('second', [KeyCode.KEY_Z, KeyCode.KEY_X]);
testResolve({ key2: true }, KeyCode.KEY_X, 'second');
testResolve({}, KeyCode.KEY_Z, 'second');
testResolve(createContext({ key2: true }), KeyCode.KEY_X, 'second');
testResolve(createContext({}), KeyCode.KEY_Z, 'second');
testKey('third', [KeyCode.KEY_X]);
testResolve({ key3: true }, KeyCode.KEY_X, 'third');
testResolve(createContext({ key3: true }), KeyCode.KEY_X, 'third');
testKey('fourth', []);
testKey('fifth', [KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_Y, KeyCode.KEY_Z)]);
testResolve({}, KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_Y, KeyCode.KEY_Z), 'fifth');
testResolve(createContext({}), KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_Y, KeyCode.KEY_Z), 'fifth');
testKey('seventh', [KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_K)]);
testResolve({}, KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_K), 'seventh');
testResolve(createContext({}), KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_K), 'seventh');
testKey('uncomment lines', [KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_U)]);
testResolve({}, KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_U), 'uncomment lines');
testResolve(createContext({}), KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_U), 'uncomment lines');
testKey('comment lines', [KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_C)]);
testResolve({}, KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_C), 'comment lines');
testResolve(createContext({}), KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_C), 'comment lines');
testKey('unreachablechord', []);
testKey('eleven', [KeyMod.CtrlCmd | KeyCode.KEY_G]);
testResolve({}, KeyMod.CtrlCmd | KeyCode.KEY_G, 'eleven');
testResolve(createContext({}), KeyMod.CtrlCmd | KeyCode.KEY_G, 'eleven');
testKey('sixth', []);
});
......
......@@ -53,7 +53,7 @@ export class MockKeybindingService implements IContextKeyService {
public getContextKeyValue(key: string) {
return;
}
public getContextValue(domNode: HTMLElement): any {
public getContext(domNode: HTMLElement): any {
return null;
}
public createScoped(domNode: HTMLElement): IContextKeyService {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册