sussudio
Version:
An unofficial VS Code Internal API
1,391 lines (1,390 loc) • 43 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { isChrome, isEdge, isFirefox, isLinux, isMacintosh, isSafari, isWeb, isWindows } from "../../../base/common/platform.mjs";
import { isFalsyOrWhitespace } from "../../../base/common/strings.mjs";
import { createDecorator } from "../../instantiation/common/instantiation.mjs";
const CONSTANT_VALUES = new Map();
CONSTANT_VALUES.set('false', false);
CONSTANT_VALUES.set('true', true);
CONSTANT_VALUES.set('isMac', isMacintosh);
CONSTANT_VALUES.set('isLinux', isLinux);
CONSTANT_VALUES.set('isWindows', isWindows);
CONSTANT_VALUES.set('isWeb', isWeb);
CONSTANT_VALUES.set('isMacNative', isMacintosh && !isWeb);
CONSTANT_VALUES.set('isEdge', isEdge);
CONSTANT_VALUES.set('isFirefox', isFirefox);
CONSTANT_VALUES.set('isChrome', isChrome);
CONSTANT_VALUES.set('isSafari', isSafari);
const hasOwnProperty = Object.prototype.hasOwnProperty;
export var ContextKeyExprType;
(function (ContextKeyExprType) {
ContextKeyExprType[ContextKeyExprType["False"] = 0] = "False";
ContextKeyExprType[ContextKeyExprType["True"] = 1] = "True";
ContextKeyExprType[ContextKeyExprType["Defined"] = 2] = "Defined";
ContextKeyExprType[ContextKeyExprType["Not"] = 3] = "Not";
ContextKeyExprType[ContextKeyExprType["Equals"] = 4] = "Equals";
ContextKeyExprType[ContextKeyExprType["NotEquals"] = 5] = "NotEquals";
ContextKeyExprType[ContextKeyExprType["And"] = 6] = "And";
ContextKeyExprType[ContextKeyExprType["Regex"] = 7] = "Regex";
ContextKeyExprType[ContextKeyExprType["NotRegex"] = 8] = "NotRegex";
ContextKeyExprType[ContextKeyExprType["Or"] = 9] = "Or";
ContextKeyExprType[ContextKeyExprType["In"] = 10] = "In";
ContextKeyExprType[ContextKeyExprType["NotIn"] = 11] = "NotIn";
ContextKeyExprType[ContextKeyExprType["Greater"] = 12] = "Greater";
ContextKeyExprType[ContextKeyExprType["GreaterEquals"] = 13] = "GreaterEquals";
ContextKeyExprType[ContextKeyExprType["Smaller"] = 14] = "Smaller";
ContextKeyExprType[ContextKeyExprType["SmallerEquals"] = 15] = "SmallerEquals";
})(ContextKeyExprType || (ContextKeyExprType = {}));
export class ContextKeyExpr {
static false() {
return ContextKeyFalseExpr.INSTANCE;
}
static true() {
return ContextKeyTrueExpr.INSTANCE;
}
static has(key) {
return ContextKeyDefinedExpr.create(key);
}
static equals(key, value) {
return ContextKeyEqualsExpr.create(key, value);
}
static notEquals(key, value) {
return ContextKeyNotEqualsExpr.create(key, value);
}
static regex(key, value) {
return ContextKeyRegexExpr.create(key, value);
}
static in(key, value) {
return ContextKeyInExpr.create(key, value);
}
static notIn(key, value) {
return ContextKeyNotInExpr.create(key, value);
}
static not(key) {
return ContextKeyNotExpr.create(key);
}
static and(...expr) {
return ContextKeyAndExpr.create(expr, null, true);
}
static or(...expr) {
return ContextKeyOrExpr.create(expr, null, true);
}
static greater(key, value) {
return ContextKeyGreaterExpr.create(key, value);
}
static greaterEquals(key, value) {
return ContextKeyGreaterEqualsExpr.create(key, value);
}
static smaller(key, value) {
return ContextKeySmallerExpr.create(key, value);
}
static smallerEquals(key, value) {
return ContextKeySmallerEqualsExpr.create(key, value);
}
static deserialize(serialized, strict = false) {
if (!serialized) {
return undefined;
}
return this._deserializeOrExpression(serialized, strict);
}
static _deserializeOrExpression(serialized, strict) {
const pieces = serialized.split('||');
return ContextKeyOrExpr.create(pieces.map(p => this._deserializeAndExpression(p, strict)), null, true);
}
static _deserializeAndExpression(serialized, strict) {
const pieces = serialized.split('&&');
return ContextKeyAndExpr.create(pieces.map(p => this._deserializeOne(p, strict)), null, true);
}
static _deserializeOne(serializedOne, strict) {
serializedOne = serializedOne.trim();
if (serializedOne.indexOf('!=') >= 0) {
const pieces = serializedOne.split('!=');
return ContextKeyNotEqualsExpr.create(pieces[0].trim(), this._deserializeValue(pieces[1], strict));
}
if (serializedOne.indexOf('==') >= 0) {
const pieces = serializedOne.split('==');
return ContextKeyEqualsExpr.create(pieces[0].trim(), this._deserializeValue(pieces[1], strict));
}
if (serializedOne.indexOf('=~') >= 0) {
const pieces = serializedOne.split('=~');
return ContextKeyRegexExpr.create(pieces[0].trim(), this._deserializeRegexValue(pieces[1], strict));
}
if (serializedOne.indexOf(' not in ') >= 0) {
const pieces = serializedOne.split(' not in ');
return ContextKeyNotInExpr.create(pieces[0].trim(), this._deserializeValue(pieces[1], strict));
}
if (serializedOne.indexOf(' in ') >= 0) {
const pieces = serializedOne.split(' in ');
return ContextKeyInExpr.create(pieces[0].trim(), this._deserializeValue(pieces[1], strict));
}
if (/^[^<=>]+>=[^<=>]+$/.test(serializedOne)) {
const pieces = serializedOne.split('>=');
return ContextKeyGreaterEqualsExpr.create(pieces[0].trim(), pieces[1].trim());
}
if (/^[^<=>]+>[^<=>]+$/.test(serializedOne)) {
const pieces = serializedOne.split('>');
return ContextKeyGreaterExpr.create(pieces[0].trim(), pieces[1].trim());
}
if (/^[^<=>]+<=[^<=>]+$/.test(serializedOne)) {
const pieces = serializedOne.split('<=');
return ContextKeySmallerEqualsExpr.create(pieces[0].trim(), pieces[1].trim());
}
if (/^[^<=>]+<[^<=>]+$/.test(serializedOne)) {
const pieces = serializedOne.split('<');
return ContextKeySmallerExpr.create(pieces[0].trim(), pieces[1].trim());
}
if (/^\!\s*/.test(serializedOne)) {
return ContextKeyNotExpr.create(serializedOne.substr(1).trim());
}
return ContextKeyDefinedExpr.create(serializedOne);
}
static _deserializeValue(serializedValue, strict) {
serializedValue = serializedValue.trim();
if (serializedValue === 'true') {
return true;
}
if (serializedValue === 'false') {
return false;
}
const m = /^'([^']*)'$/.exec(serializedValue);
if (m) {
return m[1].trim();
}
return serializedValue;
}
static _deserializeRegexValue(serializedValue, strict) {
if (isFalsyOrWhitespace(serializedValue)) {
if (strict) {
throw new Error('missing regexp-value for =~-expression');
}
else {
console.warn('missing regexp-value for =~-expression');
}
return null;
}
const start = serializedValue.indexOf('/');
const end = serializedValue.lastIndexOf('/');
if (start === end || start < 0 /* || to < 0 */) {
if (strict) {
throw new Error(`bad regexp-value '${serializedValue}', missing /-enclosure`);
}
else {
console.warn(`bad regexp-value '${serializedValue}', missing /-enclosure`);
}
return null;
}
const value = serializedValue.slice(start + 1, end);
const caseIgnoreFlag = serializedValue[end + 1] === 'i' ? 'i' : '';
try {
return new RegExp(value, caseIgnoreFlag);
}
catch (e) {
if (strict) {
throw new Error(`bad regexp-value '${serializedValue}', parse error: ${e}`);
}
else {
console.warn(`bad regexp-value '${serializedValue}', parse error: ${e}`);
}
return null;
}
}
}
export function expressionsAreEqualWithConstantSubstitution(a, b) {
const aExpr = a ? a.substituteConstants() : undefined;
const bExpr = b ? b.substituteConstants() : undefined;
if (!aExpr && !bExpr) {
return true;
}
if (!aExpr || !bExpr) {
return false;
}
return aExpr.equals(bExpr);
}
function cmp(a, b) {
return a.cmp(b);
}
export class ContextKeyFalseExpr {
static INSTANCE = new ContextKeyFalseExpr();
type = 0 /* ContextKeyExprType.False */;
constructor() {
}
cmp(other) {
return this.type - other.type;
}
equals(other) {
return (other.type === this.type);
}
substituteConstants() {
return this;
}
evaluate(context) {
return false;
}
serialize() {
return 'false';
}
keys() {
return [];
}
map(mapFnc) {
return this;
}
negate() {
return ContextKeyTrueExpr.INSTANCE;
}
}
export class ContextKeyTrueExpr {
static INSTANCE = new ContextKeyTrueExpr();
type = 1 /* ContextKeyExprType.True */;
constructor() {
}
cmp(other) {
return this.type - other.type;
}
equals(other) {
return (other.type === this.type);
}
substituteConstants() {
return this;
}
evaluate(context) {
return true;
}
serialize() {
return 'true';
}
keys() {
return [];
}
map(mapFnc) {
return this;
}
negate() {
return ContextKeyFalseExpr.INSTANCE;
}
}
export class ContextKeyDefinedExpr {
key;
negated;
static create(key, negated = null) {
const constantValue = CONSTANT_VALUES.get(key);
if (typeof constantValue === 'boolean') {
return constantValue ? ContextKeyTrueExpr.INSTANCE : ContextKeyFalseExpr.INSTANCE;
}
return new ContextKeyDefinedExpr(key, negated);
}
type = 2 /* ContextKeyExprType.Defined */;
constructor(key, negated) {
this.key = key;
this.negated = negated;
}
cmp(other) {
if (other.type !== this.type) {
return this.type - other.type;
}
return cmp1(this.key, other.key);
}
equals(other) {
if (other.type === this.type) {
return (this.key === other.key);
}
return false;
}
substituteConstants() {
const constantValue = CONSTANT_VALUES.get(this.key);
if (typeof constantValue === 'boolean') {
return constantValue ? ContextKeyTrueExpr.INSTANCE : ContextKeyFalseExpr.INSTANCE;
}
return this;
}
evaluate(context) {
return (!!context.getValue(this.key));
}
serialize() {
return this.key;
}
keys() {
return [this.key];
}
map(mapFnc) {
return mapFnc.mapDefined(this.key);
}
negate() {
if (!this.negated) {
this.negated = ContextKeyNotExpr.create(this.key, this);
}
return this.negated;
}
}
export class ContextKeyEqualsExpr {
key;
value;
negated;
static create(key, value, negated = null) {
if (typeof value === 'boolean') {
return (value ? ContextKeyDefinedExpr.create(key, negated) : ContextKeyNotExpr.create(key, negated));
}
const constantValue = CONSTANT_VALUES.get(key);
if (typeof constantValue === 'boolean') {
const trueValue = constantValue ? 'true' : 'false';
return (value === trueValue ? ContextKeyTrueExpr.INSTANCE : ContextKeyFalseExpr.INSTANCE);
}
return new ContextKeyEqualsExpr(key, value, negated);
}
type = 4 /* ContextKeyExprType.Equals */;
constructor(key, value, negated) {
this.key = key;
this.value = value;
this.negated = negated;
}
cmp(other) {
if (other.type !== this.type) {
return this.type - other.type;
}
return cmp2(this.key, this.value, other.key, other.value);
}
equals(other) {
if (other.type === this.type) {
return (this.key === other.key && this.value === other.value);
}
return false;
}
substituteConstants() {
const constantValue = CONSTANT_VALUES.get(this.key);
if (typeof constantValue === 'boolean') {
const trueValue = constantValue ? 'true' : 'false';
return (this.value === trueValue ? ContextKeyTrueExpr.INSTANCE : ContextKeyFalseExpr.INSTANCE);
}
return this;
}
evaluate(context) {
// Intentional ==
// eslint-disable-next-line eqeqeq
return (context.getValue(this.key) == this.value);
}
serialize() {
return `${this.key} == '${this.value}'`;
}
keys() {
return [this.key];
}
map(mapFnc) {
return mapFnc.mapEquals(this.key, this.value);
}
negate() {
if (!this.negated) {
this.negated = ContextKeyNotEqualsExpr.create(this.key, this.value, this);
}
return this.negated;
}
}
export class ContextKeyInExpr {
key;
valueKey;
static create(key, valueKey) {
return new ContextKeyInExpr(key, valueKey);
}
type = 10 /* ContextKeyExprType.In */;
negated = null;
constructor(key, valueKey) {
this.key = key;
this.valueKey = valueKey;
}
cmp(other) {
if (other.type !== this.type) {
return this.type - other.type;
}
return cmp2(this.key, this.valueKey, other.key, other.valueKey);
}
equals(other) {
if (other.type === this.type) {
return (this.key === other.key && this.valueKey === other.valueKey);
}
return false;
}
substituteConstants() {
return this;
}
evaluate(context) {
const source = context.getValue(this.valueKey);
const item = context.getValue(this.key);
if (Array.isArray(source)) {
return source.includes(item);
}
if (typeof item === 'string' && typeof source === 'object' && source !== null) {
return hasOwnProperty.call(source, item);
}
return false;
}
serialize() {
return `${this.key} in '${this.valueKey}'`;
}
keys() {
return [this.key, this.valueKey];
}
map(mapFnc) {
return mapFnc.mapIn(this.key, this.valueKey);
}
negate() {
if (!this.negated) {
this.negated = ContextKeyNotInExpr.create(this.key, this.valueKey);
}
return this.negated;
}
}
export class ContextKeyNotInExpr {
key;
valueKey;
static create(key, valueKey) {
return new ContextKeyNotInExpr(key, valueKey);
}
type = 11 /* ContextKeyExprType.NotIn */;
_negated;
constructor(key, valueKey) {
this.key = key;
this.valueKey = valueKey;
this._negated = ContextKeyInExpr.create(key, valueKey);
}
cmp(other) {
if (other.type !== this.type) {
return this.type - other.type;
}
return this._negated.cmp(other._negated);
}
equals(other) {
if (other.type === this.type) {
return this._negated.equals(other._negated);
}
return false;
}
substituteConstants() {
return this;
}
evaluate(context) {
return !this._negated.evaluate(context);
}
serialize() {
return `${this.key} not in '${this.valueKey}'`;
}
keys() {
return this._negated.keys();
}
map(mapFnc) {
return mapFnc.mapNotIn(this.key, this.valueKey);
}
negate() {
return this._negated;
}
}
export class ContextKeyNotEqualsExpr {
key;
value;
negated;
static create(key, value, negated = null) {
if (typeof value === 'boolean') {
if (value) {
return ContextKeyNotExpr.create(key, negated);
}
return ContextKeyDefinedExpr.create(key, negated);
}
const constantValue = CONSTANT_VALUES.get(key);
if (typeof constantValue === 'boolean') {
const falseValue = constantValue ? 'true' : 'false';
return (value === falseValue ? ContextKeyFalseExpr.INSTANCE : ContextKeyTrueExpr.INSTANCE);
}
return new ContextKeyNotEqualsExpr(key, value, negated);
}
type = 5 /* ContextKeyExprType.NotEquals */;
constructor(key, value, negated) {
this.key = key;
this.value = value;
this.negated = negated;
}
cmp(other) {
if (other.type !== this.type) {
return this.type - other.type;
}
return cmp2(this.key, this.value, other.key, other.value);
}
equals(other) {
if (other.type === this.type) {
return (this.key === other.key && this.value === other.value);
}
return false;
}
substituteConstants() {
const constantValue = CONSTANT_VALUES.get(this.key);
if (typeof constantValue === 'boolean') {
const falseValue = constantValue ? 'true' : 'false';
return (this.value === falseValue ? ContextKeyFalseExpr.INSTANCE : ContextKeyTrueExpr.INSTANCE);
}
return this;
}
evaluate(context) {
// Intentional !=
// eslint-disable-next-line eqeqeq
return (context.getValue(this.key) != this.value);
}
serialize() {
return `${this.key} != '${this.value}'`;
}
keys() {
return [this.key];
}
map(mapFnc) {
return mapFnc.mapNotEquals(this.key, this.value);
}
negate() {
if (!this.negated) {
this.negated = ContextKeyEqualsExpr.create(this.key, this.value, this);
}
return this.negated;
}
}
export class ContextKeyNotExpr {
key;
negated;
static create(key, negated = null) {
const constantValue = CONSTANT_VALUES.get(key);
if (typeof constantValue === 'boolean') {
return (constantValue ? ContextKeyFalseExpr.INSTANCE : ContextKeyTrueExpr.INSTANCE);
}
return new ContextKeyNotExpr(key, negated);
}
type = 3 /* ContextKeyExprType.Not */;
constructor(key, negated) {
this.key = key;
this.negated = negated;
}
cmp(other) {
if (other.type !== this.type) {
return this.type - other.type;
}
return cmp1(this.key, other.key);
}
equals(other) {
if (other.type === this.type) {
return (this.key === other.key);
}
return false;
}
substituteConstants() {
const constantValue = CONSTANT_VALUES.get(this.key);
if (typeof constantValue === 'boolean') {
return (constantValue ? ContextKeyFalseExpr.INSTANCE : ContextKeyTrueExpr.INSTANCE);
}
return this;
}
evaluate(context) {
return (!context.getValue(this.key));
}
serialize() {
return `!${this.key}`;
}
keys() {
return [this.key];
}
map(mapFnc) {
return mapFnc.mapNot(this.key);
}
negate() {
if (!this.negated) {
this.negated = ContextKeyDefinedExpr.create(this.key, this);
}
return this.negated;
}
}
function withFloatOrStr(value, callback) {
if (typeof value === 'string') {
const n = parseFloat(value);
if (!isNaN(n)) {
value = n;
}
}
if (typeof value === 'string' || typeof value === 'number') {
return callback(value);
}
return ContextKeyFalseExpr.INSTANCE;
}
export class ContextKeyGreaterExpr {
key;
value;
negated;
static create(key, _value, negated = null) {
return withFloatOrStr(_value, (value) => new ContextKeyGreaterExpr(key, value, negated));
}
type = 12 /* ContextKeyExprType.Greater */;
constructor(key, value, negated) {
this.key = key;
this.value = value;
this.negated = negated;
}
cmp(other) {
if (other.type !== this.type) {
return this.type - other.type;
}
return cmp2(this.key, this.value, other.key, other.value);
}
equals(other) {
if (other.type === this.type) {
return (this.key === other.key && this.value === other.value);
}
return false;
}
substituteConstants() {
return this;
}
evaluate(context) {
if (typeof this.value === 'string') {
return false;
}
return (parseFloat(context.getValue(this.key)) > this.value);
}
serialize() {
return `${this.key} > ${this.value}`;
}
keys() {
return [this.key];
}
map(mapFnc) {
return mapFnc.mapGreater(this.key, this.value);
}
negate() {
if (!this.negated) {
this.negated = ContextKeySmallerEqualsExpr.create(this.key, this.value, this);
}
return this.negated;
}
}
export class ContextKeyGreaterEqualsExpr {
key;
value;
negated;
static create(key, _value, negated = null) {
return withFloatOrStr(_value, (value) => new ContextKeyGreaterEqualsExpr(key, value, negated));
}
type = 13 /* ContextKeyExprType.GreaterEquals */;
constructor(key, value, negated) {
this.key = key;
this.value = value;
this.negated = negated;
}
cmp(other) {
if (other.type !== this.type) {
return this.type - other.type;
}
return cmp2(this.key, this.value, other.key, other.value);
}
equals(other) {
if (other.type === this.type) {
return (this.key === other.key && this.value === other.value);
}
return false;
}
substituteConstants() {
return this;
}
evaluate(context) {
if (typeof this.value === 'string') {
return false;
}
return (parseFloat(context.getValue(this.key)) >= this.value);
}
serialize() {
return `${this.key} >= ${this.value}`;
}
keys() {
return [this.key];
}
map(mapFnc) {
return mapFnc.mapGreaterEquals(this.key, this.value);
}
negate() {
if (!this.negated) {
this.negated = ContextKeySmallerExpr.create(this.key, this.value, this);
}
return this.negated;
}
}
export class ContextKeySmallerExpr {
key;
value;
negated;
static create(key, _value, negated = null) {
return withFloatOrStr(_value, (value) => new ContextKeySmallerExpr(key, value, negated));
}
type = 14 /* ContextKeyExprType.Smaller */;
constructor(key, value, negated) {
this.key = key;
this.value = value;
this.negated = negated;
}
cmp(other) {
if (other.type !== this.type) {
return this.type - other.type;
}
return cmp2(this.key, this.value, other.key, other.value);
}
equals(other) {
if (other.type === this.type) {
return (this.key === other.key && this.value === other.value);
}
return false;
}
substituteConstants() {
return this;
}
evaluate(context) {
if (typeof this.value === 'string') {
return false;
}
return (parseFloat(context.getValue(this.key)) < this.value);
}
serialize() {
return `${this.key} < ${this.value}`;
}
keys() {
return [this.key];
}
map(mapFnc) {
return mapFnc.mapSmaller(this.key, this.value);
}
negate() {
if (!this.negated) {
this.negated = ContextKeyGreaterEqualsExpr.create(this.key, this.value, this);
}
return this.negated;
}
}
export class ContextKeySmallerEqualsExpr {
key;
value;
negated;
static create(key, _value, negated = null) {
return withFloatOrStr(_value, (value) => new ContextKeySmallerEqualsExpr(key, value, negated));
}
type = 15 /* ContextKeyExprType.SmallerEquals */;
constructor(key, value, negated) {
this.key = key;
this.value = value;
this.negated = negated;
}
cmp(other) {
if (other.type !== this.type) {
return this.type - other.type;
}
return cmp2(this.key, this.value, other.key, other.value);
}
equals(other) {
if (other.type === this.type) {
return (this.key === other.key && this.value === other.value);
}
return false;
}
substituteConstants() {
return this;
}
evaluate(context) {
if (typeof this.value === 'string') {
return false;
}
return (parseFloat(context.getValue(this.key)) <= this.value);
}
serialize() {
return `${this.key} <= ${this.value}`;
}
keys() {
return [this.key];
}
map(mapFnc) {
return mapFnc.mapSmallerEquals(this.key, this.value);
}
negate() {
if (!this.negated) {
this.negated = ContextKeyGreaterExpr.create(this.key, this.value, this);
}
return this.negated;
}
}
export class ContextKeyRegexExpr {
key;
regexp;
static create(key, regexp) {
return new ContextKeyRegexExpr(key, regexp);
}
type = 7 /* ContextKeyExprType.Regex */;
negated = null;
constructor(key, regexp) {
this.key = key;
this.regexp = regexp;
//
}
cmp(other) {
if (other.type !== this.type) {
return this.type - other.type;
}
if (this.key < other.key) {
return -1;
}
if (this.key > other.key) {
return 1;
}
const thisSource = this.regexp ? this.regexp.source : '';
const otherSource = other.regexp ? other.regexp.source : '';
if (thisSource < otherSource) {
return -1;
}
if (thisSource > otherSource) {
return 1;
}
return 0;
}
equals(other) {
if (other.type === this.type) {
const thisSource = this.regexp ? this.regexp.source : '';
const otherSource = other.regexp ? other.regexp.source : '';
return (this.key === other.key && thisSource === otherSource);
}
return false;
}
substituteConstants() {
return this;
}
evaluate(context) {
const value = context.getValue(this.key);
return this.regexp ? this.regexp.test(value) : false;
}
serialize() {
const value = this.regexp
? `/${this.regexp.source}/${this.regexp.ignoreCase ? 'i' : ''}`
: '/invalid/';
return `${this.key} =~ ${value}`;
}
keys() {
return [this.key];
}
map(mapFnc) {
return mapFnc.mapRegex(this.key, this.regexp);
}
negate() {
if (!this.negated) {
this.negated = ContextKeyNotRegexExpr.create(this);
}
return this.negated;
}
}
export class ContextKeyNotRegexExpr {
_actual;
static create(actual) {
return new ContextKeyNotRegexExpr(actual);
}
type = 8 /* ContextKeyExprType.NotRegex */;
constructor(_actual) {
this._actual = _actual;
//
}
cmp(other) {
if (other.type !== this.type) {
return this.type - other.type;
}
return this._actual.cmp(other._actual);
}
equals(other) {
if (other.type === this.type) {
return this._actual.equals(other._actual);
}
return false;
}
substituteConstants() {
return this;
}
evaluate(context) {
return !this._actual.evaluate(context);
}
serialize() {
throw new Error('Method not implemented.');
}
keys() {
return this._actual.keys();
}
map(mapFnc) {
return new ContextKeyNotRegexExpr(this._actual.map(mapFnc));
}
negate() {
return this._actual;
}
}
/**
* @returns the same instance if nothing changed.
*/
function eliminateConstantsInArray(arr) {
// Allocate array only if there is a difference
let newArr = null;
for (let i = 0, len = arr.length; i < len; i++) {
const newExpr = arr[i].substituteConstants();
if (arr[i] !== newExpr) {
// something has changed!
// allocate array on first difference
if (newArr === null) {
newArr = [];
for (let j = 0; j < i; j++) {
newArr[j] = arr[j];
}
}
}
if (newArr !== null) {
newArr[i] = newExpr;
}
}
if (newArr === null) {
return arr;
}
return newArr;
}
class ContextKeyAndExpr {
expr;
negated;
static create(_expr, negated, extraRedundantCheck) {
return ContextKeyAndExpr._normalizeArr(_expr, negated, extraRedundantCheck);
}
type = 6 /* ContextKeyExprType.And */;
constructor(expr, negated) {
this.expr = expr;
this.negated = negated;
}
cmp(other) {
if (other.type !== this.type) {
return this.type - other.type;
}
if (this.expr.length < other.expr.length) {
return -1;
}
if (this.expr.length > other.expr.length) {
return 1;
}
for (let i = 0, len = this.expr.length; i < len; i++) {
const r = cmp(this.expr[i], other.expr[i]);
if (r !== 0) {
return r;
}
}
return 0;
}
equals(other) {
if (other.type === this.type) {
if (this.expr.length !== other.expr.length) {
return false;
}
for (let i = 0, len = this.expr.length; i < len; i++) {
if (!this.expr[i].equals(other.expr[i])) {
return false;
}
}
return true;
}
return false;
}
substituteConstants() {
const exprArr = eliminateConstantsInArray(this.expr);
if (exprArr === this.expr) {
// no change
return this;
}
return ContextKeyAndExpr.create(exprArr, this.negated, false);
}
evaluate(context) {
for (let i = 0, len = this.expr.length; i < len; i++) {
if (!this.expr[i].evaluate(context)) {
return false;
}
}
return true;
}
static _normalizeArr(arr, negated, extraRedundantCheck) {
const expr = [];
let hasTrue = false;
for (const e of arr) {
if (!e) {
continue;
}
if (e.type === 1 /* ContextKeyExprType.True */) {
// anything && true ==> anything
hasTrue = true;
continue;
}
if (e.type === 0 /* ContextKeyExprType.False */) {
// anything && false ==> false
return ContextKeyFalseExpr.INSTANCE;
}
if (e.type === 6 /* ContextKeyExprType.And */) {
expr.push(...e.expr);
continue;
}
expr.push(e);
}
if (expr.length === 0 && hasTrue) {
return ContextKeyTrueExpr.INSTANCE;
}
if (expr.length === 0) {
return undefined;
}
if (expr.length === 1) {
return expr[0];
}
expr.sort(cmp);
// eliminate duplicate terms
for (let i = 1; i < expr.length; i++) {
if (expr[i - 1].equals(expr[i])) {
expr.splice(i, 1);
i--;
}
}
if (expr.length === 1) {
return expr[0];
}
// We must distribute any OR expression because we don't support parens
// OR extensions will be at the end (due to sorting rules)
while (expr.length > 1) {
const lastElement = expr[expr.length - 1];
if (lastElement.type !== 9 /* ContextKeyExprType.Or */) {
break;
}
// pop the last element
expr.pop();
// pop the second to last element
const secondToLastElement = expr.pop();
const isFinished = (expr.length === 0);
// distribute `lastElement` over `secondToLastElement`
const resultElement = ContextKeyOrExpr.create(lastElement.expr.map(el => ContextKeyAndExpr.create([el, secondToLastElement], null, extraRedundantCheck)), null, isFinished);
if (resultElement) {
expr.push(resultElement);
expr.sort(cmp);
}
}
if (expr.length === 1) {
return expr[0];
}
// resolve false AND expressions
if (extraRedundantCheck) {
for (let i = 0; i < expr.length; i++) {
for (let j = i + 1; j < expr.length; j++) {
if (expr[i].negate().equals(expr[j])) {
// A && !A case
return ContextKeyFalseExpr.INSTANCE;
}
}
}
if (expr.length === 1) {
return expr[0];
}
}
return new ContextKeyAndExpr(expr, negated);
}
serialize() {
return this.expr.map(e => e.serialize()).join(' && ');
}
keys() {
const result = [];
for (const expr of this.expr) {
result.push(...expr.keys());
}
return result;
}
map(mapFnc) {
return new ContextKeyAndExpr(this.expr.map(expr => expr.map(mapFnc)), null);
}
negate() {
if (!this.negated) {
const result = [];
for (const expr of this.expr) {
result.push(expr.negate());
}
this.negated = ContextKeyOrExpr.create(result, this, true);
}
return this.negated;
}
}
class ContextKeyOrExpr {
expr;
negated;
static create(_expr, negated, extraRedundantCheck) {
return ContextKeyOrExpr._normalizeArr(_expr, negated, extraRedundantCheck);
}
type = 9 /* ContextKeyExprType.Or */;
constructor(expr, negated) {
this.expr = expr;
this.negated = negated;
}
cmp(other) {
if (other.type !== this.type) {
return this.type - other.type;
}
if (this.expr.length < other.expr.length) {
return -1;
}
if (this.expr.length > other.expr.length) {
return 1;
}
for (let i = 0, len = this.expr.length; i < len; i++) {
const r = cmp(this.expr[i], other.expr[i]);
if (r !== 0) {
return r;
}
}
return 0;
}
equals(other) {
if (other.type === this.type) {
if (this.expr.length !== other.expr.length) {
return false;
}
for (let i = 0, len = this.expr.length; i < len; i++) {
if (!this.expr[i].equals(other.expr[i])) {
return false;
}
}
return true;
}
return false;
}
substituteConstants() {
const exprArr = eliminateConstantsInArray(this.expr);
if (exprArr === this.expr) {
// no change
return this;
}
return ContextKeyOrExpr.create(exprArr, this.negated, false);
}
evaluate(context) {
for (let i = 0, len = this.expr.length; i < len; i++) {
if (this.expr[i].evaluate(context)) {
return true;
}
}
return false;
}
static _normalizeArr(arr, negated, extraRedundantCheck) {
let expr = [];
let hasFalse = false;
if (arr) {
for (let i = 0, len = arr.length; i < len; i++) {
const e = arr[i];
if (!e) {
continue;
}
if (e.type === 0 /* ContextKeyExprType.False */) {
// anything || false ==> anything
hasFalse = true;
continue;
}
if (e.type === 1 /* ContextKeyExprType.True */) {
// anything || true ==> true
return ContextKeyTrueExpr.INSTANCE;
}
if (e.type === 9 /* ContextKeyExprType.Or */) {
expr = expr.concat(e.expr);
continue;
}
expr.push(e);
}
if (expr.length === 0 && hasFalse) {
return ContextKeyFalseExpr.INSTANCE;
}
expr.sort(cmp);
}
if (expr.length === 0) {
return undefined;
}
if (expr.length === 1) {
return expr[0];
}
// eliminate duplicate terms
for (let i = 1; i < expr.length; i++) {
if (expr[i - 1].equals(expr[i])) {
expr.splice(i, 1);
i--;
}
}
if (expr.length === 1) {
return expr[0];
}
// resolve true OR expressions
if (extraRedundantCheck) {
for (let i = 0; i < expr.length; i++) {
for (let j = i + 1; j < expr.length; j++) {
if (expr[i].negate().equals(expr[j])) {
// A || !A case
return ContextKeyTrueExpr.INSTANCE;
}
}
}
if (expr.length === 1) {
return expr[0];
}
}
return new ContextKeyOrExpr(expr, negated);
}
serialize() {
return this.expr.map(e => e.serialize()).join(' || ');
}
keys() {
const result = [];
for (const expr of this.expr) {
result.push(...expr.keys());
}
return result;
}
map(mapFnc) {
return new ContextKeyOrExpr(this.expr.map(expr => expr.map(mapFnc)), null);
}
negate() {
if (!this.negated) {
const result = [];
for (const expr of this.expr) {
result.push(expr.negate());
}
// We don't support parens, so here we distribute the AND over the OR terminals
// We always take the first 2 AND pairs and distribute them
while (result.length > 1) {
const LEFT = result.shift();
const RIGHT = result.shift();
const all = [];
for (const left of getTerminals(LEFT)) {
for (const right of getTerminals(RIGHT)) {
all.push(ContextKeyAndExpr.create([left, right], null, false));
}
}
result.unshift(ContextKeyOrExpr.create(all, null, false));
}
this.negated = ContextKeyOrExpr.create(result, this, true);
}
return this.negated;
}
}
export class RawContextKey extends ContextKeyDefinedExpr {
static _info = [];
static all() {
return RawContextKey._info.values();
}
_defaultValue;
constructor(key, defaultValue, metaOrHide) {
super(key, null);
this._defaultValue = defaultValue;
// collect all context keys into a central place
if (typeof metaOrHide === 'object') {
RawContextKey._info.push({ ...metaOrHide, key });
}
else if (metaOrHide !== true) {
RawContextKey._info.push({ key, description: metaOrHide, type: defaultValue !== null && defaultValue !== undefined ? typeof defaultValue : undefined });
}
}
bindTo(target) {
return target.createKey(this.key, this._defaultValue);
}
getValue(target) {
return target.getContextKeyValue(this.key);
}
toNegated() {
return this.negate();
}
isEqualTo(value) {
return ContextKeyEqualsExpr.create(this.key, value);
}
notEqualsTo(value) {
return ContextKeyNotEqualsExpr.create(this.key, value);
}
}
export const IContextKeyService = createDecorator('contextKeyService');
function cmp1(key1, key2) {
if (key1 < key2) {
return -1;
}
if (key1 > key2) {
return 1;
}
return 0;
}
function cmp2(key1, value1, key2, value2) {
if (key1 < key2) {
return -1;
}
if (key1 > key2) {
return 1;
}
if (value1 < value2) {
return -1;
}
if (value1 > value2) {
return 1;
}
return 0;
}
/**
* Returns true if it is provable `p` implies `q`.
*/
export function implies(p, q) {
if (p.type === 0 /* ContextKeyExprType.False */ || q.type === 1 /* ContextKeyExprType.True */) {
// false implies anything
// anything implies true
return true;
}
if (p.type === 9 /* ContextKeyExprType.Or */) {
if (q.type === 9 /* ContextKeyExprType.Or */) {
// `a || b || c` can only imply something like `a || b || c || d`
return allElementsIncluded(p.expr, q.expr);
}
return false;
}
if (q.type === 9 /* ContextKeyExprType.Or */) {
for (const element of q.expr) {
if (implies(p, element)) {
return true;
}
}
return false;
}
if (p.type === 6 /* ContextKeyExprType.And */) {
if (q.type === 6 /* ContextKeyExprType.And */) {
// `a && b && c` implies `a && c`
return allElementsIncluded(q.expr, p.expr);
}
for (const element of p.expr) {
if (implies(element, q)) {
return true;
}
}
return false;
}
return p.equals(q);
}
/**
* Returns true if all elements in `p` are also present in `q`.
* The two arrays are assumed to be sorted
*/
function allElementsIncluded(p, q) {
let pIndex = 0;
let qIndex = 0;
while (pIndex < p.length && qIndex < q.length) {
const cmp = p[pIndex].cmp(q[qIndex]);
if (cmp < 0) {
// an element from `p` is missing from `q`
return false;
}
else if (cmp === 0) {
pIndex++;
qIndex++;
}
else {
qIndex++;
}
}
return (pIndex === p.length);
}
function getTerminals(node) {
if (node.type === 9 /* ContextKeyExprType.Or */) {
return node.expr;
}
return [node];
}