mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Merge from master
This commit is contained in:
@@ -2,24 +2,24 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { Emitter, Event, mapEvent } 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';
|
||||
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ContextKeyExpr, IContext, IContextKey, IContextKeyChangeEvent, IContextKeyService, IContextKeyServiceTarget, IReadableSet, SET_CONTEXT_COMMAND_ID } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver';
|
||||
import { IContextKey, IContext, IContextKeyServiceTarget, IContextKeyService, SET_CONTEXT_COMMAND_ID, ContextKeyExpr, IContextKeyChangeEvent, IReadableSet } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IConfigurationService, IConfigurationChangeEvent, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||
import { Event, Emitter, debounceEvent } from 'vs/base/common/event';
|
||||
|
||||
const KEYBINDING_CONTEXT_ATTR = 'data-keybinding-context';
|
||||
|
||||
export class Context implements IContext {
|
||||
|
||||
protected _parent: Context;
|
||||
protected _parent: Context | null;
|
||||
protected _value: { [key: string]: any; };
|
||||
protected _id: number;
|
||||
|
||||
constructor(id: number, parent: Context) {
|
||||
constructor(id: number, parent: Context | null) {
|
||||
this._id = id;
|
||||
this._parent = parent;
|
||||
this._value = Object.create(null);
|
||||
@@ -44,7 +44,7 @@ export class Context implements IContext {
|
||||
return false;
|
||||
}
|
||||
|
||||
public getValue<T>(key: string): T {
|
||||
public getValue<T>(key: string): T | undefined {
|
||||
const ret = this._value[key];
|
||||
if (typeof ret === 'undefined' && this._parent) {
|
||||
return this._parent.getValue<T>(key);
|
||||
@@ -60,84 +60,106 @@ export class Context implements IContext {
|
||||
}
|
||||
}
|
||||
|
||||
class NullContext extends Context {
|
||||
|
||||
static readonly INSTANCE = new NullContext();
|
||||
|
||||
constructor() {
|
||||
super(-1, null);
|
||||
}
|
||||
|
||||
public setValue(key: string, value: any): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
public removeValue(key: string): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
public getValue<T>(key: string): T | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
collectAllValues(): { [key: string]: any; } {
|
||||
return Object.create(null);
|
||||
}
|
||||
}
|
||||
|
||||
class ConfigAwareContextValuesContainer extends Context {
|
||||
|
||||
private readonly _emitter: Emitter<string | string[]>;
|
||||
private readonly _subscription: IDisposable;
|
||||
private readonly _configurationService: IConfigurationService;
|
||||
private static _keyPrefix = 'config.';
|
||||
|
||||
constructor(id: number, configurationService: IConfigurationService, emitter: Emitter<string | string[]>) {
|
||||
private readonly _values = new Map<string, any>();
|
||||
private readonly _listener: IDisposable;
|
||||
|
||||
constructor(
|
||||
id: number,
|
||||
private readonly _configurationService: IConfigurationService,
|
||||
emitter: Emitter<string | string[]>
|
||||
) {
|
||||
super(id, null);
|
||||
|
||||
this._emitter = emitter;
|
||||
this._configurationService = configurationService;
|
||||
this._subscription = configurationService.onDidChangeConfiguration(this._onConfigurationUpdated, this);
|
||||
this._initFromConfiguration();
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
this._subscription.dispose();
|
||||
}
|
||||
|
||||
private _onConfigurationUpdated(event: IConfigurationChangeEvent): void {
|
||||
if (event.source === ConfigurationTarget.DEFAULT) {
|
||||
// new setting, rebuild everything
|
||||
this._initFromConfiguration();
|
||||
} else {
|
||||
// update those that we know
|
||||
for (const configKey of event.affectedKeys) {
|
||||
const contextKey = `config.${configKey}`;
|
||||
if (contextKey in this._value) {
|
||||
this._value[contextKey] = this._configurationService.getValue(configKey);
|
||||
this._emitter.fire(contextKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _initFromConfiguration() {
|
||||
|
||||
const prefix = 'config.';
|
||||
const config = this._configurationService.getValue();
|
||||
const configKeys: { [key: string]: boolean } = Object.create(null);
|
||||
const configKeysChanged: string[] = [];
|
||||
|
||||
// add new value from config
|
||||
const walk = (obj: any, keys: string[]) => {
|
||||
for (let key in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
keys.push(key);
|
||||
let value = obj[key];
|
||||
if (typeof value === 'boolean') {
|
||||
const configKey = keys.join('.');
|
||||
const oldValue = this._value[configKey];
|
||||
this._value[configKey] = value;
|
||||
if (oldValue !== value) {
|
||||
configKeysChanged.push(configKey);
|
||||
configKeys[configKey] = true;
|
||||
} else {
|
||||
configKeys[configKey] = false;
|
||||
}
|
||||
} else if (typeof value === 'object') {
|
||||
walk(value, keys);
|
||||
this._listener = this._configurationService.onDidChangeConfiguration(event => {
|
||||
if (event.source === ConfigurationTarget.DEFAULT) {
|
||||
// new setting, reset everything
|
||||
const allKeys = keys(this._values);
|
||||
this._values.clear();
|
||||
emitter.fire(allKeys);
|
||||
} else {
|
||||
const changedKeys: string[] = [];
|
||||
for (const configKey of event.affectedKeys) {
|
||||
const contextKey = `config.${configKey}`;
|
||||
if (this._values.has(contextKey)) {
|
||||
this._values.delete(contextKey);
|
||||
changedKeys.push(contextKey);
|
||||
}
|
||||
keys.pop();
|
||||
}
|
||||
emitter.fire(changedKeys);
|
||||
}
|
||||
};
|
||||
walk(config, ['config']);
|
||||
});
|
||||
}
|
||||
|
||||
// remove unused keys
|
||||
for (let key in this._value) {
|
||||
if (key.indexOf(prefix) === 0 && configKeys[key] === undefined) {
|
||||
delete this._value[key];
|
||||
configKeys[key] = true;
|
||||
configKeysChanged.push(key);
|
||||
}
|
||||
dispose(): void {
|
||||
this._listener.dispose();
|
||||
}
|
||||
|
||||
getValue(key: string): any {
|
||||
|
||||
if (key.indexOf(ConfigAwareContextValuesContainer._keyPrefix) !== 0) {
|
||||
return super.getValue(key);
|
||||
}
|
||||
|
||||
// send events
|
||||
this._emitter.fire(configKeysChanged);
|
||||
if (this._values.has(key)) {
|
||||
return this._values.get(key);
|
||||
}
|
||||
|
||||
const configKey = key.substr(ConfigAwareContextValuesContainer._keyPrefix.length);
|
||||
const configValue = this._configurationService.getValue(configKey);
|
||||
let value: any = undefined;
|
||||
switch (typeof configValue) {
|
||||
case 'number':
|
||||
case 'boolean':
|
||||
case 'string':
|
||||
value = configValue;
|
||||
break;
|
||||
}
|
||||
|
||||
this._values.set(key, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
setValue(key: string, value: any): boolean {
|
||||
return super.setValue(key, value);
|
||||
}
|
||||
|
||||
removeValue(key: string): boolean {
|
||||
return super.removeValue(key);
|
||||
}
|
||||
|
||||
collectAllValues(): { [key: string]: any; } {
|
||||
const result: { [key: string]: any } = Object.create(null);
|
||||
this._values.forEach((value, index) => result[index] = value);
|
||||
return { ...result, ...super.collectAllValues() };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,9 +167,9 @@ class ContextKey<T> implements IContextKey<T> {
|
||||
|
||||
private _parent: AbstractContextKeyService;
|
||||
private _key: string;
|
||||
private _defaultValue: T;
|
||||
private _defaultValue: T | undefined;
|
||||
|
||||
constructor(parent: AbstractContextKeyService, key: string, defaultValue: T) {
|
||||
constructor(parent: AbstractContextKeyService, key: string, defaultValue: T | undefined) {
|
||||
this._parent = parent;
|
||||
this._key = key;
|
||||
this._defaultValue = defaultValue;
|
||||
@@ -166,19 +188,19 @@ class ContextKey<T> implements IContextKey<T> {
|
||||
}
|
||||
}
|
||||
|
||||
public get(): T {
|
||||
public get(): T | undefined {
|
||||
return this._parent.getContextKeyValue<T>(this._key);
|
||||
}
|
||||
}
|
||||
|
||||
export class ContextKeyChangeEvent implements IContextKeyChangeEvent {
|
||||
|
||||
private _keys: string[] = [];
|
||||
|
||||
collect(oneOrManyKeys: string | string[]): void {
|
||||
this._keys = this._keys.concat(oneOrManyKeys);
|
||||
class SimpleContextKeyChangeEvent implements IContextKeyChangeEvent {
|
||||
constructor(private readonly _key: string) { }
|
||||
affectsSome(keys: IReadableSet<string>): boolean {
|
||||
return keys.has(this._key);
|
||||
}
|
||||
|
||||
}
|
||||
class ArrayContextKeyChangeEvent implements IContextKeyChangeEvent {
|
||||
constructor(private readonly _keys: string[]) { }
|
||||
affectsSome(keys: IReadableSet<string>): boolean {
|
||||
for (const key of this._keys) {
|
||||
if (keys.has(key)) {
|
||||
@@ -192,39 +214,48 @@ export class ContextKeyChangeEvent implements IContextKeyChangeEvent {
|
||||
export abstract class AbstractContextKeyService implements IContextKeyService {
|
||||
public _serviceBrand: any;
|
||||
|
||||
protected _isDisposed: boolean;
|
||||
protected _onDidChangeContext: Event<IContextKeyChangeEvent>;
|
||||
protected _onDidChangeContextKey: Emitter<string | string[]>;
|
||||
protected _myContextId: number;
|
||||
|
||||
constructor(myContextId: number) {
|
||||
this._isDisposed = false;
|
||||
this._myContextId = myContextId;
|
||||
this._onDidChangeContextKey = new Emitter<string>();
|
||||
}
|
||||
|
||||
abstract dispose(): void;
|
||||
|
||||
public createKey<T>(key: string, defaultValue: T): IContextKey<T> {
|
||||
public createKey<T>(key: string, defaultValue: T | undefined): IContextKey<T> {
|
||||
if (this._isDisposed) {
|
||||
throw new Error(`AbstractContextKeyService has been disposed`);
|
||||
}
|
||||
return new ContextKey(this, key, defaultValue);
|
||||
}
|
||||
|
||||
public get onDidChangeContext(): Event<IContextKeyChangeEvent> {
|
||||
if (!this._onDidChangeContext) {
|
||||
this._onDidChangeContext = debounceEvent<string | string[], ContextKeyChangeEvent>(this._onDidChangeContextKey.event, (prev, cur) => {
|
||||
if (!prev) {
|
||||
prev = new ContextKeyChangeEvent();
|
||||
}
|
||||
prev.collect(cur);
|
||||
return prev;
|
||||
}, 25);
|
||||
this._onDidChangeContext = mapEvent(this._onDidChangeContextKey.event, ((changedKeyOrKeys): IContextKeyChangeEvent => {
|
||||
return typeof changedKeyOrKeys === 'string'
|
||||
? new SimpleContextKeyChangeEvent(changedKeyOrKeys)
|
||||
: new ArrayContextKeyChangeEvent(changedKeyOrKeys);
|
||||
}));
|
||||
}
|
||||
return this._onDidChangeContext;
|
||||
}
|
||||
|
||||
public createScoped(domNode: IContextKeyServiceTarget): IContextKeyService {
|
||||
if (this._isDisposed) {
|
||||
throw new Error(`AbstractContextKeyService has been disposed`);
|
||||
}
|
||||
return new ScopedContextKeyService(this, this._onDidChangeContextKey, domNode);
|
||||
}
|
||||
|
||||
public contextMatchesRules(rules: ContextKeyExpr): boolean {
|
||||
public contextMatchesRules(rules: ContextKeyExpr | null): boolean {
|
||||
if (this._isDisposed) {
|
||||
throw new Error(`AbstractContextKeyService has been disposed`);
|
||||
}
|
||||
const context = this.getContextValuesContainer(this._myContextId);
|
||||
const result = KeybindingResolver.contextMatchesRules(context, rules);
|
||||
// console.group(rules.serialize() + ' -> ' + result);
|
||||
@@ -233,11 +264,17 @@ export abstract class AbstractContextKeyService implements IContextKeyService {
|
||||
return result;
|
||||
}
|
||||
|
||||
public getContextKeyValue<T>(key: string): T {
|
||||
public getContextKeyValue<T>(key: string): T | undefined {
|
||||
if (this._isDisposed) {
|
||||
return undefined;
|
||||
}
|
||||
return this.getContextValuesContainer(this._myContextId).getValue<T>(key);
|
||||
}
|
||||
|
||||
public setContext(key: string, value: any): void {
|
||||
if (this._isDisposed) {
|
||||
return;
|
||||
}
|
||||
const myContext = this.getContextValuesContainer(this._myContextId);
|
||||
if (!myContext) {
|
||||
return;
|
||||
@@ -248,12 +285,18 @@ export abstract class AbstractContextKeyService implements IContextKeyService {
|
||||
}
|
||||
|
||||
public removeContext(key: string): void {
|
||||
if (this._isDisposed) {
|
||||
return;
|
||||
}
|
||||
if (this.getContextValuesContainer(this._myContextId).removeValue(key)) {
|
||||
this._onDidChangeContextKey.fire(key);
|
||||
}
|
||||
}
|
||||
|
||||
public getContext(target: IContextKeyServiceTarget): IContext {
|
||||
public getContext(target: IContextKeyServiceTarget | null): IContext {
|
||||
if (this._isDisposed) {
|
||||
return NullContext.INSTANCE;
|
||||
}
|
||||
return this.getContextValuesContainer(findContextAttr(target));
|
||||
}
|
||||
|
||||
@@ -281,7 +324,7 @@ export class ContextKeyService extends AbstractContextKeyService implements ICon
|
||||
this._toDispose.push(myContext);
|
||||
|
||||
// Uncomment this to see the contexts continuously logged
|
||||
// let lastLoggedValue: string = null;
|
||||
// let lastLoggedValue: string | null = null;
|
||||
// setInterval(() => {
|
||||
// let values = Object.keys(this._contexts).map((key) => this._contexts[key]);
|
||||
// let logValue = values.map(v => JSON.stringify(v._value, null, '\t')).join('\n');
|
||||
@@ -293,20 +336,30 @@ export class ContextKeyService extends AbstractContextKeyService implements ICon
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._isDisposed = true;
|
||||
this._toDispose = dispose(this._toDispose);
|
||||
}
|
||||
|
||||
public getContextValuesContainer(contextId: number): Context {
|
||||
if (this._isDisposed) {
|
||||
return NullContext.INSTANCE;
|
||||
}
|
||||
return this._contexts[String(contextId)];
|
||||
}
|
||||
|
||||
public createChildContext(parentContextId: number = this._myContextId): number {
|
||||
if (this._isDisposed) {
|
||||
throw new Error(`ContextKeyService has been disposed`);
|
||||
}
|
||||
let id = (++this._lastContextId);
|
||||
this._contexts[String(id)] = new Context(id, this.getContextValuesContainer(parentContextId));
|
||||
return id;
|
||||
}
|
||||
|
||||
public disposeContext(contextId: number): void {
|
||||
if (this._isDisposed) {
|
||||
return;
|
||||
}
|
||||
delete this._contexts[String(contextId)];
|
||||
}
|
||||
}
|
||||
@@ -314,7 +367,7 @@ export class ContextKeyService extends AbstractContextKeyService implements ICon
|
||||
class ScopedContextKeyService extends AbstractContextKeyService {
|
||||
|
||||
private _parent: AbstractContextKeyService;
|
||||
private _domNode: IContextKeyServiceTarget;
|
||||
private _domNode: IContextKeyServiceTarget | undefined;
|
||||
|
||||
constructor(parent: AbstractContextKeyService, emitter: Emitter<string | string[]>, domNode?: IContextKeyServiceTarget) {
|
||||
super(parent.createChildContext());
|
||||
@@ -328,6 +381,7 @@ class ScopedContextKeyService extends AbstractContextKeyService {
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._isDisposed = true;
|
||||
this._parent.disposeContext(this._myContextId);
|
||||
if (this._domNode) {
|
||||
this._domNode.removeAttribute(KEYBINDING_CONTEXT_ATTR);
|
||||
@@ -340,22 +394,35 @@ class ScopedContextKeyService extends AbstractContextKeyService {
|
||||
}
|
||||
|
||||
public getContextValuesContainer(contextId: number): Context {
|
||||
if (this._isDisposed) {
|
||||
return NullContext.INSTANCE;
|
||||
}
|
||||
return this._parent.getContextValuesContainer(contextId);
|
||||
}
|
||||
|
||||
public createChildContext(parentContextId: number = this._myContextId): number {
|
||||
if (this._isDisposed) {
|
||||
throw new Error(`ScopedContextKeyService has been disposed`);
|
||||
}
|
||||
return this._parent.createChildContext(parentContextId);
|
||||
}
|
||||
|
||||
public disposeContext(contextId: number): void {
|
||||
if (this._isDisposed) {
|
||||
return;
|
||||
}
|
||||
this._parent.disposeContext(contextId);
|
||||
}
|
||||
}
|
||||
|
||||
function findContextAttr(domNode: IContextKeyServiceTarget): number {
|
||||
function findContextAttr(domNode: IContextKeyServiceTarget | null): number {
|
||||
while (domNode) {
|
||||
if (domNode.hasAttribute(KEYBINDING_CONTEXT_ATTR)) {
|
||||
return parseInt(domNode.getAttribute(KEYBINDING_CONTEXT_ATTR), 10);
|
||||
const attr = domNode.getAttribute(KEYBINDING_CONTEXT_ATTR);
|
||||
if (attr) {
|
||||
return parseInt(attr, 10);
|
||||
}
|
||||
return NaN;
|
||||
}
|
||||
domNode = domNode.parentElement;
|
||||
}
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { isFalsyOrWhitespace } from 'vs/base/common/strings';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
export enum ContextKeyExprType {
|
||||
export const enum ContextKeyExprType {
|
||||
Defined = 1,
|
||||
Not = 2,
|
||||
Equals = 3,
|
||||
@@ -43,7 +42,7 @@ export abstract class ContextKeyExpr {
|
||||
return new ContextKeyNotExpr(key);
|
||||
}
|
||||
|
||||
public static and(...expr: ContextKeyExpr[]): ContextKeyExpr {
|
||||
public static and(...expr: (ContextKeyExpr | undefined | null)[]): ContextKeyExpr {
|
||||
return new ContextKeyAndExpr(expr);
|
||||
}
|
||||
|
||||
@@ -56,7 +55,7 @@ export abstract class ContextKeyExpr {
|
||||
}
|
||||
//
|
||||
|
||||
public static deserialize(serialized: string): ContextKeyExpr {
|
||||
public static deserialize(serialized: string | null | undefined): ContextKeyExpr | null {
|
||||
if (!serialized) {
|
||||
return null;
|
||||
}
|
||||
@@ -121,7 +120,7 @@ export abstract class ContextKeyExpr {
|
||||
return serializedValue;
|
||||
}
|
||||
|
||||
private static _deserializeRegexValue(serializedValue: string): RegExp {
|
||||
private static _deserializeRegexValue(serializedValue: string): RegExp | null {
|
||||
|
||||
if (isFalsyOrWhitespace(serializedValue)) {
|
||||
console.warn('missing regexp-value for =~-expression');
|
||||
@@ -148,7 +147,7 @@ export abstract class ContextKeyExpr {
|
||||
public abstract getType(): ContextKeyExprType;
|
||||
public abstract equals(other: ContextKeyExpr): boolean;
|
||||
public abstract evaluate(context: IContext): boolean;
|
||||
public abstract normalize(): ContextKeyExpr;
|
||||
public abstract normalize(): ContextKeyExpr | null;
|
||||
public abstract serialize(): string;
|
||||
public abstract keys(): string[];
|
||||
}
|
||||
@@ -389,7 +388,7 @@ export class ContextKeyNotExpr implements ContextKeyExpr {
|
||||
|
||||
export class ContextKeyRegexExpr implements ContextKeyExpr {
|
||||
|
||||
constructor(private key: string, private regexp: RegExp) {
|
||||
constructor(private key: string, private regexp: RegExp | null) {
|
||||
//
|
||||
}
|
||||
|
||||
@@ -404,11 +403,12 @@ export class ContextKeyRegexExpr implements ContextKeyExpr {
|
||||
if (this.key > other.key) {
|
||||
return 1;
|
||||
}
|
||||
const source = this.regexp ? this.regexp.source : undefined;
|
||||
if (source < other.regexp.source) {
|
||||
const thisSource = this.regexp ? this.regexp.source : '';
|
||||
const otherSource = other.regexp ? other.regexp.source : '';
|
||||
if (thisSource < otherSource) {
|
||||
return -1;
|
||||
}
|
||||
if (source > other.regexp.source) {
|
||||
if (thisSource > otherSource) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -416,14 +416,16 @@ export class ContextKeyRegexExpr implements ContextKeyExpr {
|
||||
|
||||
public equals(other: ContextKeyExpr): boolean {
|
||||
if (other instanceof ContextKeyRegexExpr) {
|
||||
const source = this.regexp ? this.regexp.source : undefined;
|
||||
return (this.key === other.key && source === other.regexp.source);
|
||||
const thisSource = this.regexp ? this.regexp.source : '';
|
||||
const otherSource = other.regexp ? other.regexp.source : '';
|
||||
return (this.key === other.key && thisSource === otherSource);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public evaluate(context: IContext): boolean {
|
||||
return this.regexp ? this.regexp.test(context.getValue(this.key)) : false;
|
||||
let value = context.getValue<any>(this.key);
|
||||
return this.regexp ? this.regexp.test(value) : false;
|
||||
}
|
||||
|
||||
public normalize(): ContextKeyExpr {
|
||||
@@ -445,7 +447,7 @@ export class ContextKeyRegexExpr implements ContextKeyExpr {
|
||||
export class ContextKeyAndExpr implements ContextKeyExpr {
|
||||
public readonly expr: ContextKeyExpr[];
|
||||
|
||||
constructor(expr: ContextKeyExpr[]) {
|
||||
constructor(expr: (ContextKeyExpr | null | undefined)[]) {
|
||||
this.expr = ContextKeyAndExpr._normalizeArr(expr);
|
||||
}
|
||||
|
||||
@@ -477,12 +479,12 @@ export class ContextKeyAndExpr implements ContextKeyExpr {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static _normalizeArr(arr: ContextKeyExpr[]): ContextKeyExpr[] {
|
||||
private static _normalizeArr(arr: (ContextKeyExpr | null | undefined)[]): ContextKeyExpr[] {
|
||||
let expr: ContextKeyExpr[] = [];
|
||||
|
||||
if (arr) {
|
||||
for (let i = 0, len = arr.length; i < len; i++) {
|
||||
let e = arr[i];
|
||||
let e: ContextKeyExpr | null | undefined = arr[i];
|
||||
if (!e) {
|
||||
continue;
|
||||
}
|
||||
@@ -506,7 +508,7 @@ export class ContextKeyAndExpr implements ContextKeyExpr {
|
||||
return expr;
|
||||
}
|
||||
|
||||
public normalize(): ContextKeyExpr {
|
||||
public normalize(): ContextKeyExpr | null {
|
||||
if (this.expr.length === 0) {
|
||||
return null;
|
||||
}
|
||||
@@ -523,7 +525,11 @@ export class ContextKeyAndExpr implements ContextKeyExpr {
|
||||
return '';
|
||||
}
|
||||
if (this.expr.length === 1) {
|
||||
return this.normalize().serialize();
|
||||
const normalized = this.normalize();
|
||||
if (!normalized) {
|
||||
return '';
|
||||
}
|
||||
return normalized.serialize();
|
||||
}
|
||||
return this.expr.map(e => e.serialize()).join(' && ');
|
||||
}
|
||||
@@ -641,9 +647,9 @@ export class ContextKeyLessThanEqualsExpr implements ContextKeyExpr {
|
||||
|
||||
export class RawContextKey<T> extends ContextKeyDefinedExpr {
|
||||
|
||||
private _defaultValue: T;
|
||||
private _defaultValue: T | undefined;
|
||||
|
||||
constructor(key: string, defaultValue: T) {
|
||||
constructor(key: string, defaultValue: T | undefined) {
|
||||
super(key);
|
||||
this._defaultValue = defaultValue;
|
||||
}
|
||||
@@ -652,7 +658,7 @@ export class RawContextKey<T> extends ContextKeyDefinedExpr {
|
||||
return target.createKey(this.key, this._defaultValue);
|
||||
}
|
||||
|
||||
public getValue(target: IContextKeyService): T {
|
||||
public getValue(target: IContextKeyService): T | undefined {
|
||||
return target.getContextKeyValue<T>(this.key);
|
||||
}
|
||||
|
||||
@@ -670,21 +676,21 @@ export class RawContextKey<T> extends ContextKeyDefinedExpr {
|
||||
}
|
||||
|
||||
export interface IContext {
|
||||
getValue<T>(key: string): T;
|
||||
getValue<T>(key: string): T | undefined;
|
||||
}
|
||||
|
||||
export interface IContextKey<T> {
|
||||
set(value: T): void;
|
||||
reset(): void;
|
||||
get(): T;
|
||||
get(): T | undefined;
|
||||
}
|
||||
|
||||
export interface IContextKeyServiceTarget {
|
||||
parentElement: IContextKeyServiceTarget;
|
||||
parentElement: IContextKeyServiceTarget | null;
|
||||
setAttribute(attr: string, value: string): void;
|
||||
removeAttribute(attr: string): void;
|
||||
hasAttribute(attr: string): boolean;
|
||||
getAttribute(attr: string): string;
|
||||
getAttribute(attr: string): string | null;
|
||||
}
|
||||
|
||||
export const IContextKeyService = createDecorator<IContextKeyService>('contextKeyService');
|
||||
@@ -702,12 +708,12 @@ export interface IContextKeyService {
|
||||
dispose(): void;
|
||||
|
||||
onDidChangeContext: Event<IContextKeyChangeEvent>;
|
||||
createKey<T>(key: string, defaultValue: T): IContextKey<T>;
|
||||
contextMatchesRules(rules: ContextKeyExpr): boolean;
|
||||
getContextKeyValue<T>(key: string): T;
|
||||
createKey<T>(key: string, defaultValue: T | undefined): IContextKey<T>;
|
||||
contextMatchesRules(rules: ContextKeyExpr | null): boolean;
|
||||
getContextKeyValue<T>(key: string): T | undefined;
|
||||
|
||||
createScoped(target?: IContextKeyServiceTarget): IContextKeyService;
|
||||
getContext(target: IContextKeyServiceTarget): IContext;
|
||||
getContext(target: IContextKeyServiceTarget | null): IContext;
|
||||
}
|
||||
|
||||
export const SET_CONTEXT_COMMAND_ID = 'setContext';
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
|
||||
@@ -16,7 +14,7 @@ function createContext(ctx: any) {
|
||||
}
|
||||
|
||||
suite('ContextKeyExpr', () => {
|
||||
test('ContextKeyExpr.equals', function () {
|
||||
test('ContextKeyExpr.equals', () => {
|
||||
let a = ContextKeyExpr.and(
|
||||
ContextKeyExpr.has('a1'),
|
||||
ContextKeyExpr.and(ContextKeyExpr.has('and.a')),
|
||||
@@ -57,7 +55,7 @@ suite('ContextKeyExpr', () => {
|
||||
assert(a.equals(b), 'expressions should be equal');
|
||||
});
|
||||
|
||||
test('normalize', function () {
|
||||
test('normalize', () => {
|
||||
let key1IsTrue = ContextKeyExpr.equals('key1', true);
|
||||
let key1IsNotFalse = ContextKeyExpr.notEquals('key1', false);
|
||||
let key1IsFalse = ContextKeyExpr.equals('key1', false);
|
||||
@@ -69,7 +67,7 @@ suite('ContextKeyExpr', () => {
|
||||
assert.ok(key1IsNotTrue.normalize().equals(ContextKeyExpr.not('key1')));
|
||||
});
|
||||
|
||||
test('evaluate', function () {
|
||||
test('evaluate', () => {
|
||||
/* tslint:disable:triple-equals */
|
||||
let context = createContext({
|
||||
'a': true,
|
||||
|
||||
Reference in New Issue
Block a user