提交 b1f31342 编写于 作者: J Joao Moreno

Merge branch 'context-type'

......@@ -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);
......
......@@ -101,7 +101,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;
return this._getResolver().resolve(contextValue, currentChord, firstPart);
}
......@@ -120,7 +120,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 keypressLabel = keybinding.getLabel();
const resolveResult = this._getResolver().resolve(contextValue, currentChord, firstPart);
......
......@@ -5,7 +5,7 @@
'use strict';
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ContextKeyExpr, IContext } from 'vs/platform/contextkey/common/contextkey';
import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';
import { CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
......@@ -234,7 +234,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: ResolvedKeybindingItem[] = null;
if (currentChord !== null) {
......@@ -285,7 +285,7 @@ export class KeybindingResolver {
};
}
private _findCommand(context: any, matches: ResolvedKeybindingItem[]): ResolvedKeybindingItem {
private _findCommand(context: IContext, matches: ResolvedKeybindingItem[]): ResolvedKeybindingItem {
for (let i = matches.length - 1; i >= 0; i--) {
let k = matches[i];
......@@ -299,7 +299,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;
}
......
......@@ -12,7 +12,7 @@ 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';
......@@ -20,6 +20,8 @@ import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKe
import { OS } from 'vs/base/common/platform';
import { IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding';
const createContext = ctx => ({ getValue: key => ctx[key] });
suite('AbstractKeybindingService', () => {
class TestKeybindingService extends AbstractKeybindingService {
......@@ -69,7 +71,7 @@ suite('AbstractKeybindingService', () => {
}
let createTestKeybindingService: (items: ResolvedKeybindingItem[], 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;
......@@ -91,7 +93,7 @@ suite('AbstractKeybindingService', () => {
contextMatchesRules: undefined,
getContextKeyValue: undefined,
createScoped: undefined,
getContextValue: (target: IContextKeyServiceTarget): any => {
getContext: (target: IContextKeyServiceTarget): any => {
return currentContextValue;
}
};
......@@ -269,9 +271,9 @@ suite('AbstractKeybindingService', () => {
// send Ctrl/Cmd + K
currentContextValue = {
currentContextValue = createContext({
key1: true
};
});
let shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KEY_K);
assert.equal(shouldPreventDefault, true);
assert.deepEqual(executeCommandCalls, [{
......@@ -287,7 +289,7 @@ suite('AbstractKeybindingService', () => {
statusMessageCallsDisposed = [];
// send Ctrl/Cmd + K
currentContextValue = {};
currentContextValue = createContext({});
shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KEY_K);
assert.equal(shouldPreventDefault, true);
assert.deepEqual(executeCommandCalls, []);
......@@ -302,7 +304,7 @@ suite('AbstractKeybindingService', () => {
statusMessageCallsDisposed = [];
// send Ctrl/Cmd + X
currentContextValue = {};
currentContextValue = createContext({});
shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KEY_X);
assert.equal(shouldPreventDefault, true);
assert.deepEqual(executeCommandCalls, [{
......@@ -331,7 +333,7 @@ suite('AbstractKeybindingService', () => {
// send Ctrl/Cmd + K
currentContextValue = {};
currentContextValue = createContext({});
let shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KEY_K);
assert.equal(shouldPreventDefault, true);
assert.deepEqual(executeCommandCalls, [{
......@@ -347,9 +349,9 @@ suite('AbstractKeybindingService', () => {
statusMessageCallsDisposed = [];
// send Ctrl/Cmd + K
currentContextValue = {
currentContextValue = createContext({
key1: true
};
});
shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KEY_K);
assert.equal(shouldPreventDefault, true);
assert.deepEqual(executeCommandCalls, [{
......@@ -365,9 +367,9 @@ suite('AbstractKeybindingService', () => {
statusMessageCallsDisposed = [];
// send Ctrl/Cmd + X
currentContextValue = {
currentContextValue = createContext({
key1: true
};
});
shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KEY_X);
assert.equal(shouldPreventDefault, false);
assert.deepEqual(executeCommandCalls, []);
......@@ -389,7 +391,7 @@ suite('AbstractKeybindingService', () => {
]);
// send Ctrl/Cmd + K
currentContextValue = {};
currentContextValue = createContext({});
let shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KEY_K);
assert.equal(shouldPreventDefault, false);
assert.deepEqual(executeCommandCalls, [{
......
......@@ -7,11 +7,13 @@
import * as assert from 'assert';
import { KeyCode, KeyMod, KeyChord, createKeybinding, KeybindingType, SimpleKeybinding } from 'vs/base/common/keyCodes';
import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver';
import { ContextKeyAndExpr, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ContextKeyAndExpr, ContextKeyExpr, IContext } from 'vs/platform/contextkey/common/contextkey';
import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';
import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding';
import { OS } from 'vs/base/common/platform';
const createContext = ctx => ({ getValue: key => ctx[key] });
suite('KeybindingResolver', () => {
function kbItem(keybinding: number, command: string, commandArgs: any, when: ContextKeyExpr, isDefault: boolean): ResolvedKeybindingItem {
......@@ -35,12 +37,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, getDispatchStr(<SimpleKeybinding>runtimeKeybinding)).commandId, 'yes');
assert.equal(resolver.resolve({ bar: 'bz' }, null, getDispatchStr(<SimpleKeybinding>runtimeKeybinding)), null);
assert.equal(resolver.resolve(createContext({ bar: 'baz' }), null, getDispatchStr(<SimpleKeybinding>runtimeKeybinding)).commandId, 'yes');
assert.equal(resolver.resolve(createContext({ bar: 'bz' }), null, getDispatchStr(<SimpleKeybinding>runtimeKeybinding)), null);
});
test('resolve key with arguments', function () {
......@@ -51,7 +53,7 @@ suite('KeybindingResolver', () => {
let keybindingItem = kbItem(keybinding, 'yes', commandArgs, contextRules, true);
let resolver = new KeybindingResolver([keybindingItem], []);
assert.equal(resolver.resolve({ bar: 'baz' }, null, getDispatchStr(<SimpleKeybinding>runtimeKeybinding)).commandArgs, commandArgs);
assert.equal(resolver.resolve(createContext({ bar: 'baz' }), null, getDispatchStr(<SimpleKeybinding>runtimeKeybinding)).commandArgs, commandArgs);
});
test('KeybindingResolver.combine simple 1', function () {
......@@ -333,7 +335,7 @@ suite('KeybindingResolver', () => {
}
};
let testResolve = (ctx: any, _expectedKey: number, commandId: string) => {
let testResolve = (ctx: IContext, _expectedKey: number, commandId: string) => {
const expectedKey = createKeybinding(_expectedKey, OS);
if (expectedKey.type === KeybindingType.Chord) {
......@@ -360,30 +362,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', []);
});
......
......@@ -54,7 +54,7 @@ export class MockContextKeyService 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.
先完成此消息的编辑!
想要评论请 注册