3c3122c895252dfa107ebdef8c40fb26edc8f67bd0027ad609242135065f4d06f8f5b566ed164a6172a93e863c1555672b1a2c37f13ed8e03345d150e8883c 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. import { isChrome, isEdge, isFirefox, isLinux, isMacintosh, isSafari, isWeb, isWindows } from '../../../base/common/platform.js';
  6. import { isFalsyOrWhitespace } from '../../../base/common/strings.js';
  7. import { createDecorator } from '../../instantiation/common/instantiation.js';
  8. const CONSTANT_VALUES = new Map();
  9. CONSTANT_VALUES.set('false', false);
  10. CONSTANT_VALUES.set('true', true);
  11. CONSTANT_VALUES.set('isMac', isMacintosh);
  12. CONSTANT_VALUES.set('isLinux', isLinux);
  13. CONSTANT_VALUES.set('isWindows', isWindows);
  14. CONSTANT_VALUES.set('isWeb', isWeb);
  15. CONSTANT_VALUES.set('isMacNative', isMacintosh && !isWeb);
  16. CONSTANT_VALUES.set('isEdge', isEdge);
  17. CONSTANT_VALUES.set('isFirefox', isFirefox);
  18. CONSTANT_VALUES.set('isChrome', isChrome);
  19. CONSTANT_VALUES.set('isSafari', isSafari);
  20. const hasOwnProperty = Object.prototype.hasOwnProperty;
  21. export class ContextKeyExpr {
  22. static has(key) {
  23. return ContextKeyDefinedExpr.create(key);
  24. }
  25. static equals(key, value) {
  26. return ContextKeyEqualsExpr.create(key, value);
  27. }
  28. static regex(key, value) {
  29. return ContextKeyRegexExpr.create(key, value);
  30. }
  31. static not(key) {
  32. return ContextKeyNotExpr.create(key);
  33. }
  34. static and(...expr) {
  35. return ContextKeyAndExpr.create(expr, null);
  36. }
  37. static or(...expr) {
  38. return ContextKeyOrExpr.create(expr, null, true);
  39. }
  40. static deserialize(serialized, strict = false) {
  41. if (!serialized) {
  42. return undefined;
  43. }
  44. return this._deserializeOrExpression(serialized, strict);
  45. }
  46. static _deserializeOrExpression(serialized, strict) {
  47. const pieces = serialized.split('||');
  48. return ContextKeyOrExpr.create(pieces.map(p => this._deserializeAndExpression(p, strict)), null, true);
  49. }
  50. static _deserializeAndExpression(serialized, strict) {
  51. const pieces = serialized.split('&&');
  52. return ContextKeyAndExpr.create(pieces.map(p => this._deserializeOne(p, strict)), null);
  53. }
  54. static _deserializeOne(serializedOne, strict) {
  55. serializedOne = serializedOne.trim();
  56. if (serializedOne.indexOf('!=') >= 0) {
  57. const pieces = serializedOne.split('!=');
  58. return ContextKeyNotEqualsExpr.create(pieces[0].trim(), this._deserializeValue(pieces[1], strict));
  59. }
  60. if (serializedOne.indexOf('==') >= 0) {
  61. const pieces = serializedOne.split('==');
  62. return ContextKeyEqualsExpr.create(pieces[0].trim(), this._deserializeValue(pieces[1], strict));
  63. }
  64. if (serializedOne.indexOf('=~') >= 0) {
  65. const pieces = serializedOne.split('=~');
  66. return ContextKeyRegexExpr.create(pieces[0].trim(), this._deserializeRegexValue(pieces[1], strict));
  67. }
  68. if (serializedOne.indexOf(' not in ') >= 0) {
  69. const pieces = serializedOne.split(' not in ');
  70. return ContextKeyNotInExpr.create(pieces[0].trim(), pieces[1].trim());
  71. }
  72. if (serializedOne.indexOf(' in ') >= 0) {
  73. const pieces = serializedOne.split(' in ');
  74. return ContextKeyInExpr.create(pieces[0].trim(), pieces[1].trim());
  75. }
  76. if (/^[^<=>]+>=[^<=>]+$/.test(serializedOne)) {
  77. const pieces = serializedOne.split('>=');
  78. return ContextKeyGreaterEqualsExpr.create(pieces[0].trim(), pieces[1].trim());
  79. }
  80. if (/^[^<=>]+>[^<=>]+$/.test(serializedOne)) {
  81. const pieces = serializedOne.split('>');
  82. return ContextKeyGreaterExpr.create(pieces[0].trim(), pieces[1].trim());
  83. }
  84. if (/^[^<=>]+<=[^<=>]+$/.test(serializedOne)) {
  85. const pieces = serializedOne.split('<=');
  86. return ContextKeySmallerEqualsExpr.create(pieces[0].trim(), pieces[1].trim());
  87. }
  88. if (/^[^<=>]+<[^<=>]+$/.test(serializedOne)) {
  89. const pieces = serializedOne.split('<');
  90. return ContextKeySmallerExpr.create(pieces[0].trim(), pieces[1].trim());
  91. }
  92. if (/^\!\s*/.test(serializedOne)) {
  93. return ContextKeyNotExpr.create(serializedOne.substr(1).trim());
  94. }
  95. return ContextKeyDefinedExpr.create(serializedOne);
  96. }
  97. static _deserializeValue(serializedValue, strict) {
  98. serializedValue = serializedValue.trim();
  99. if (serializedValue === 'true') {
  100. return true;
  101. }
  102. if (serializedValue === 'false') {
  103. return false;
  104. }
  105. const m = /^'([^']*)'$/.exec(serializedValue);
  106. if (m) {
  107. return m[1].trim();
  108. }
  109. return serializedValue;
  110. }
  111. static _deserializeRegexValue(serializedValue, strict) {
  112. if (isFalsyOrWhitespace(serializedValue)) {
  113. if (strict) {
  114. throw new Error('missing regexp-value for =~-expression');
  115. }
  116. else {
  117. console.warn('missing regexp-value for =~-expression');
  118. }
  119. return null;
  120. }
  121. const start = serializedValue.indexOf('/');
  122. const end = serializedValue.lastIndexOf('/');
  123. if (start === end || start < 0 /* || to < 0 */) {
  124. if (strict) {
  125. throw new Error(`bad regexp-value '${serializedValue}', missing /-enclosure`);
  126. }
  127. else {
  128. console.warn(`bad regexp-value '${serializedValue}', missing /-enclosure`);
  129. }
  130. return null;
  131. }
  132. const value = serializedValue.slice(start + 1, end);
  133. const caseIgnoreFlag = serializedValue[end + 1] === 'i' ? 'i' : '';
  134. try {
  135. return new RegExp(value, caseIgnoreFlag);
  136. }
  137. catch (e) {
  138. if (strict) {
  139. throw new Error(`bad regexp-value '${serializedValue}', parse error: ${e}`);
  140. }
  141. else {
  142. console.warn(`bad regexp-value '${serializedValue}', parse error: ${e}`);
  143. }
  144. return null;
  145. }
  146. }
  147. }
  148. export function expressionsAreEqualWithConstantSubstitution(a, b) {
  149. const aExpr = a ? a.substituteConstants() : undefined;
  150. const bExpr = b ? b.substituteConstants() : undefined;
  151. if (!aExpr && !bExpr) {
  152. return true;
  153. }
  154. if (!aExpr || !bExpr) {
  155. return false;
  156. }
  157. return aExpr.equals(bExpr);
  158. }
  159. function cmp(a, b) {
  160. return a.cmp(b);
  161. }
  162. export class ContextKeyFalseExpr {
  163. constructor() {
  164. this.type = 0 /* ContextKeyExprType.False */;
  165. }
  166. cmp(other) {
  167. return this.type - other.type;
  168. }
  169. equals(other) {
  170. return (other.type === this.type);
  171. }
  172. substituteConstants() {
  173. return this;
  174. }
  175. evaluate(context) {
  176. return false;
  177. }
  178. serialize() {
  179. return 'false';
  180. }
  181. keys() {
  182. return [];
  183. }
  184. negate() {
  185. return ContextKeyTrueExpr.INSTANCE;
  186. }
  187. }
  188. ContextKeyFalseExpr.INSTANCE = new ContextKeyFalseExpr();
  189. export class ContextKeyTrueExpr {
  190. constructor() {
  191. this.type = 1 /* ContextKeyExprType.True */;
  192. }
  193. cmp(other) {
  194. return this.type - other.type;
  195. }
  196. equals(other) {
  197. return (other.type === this.type);
  198. }
  199. substituteConstants() {
  200. return this;
  201. }
  202. evaluate(context) {
  203. return true;
  204. }
  205. serialize() {
  206. return 'true';
  207. }
  208. keys() {
  209. return [];
  210. }
  211. negate() {
  212. return ContextKeyFalseExpr.INSTANCE;
  213. }
  214. }
  215. ContextKeyTrueExpr.INSTANCE = new ContextKeyTrueExpr();
  216. export class ContextKeyDefinedExpr {
  217. constructor(key, negated) {
  218. this.key = key;
  219. this.negated = negated;
  220. this.type = 2 /* ContextKeyExprType.Defined */;
  221. }
  222. static create(key, negated = null) {
  223. const constantValue = CONSTANT_VALUES.get(key);
  224. if (typeof constantValue === 'boolean') {
  225. return constantValue ? ContextKeyTrueExpr.INSTANCE : ContextKeyFalseExpr.INSTANCE;
  226. }
  227. return new ContextKeyDefinedExpr(key, negated);
  228. }
  229. cmp(other) {
  230. if (other.type !== this.type) {
  231. return this.type - other.type;
  232. }
  233. return cmp1(this.key, other.key);
  234. }
  235. equals(other) {
  236. if (other.type === this.type) {
  237. return (this.key === other.key);
  238. }
  239. return false;
  240. }
  241. substituteConstants() {
  242. const constantValue = CONSTANT_VALUES.get(this.key);
  243. if (typeof constantValue === 'boolean') {
  244. return constantValue ? ContextKeyTrueExpr.INSTANCE : ContextKeyFalseExpr.INSTANCE;
  245. }
  246. return this;
  247. }
  248. evaluate(context) {
  249. return (!!context.getValue(this.key));
  250. }
  251. serialize() {
  252. return this.key;
  253. }
  254. keys() {
  255. return [this.key];
  256. }
  257. negate() {
  258. if (!this.negated) {
  259. this.negated = ContextKeyNotExpr.create(this.key, this);
  260. }
  261. return this.negated;
  262. }
  263. }
  264. export class ContextKeyEqualsExpr {
  265. constructor(key, value, negated) {
  266. this.key = key;
  267. this.value = value;
  268. this.negated = negated;
  269. this.type = 4 /* ContextKeyExprType.Equals */;
  270. }
  271. static create(key, value, negated = null) {
  272. if (typeof value === 'boolean') {
  273. return (value ? ContextKeyDefinedExpr.create(key, negated) : ContextKeyNotExpr.create(key, negated));
  274. }
  275. const constantValue = CONSTANT_VALUES.get(key);
  276. if (typeof constantValue === 'boolean') {
  277. const trueValue = constantValue ? 'true' : 'false';
  278. return (value === trueValue ? ContextKeyTrueExpr.INSTANCE : ContextKeyFalseExpr.INSTANCE);
  279. }
  280. return new ContextKeyEqualsExpr(key, value, negated);
  281. }
  282. cmp(other) {
  283. if (other.type !== this.type) {
  284. return this.type - other.type;
  285. }
  286. return cmp2(this.key, this.value, other.key, other.value);
  287. }
  288. equals(other) {
  289. if (other.type === this.type) {
  290. return (this.key === other.key && this.value === other.value);
  291. }
  292. return false;
  293. }
  294. substituteConstants() {
  295. const constantValue = CONSTANT_VALUES.get(this.key);
  296. if (typeof constantValue === 'boolean') {
  297. const trueValue = constantValue ? 'true' : 'false';
  298. return (this.value === trueValue ? ContextKeyTrueExpr.INSTANCE : ContextKeyFalseExpr.INSTANCE);
  299. }
  300. return this;
  301. }
  302. evaluate(context) {
  303. // Intentional ==
  304. // eslint-disable-next-line eqeqeq
  305. return (context.getValue(this.key) == this.value);
  306. }
  307. serialize() {
  308. return `${this.key} == '${this.value}'`;
  309. }
  310. keys() {
  311. return [this.key];
  312. }
  313. negate() {
  314. if (!this.negated) {
  315. this.negated = ContextKeyNotEqualsExpr.create(this.key, this.value, this);
  316. }
  317. return this.negated;
  318. }
  319. }
  320. export class ContextKeyInExpr {
  321. constructor(key, valueKey) {
  322. this.key = key;
  323. this.valueKey = valueKey;
  324. this.type = 10 /* ContextKeyExprType.In */;
  325. this.negated = null;
  326. }
  327. static create(key, valueKey) {
  328. return new ContextKeyInExpr(key, valueKey);
  329. }
  330. cmp(other) {
  331. if (other.type !== this.type) {
  332. return this.type - other.type;
  333. }
  334. return cmp2(this.key, this.valueKey, other.key, other.valueKey);
  335. }
  336. equals(other) {
  337. if (other.type === this.type) {
  338. return (this.key === other.key && this.valueKey === other.valueKey);
  339. }
  340. return false;
  341. }
  342. substituteConstants() {
  343. return this;
  344. }
  345. evaluate(context) {
  346. const source = context.getValue(this.valueKey);
  347. const item = context.getValue(this.key);
  348. if (Array.isArray(source)) {
  349. return source.includes(item);
  350. }
  351. if (typeof item === 'string' && typeof source === 'object' && source !== null) {
  352. return hasOwnProperty.call(source, item);
  353. }
  354. return false;
  355. }
  356. serialize() {
  357. return `${this.key} in '${this.valueKey}'`;
  358. }
  359. keys() {
  360. return [this.key, this.valueKey];
  361. }
  362. negate() {
  363. if (!this.negated) {
  364. this.negated = ContextKeyNotInExpr.create(this.key, this.valueKey);
  365. }
  366. return this.negated;
  367. }
  368. }
  369. export class ContextKeyNotInExpr {
  370. constructor(key, valueKey) {
  371. this.key = key;
  372. this.valueKey = valueKey;
  373. this.type = 11 /* ContextKeyExprType.NotIn */;
  374. this._negated = ContextKeyInExpr.create(key, valueKey);
  375. }
  376. static create(key, valueKey) {
  377. return new ContextKeyNotInExpr(key, valueKey);
  378. }
  379. cmp(other) {
  380. if (other.type !== this.type) {
  381. return this.type - other.type;
  382. }
  383. return this._negated.cmp(other._negated);
  384. }
  385. equals(other) {
  386. if (other.type === this.type) {
  387. return this._negated.equals(other._negated);
  388. }
  389. return false;
  390. }
  391. substituteConstants() {
  392. return this;
  393. }
  394. evaluate(context) {
  395. return !this._negated.evaluate(context);
  396. }
  397. serialize() {
  398. return `${this.key} not in '${this.valueKey}'`;
  399. }
  400. keys() {
  401. return this._negated.keys();
  402. }
  403. negate() {
  404. return this._negated;
  405. }
  406. }
  407. export class ContextKeyNotEqualsExpr {
  408. constructor(key, value, negated) {
  409. this.key = key;
  410. this.value = value;
  411. this.negated = negated;
  412. this.type = 5 /* ContextKeyExprType.NotEquals */;
  413. }
  414. static create(key, value, negated = null) {
  415. if (typeof value === 'boolean') {
  416. if (value) {
  417. return ContextKeyNotExpr.create(key, negated);
  418. }
  419. return ContextKeyDefinedExpr.create(key, negated);
  420. }
  421. const constantValue = CONSTANT_VALUES.get(key);
  422. if (typeof constantValue === 'boolean') {
  423. const falseValue = constantValue ? 'true' : 'false';
  424. return (value === falseValue ? ContextKeyFalseExpr.INSTANCE : ContextKeyTrueExpr.INSTANCE);
  425. }
  426. return new ContextKeyNotEqualsExpr(key, value, negated);
  427. }
  428. cmp(other) {
  429. if (other.type !== this.type) {
  430. return this.type - other.type;
  431. }
  432. return cmp2(this.key, this.value, other.key, other.value);
  433. }
  434. equals(other) {
  435. if (other.type === this.type) {
  436. return (this.key === other.key && this.value === other.value);
  437. }
  438. return false;
  439. }
  440. substituteConstants() {
  441. const constantValue = CONSTANT_VALUES.get(this.key);
  442. if (typeof constantValue === 'boolean') {
  443. const falseValue = constantValue ? 'true' : 'false';
  444. return (this.value === falseValue ? ContextKeyFalseExpr.INSTANCE : ContextKeyTrueExpr.INSTANCE);
  445. }
  446. return this;
  447. }
  448. evaluate(context) {
  449. // Intentional !=
  450. // eslint-disable-next-line eqeqeq
  451. return (context.getValue(this.key) != this.value);
  452. }
  453. serialize() {
  454. return `${this.key} != '${this.value}'`;
  455. }
  456. keys() {
  457. return [this.key];
  458. }
  459. negate() {
  460. if (!this.negated) {
  461. this.negated = ContextKeyEqualsExpr.create(this.key, this.value, this);
  462. }
  463. return this.negated;
  464. }
  465. }
  466. export class ContextKeyNotExpr {
  467. constructor(key, negated) {
  468. this.key = key;
  469. this.negated = negated;
  470. this.type = 3 /* ContextKeyExprType.Not */;
  471. }
  472. static create(key, negated = null) {
  473. const constantValue = CONSTANT_VALUES.get(key);
  474. if (typeof constantValue === 'boolean') {
  475. return (constantValue ? ContextKeyFalseExpr.INSTANCE : ContextKeyTrueExpr.INSTANCE);
  476. }
  477. return new ContextKeyNotExpr(key, negated);
  478. }
  479. cmp(other) {
  480. if (other.type !== this.type) {
  481. return this.type - other.type;
  482. }
  483. return cmp1(this.key, other.key);
  484. }
  485. equals(other) {
  486. if (other.type === this.type) {
  487. return (this.key === other.key);
  488. }
  489. return false;
  490. }
  491. substituteConstants() {
  492. const constantValue = CONSTANT_VALUES.get(this.key);
  493. if (typeof constantValue === 'boolean') {
  494. return (constantValue ? ContextKeyFalseExpr.INSTANCE : ContextKeyTrueExpr.INSTANCE);
  495. }
  496. return this;
  497. }
  498. evaluate(context) {
  499. return (!context.getValue(this.key));
  500. }
  501. serialize() {
  502. return `!${this.key}`;
  503. }
  504. keys() {
  505. return [this.key];
  506. }
  507. negate() {
  508. if (!this.negated) {
  509. this.negated = ContextKeyDefinedExpr.create(this.key, this);
  510. }
  511. return this.negated;
  512. }
  513. }
  514. function withFloatOrStr(value, callback) {
  515. if (typeof value === 'string') {
  516. const n = parseFloat(value);
  517. if (!isNaN(n)) {
  518. value = n;
  519. }
  520. }
  521. if (typeof value === 'string' || typeof value === 'number') {
  522. return callback(value);
  523. }
  524. return ContextKeyFalseExpr.INSTANCE;
  525. }
  526. export class ContextKeyGreaterExpr {
  527. constructor(key, value, negated) {
  528. this.key = key;
  529. this.value = value;
  530. this.negated = negated;
  531. this.type = 12 /* ContextKeyExprType.Greater */;
  532. }
  533. static create(key, _value, negated = null) {
  534. return withFloatOrStr(_value, (value) => new ContextKeyGreaterExpr(key, value, negated));
  535. }
  536. cmp(other) {
  537. if (other.type !== this.type) {
  538. return this.type - other.type;
  539. }
  540. return cmp2(this.key, this.value, other.key, other.value);
  541. }
  542. equals(other) {
  543. if (other.type === this.type) {
  544. return (this.key === other.key && this.value === other.value);
  545. }
  546. return false;
  547. }
  548. substituteConstants() {
  549. return this;
  550. }
  551. evaluate(context) {
  552. if (typeof this.value === 'string') {
  553. return false;
  554. }
  555. return (parseFloat(context.getValue(this.key)) > this.value);
  556. }
  557. serialize() {
  558. return `${this.key} > ${this.value}`;
  559. }
  560. keys() {
  561. return [this.key];
  562. }
  563. negate() {
  564. if (!this.negated) {
  565. this.negated = ContextKeySmallerEqualsExpr.create(this.key, this.value, this);
  566. }
  567. return this.negated;
  568. }
  569. }
  570. export class ContextKeyGreaterEqualsExpr {
  571. constructor(key, value, negated) {
  572. this.key = key;
  573. this.value = value;
  574. this.negated = negated;
  575. this.type = 13 /* ContextKeyExprType.GreaterEquals */;
  576. }
  577. static create(key, _value, negated = null) {
  578. return withFloatOrStr(_value, (value) => new ContextKeyGreaterEqualsExpr(key, value, negated));
  579. }
  580. cmp(other) {
  581. if (other.type !== this.type) {
  582. return this.type - other.type;
  583. }
  584. return cmp2(this.key, this.value, other.key, other.value);
  585. }
  586. equals(other) {
  587. if (other.type === this.type) {
  588. return (this.key === other.key && this.value === other.value);
  589. }
  590. return false;
  591. }
  592. substituteConstants() {
  593. return this;
  594. }
  595. evaluate(context) {
  596. if (typeof this.value === 'string') {
  597. return false;
  598. }
  599. return (parseFloat(context.getValue(this.key)) >= this.value);
  600. }
  601. serialize() {
  602. return `${this.key} >= ${this.value}`;
  603. }
  604. keys() {
  605. return [this.key];
  606. }
  607. negate() {
  608. if (!this.negated) {
  609. this.negated = ContextKeySmallerExpr.create(this.key, this.value, this);
  610. }
  611. return this.negated;
  612. }
  613. }
  614. export class ContextKeySmallerExpr {
  615. constructor(key, value, negated) {
  616. this.key = key;
  617. this.value = value;
  618. this.negated = negated;
  619. this.type = 14 /* ContextKeyExprType.Smaller */;
  620. }
  621. static create(key, _value, negated = null) {
  622. return withFloatOrStr(_value, (value) => new ContextKeySmallerExpr(key, value, negated));
  623. }
  624. cmp(other) {
  625. if (other.type !== this.type) {
  626. return this.type - other.type;
  627. }
  628. return cmp2(this.key, this.value, other.key, other.value);
  629. }
  630. equals(other) {
  631. if (other.type === this.type) {
  632. return (this.key === other.key && this.value === other.value);
  633. }
  634. return false;
  635. }
  636. substituteConstants() {
  637. return this;
  638. }
  639. evaluate(context) {
  640. if (typeof this.value === 'string') {
  641. return false;
  642. }
  643. return (parseFloat(context.getValue(this.key)) < this.value);
  644. }
  645. serialize() {
  646. return `${this.key} < ${this.value}`;
  647. }
  648. keys() {
  649. return [this.key];
  650. }
  651. negate() {
  652. if (!this.negated) {
  653. this.negated = ContextKeyGreaterEqualsExpr.create(this.key, this.value, this);
  654. }
  655. return this.negated;
  656. }
  657. }
  658. export class ContextKeySmallerEqualsExpr {
  659. constructor(key, value, negated) {
  660. this.key = key;
  661. this.value = value;
  662. this.negated = negated;
  663. this.type = 15 /* ContextKeyExprType.SmallerEquals */;
  664. }
  665. static create(key, _value, negated = null) {
  666. return withFloatOrStr(_value, (value) => new ContextKeySmallerEqualsExpr(key, value, negated));
  667. }
  668. cmp(other) {
  669. if (other.type !== this.type) {
  670. return this.type - other.type;
  671. }
  672. return cmp2(this.key, this.value, other.key, other.value);
  673. }
  674. equals(other) {
  675. if (other.type === this.type) {
  676. return (this.key === other.key && this.value === other.value);
  677. }
  678. return false;
  679. }
  680. substituteConstants() {
  681. return this;
  682. }
  683. evaluate(context) {
  684. if (typeof this.value === 'string') {
  685. return false;
  686. }
  687. return (parseFloat(context.getValue(this.key)) <= this.value);
  688. }
  689. serialize() {
  690. return `${this.key} <= ${this.value}`;
  691. }
  692. keys() {
  693. return [this.key];
  694. }
  695. negate() {
  696. if (!this.negated) {
  697. this.negated = ContextKeyGreaterExpr.create(this.key, this.value, this);
  698. }
  699. return this.negated;
  700. }
  701. }
  702. export class ContextKeyRegexExpr {
  703. constructor(key, regexp) {
  704. this.key = key;
  705. this.regexp = regexp;
  706. this.type = 7 /* ContextKeyExprType.Regex */;
  707. this.negated = null;
  708. //
  709. }
  710. static create(key, regexp) {
  711. return new ContextKeyRegexExpr(key, regexp);
  712. }
  713. cmp(other) {
  714. if (other.type !== this.type) {
  715. return this.type - other.type;
  716. }
  717. if (this.key < other.key) {
  718. return -1;
  719. }
  720. if (this.key > other.key) {
  721. return 1;
  722. }
  723. const thisSource = this.regexp ? this.regexp.source : '';
  724. const otherSource = other.regexp ? other.regexp.source : '';
  725. if (thisSource < otherSource) {
  726. return -1;
  727. }
  728. if (thisSource > otherSource) {
  729. return 1;
  730. }
  731. return 0;
  732. }
  733. equals(other) {
  734. if (other.type === this.type) {
  735. const thisSource = this.regexp ? this.regexp.source : '';
  736. const otherSource = other.regexp ? other.regexp.source : '';
  737. return (this.key === other.key && thisSource === otherSource);
  738. }
  739. return false;
  740. }
  741. substituteConstants() {
  742. return this;
  743. }
  744. evaluate(context) {
  745. const value = context.getValue(this.key);
  746. return this.regexp ? this.regexp.test(value) : false;
  747. }
  748. serialize() {
  749. const value = this.regexp
  750. ? `/${this.regexp.source}/${this.regexp.ignoreCase ? 'i' : ''}`
  751. : '/invalid/';
  752. return `${this.key} =~ ${value}`;
  753. }
  754. keys() {
  755. return [this.key];
  756. }
  757. negate() {
  758. if (!this.negated) {
  759. this.negated = ContextKeyNotRegexExpr.create(this);
  760. }
  761. return this.negated;
  762. }
  763. }
  764. export class ContextKeyNotRegexExpr {
  765. constructor(_actual) {
  766. this._actual = _actual;
  767. this.type = 8 /* ContextKeyExprType.NotRegex */;
  768. //
  769. }
  770. static create(actual) {
  771. return new ContextKeyNotRegexExpr(actual);
  772. }
  773. cmp(other) {
  774. if (other.type !== this.type) {
  775. return this.type - other.type;
  776. }
  777. return this._actual.cmp(other._actual);
  778. }
  779. equals(other) {
  780. if (other.type === this.type) {
  781. return this._actual.equals(other._actual);
  782. }
  783. return false;
  784. }
  785. substituteConstants() {
  786. return this;
  787. }
  788. evaluate(context) {
  789. return !this._actual.evaluate(context);
  790. }
  791. serialize() {
  792. throw new Error('Method not implemented.');
  793. }
  794. keys() {
  795. return this._actual.keys();
  796. }
  797. negate() {
  798. return this._actual;
  799. }
  800. }
  801. /**
  802. * @returns the same instance if nothing changed.
  803. */
  804. function eliminateConstantsInArray(arr) {
  805. // Allocate array only if there is a difference
  806. let newArr = null;
  807. for (let i = 0, len = arr.length; i < len; i++) {
  808. const newExpr = arr[i].substituteConstants();
  809. if (arr[i] !== newExpr) {
  810. // something has changed!
  811. // allocate array on first difference
  812. if (newArr === null) {
  813. newArr = [];
  814. for (let j = 0; j < i; j++) {
  815. newArr[j] = arr[j];
  816. }
  817. }
  818. }
  819. if (newArr !== null) {
  820. newArr[i] = newExpr;
  821. }
  822. }
  823. if (newArr === null) {
  824. return arr;
  825. }
  826. return newArr;
  827. }
  828. class ContextKeyAndExpr {
  829. constructor(expr, negated) {
  830. this.expr = expr;
  831. this.negated = negated;
  832. this.type = 6 /* ContextKeyExprType.And */;
  833. }
  834. static create(_expr, negated) {
  835. return ContextKeyAndExpr._normalizeArr(_expr, negated);
  836. }
  837. cmp(other) {
  838. if (other.type !== this.type) {
  839. return this.type - other.type;
  840. }
  841. if (this.expr.length < other.expr.length) {
  842. return -1;
  843. }
  844. if (this.expr.length > other.expr.length) {
  845. return 1;
  846. }
  847. for (let i = 0, len = this.expr.length; i < len; i++) {
  848. const r = cmp(this.expr[i], other.expr[i]);
  849. if (r !== 0) {
  850. return r;
  851. }
  852. }
  853. return 0;
  854. }
  855. equals(other) {
  856. if (other.type === this.type) {
  857. if (this.expr.length !== other.expr.length) {
  858. return false;
  859. }
  860. for (let i = 0, len = this.expr.length; i < len; i++) {
  861. if (!this.expr[i].equals(other.expr[i])) {
  862. return false;
  863. }
  864. }
  865. return true;
  866. }
  867. return false;
  868. }
  869. substituteConstants() {
  870. const exprArr = eliminateConstantsInArray(this.expr);
  871. if (exprArr === this.expr) {
  872. // no change
  873. return this;
  874. }
  875. return ContextKeyAndExpr.create(exprArr, this.negated);
  876. }
  877. evaluate(context) {
  878. for (let i = 0, len = this.expr.length; i < len; i++) {
  879. if (!this.expr[i].evaluate(context)) {
  880. return false;
  881. }
  882. }
  883. return true;
  884. }
  885. static _normalizeArr(arr, negated) {
  886. const expr = [];
  887. let hasTrue = false;
  888. for (const e of arr) {
  889. if (!e) {
  890. continue;
  891. }
  892. if (e.type === 1 /* ContextKeyExprType.True */) {
  893. // anything && true ==> anything
  894. hasTrue = true;
  895. continue;
  896. }
  897. if (e.type === 0 /* ContextKeyExprType.False */) {
  898. // anything && false ==> false
  899. return ContextKeyFalseExpr.INSTANCE;
  900. }
  901. if (e.type === 6 /* ContextKeyExprType.And */) {
  902. expr.push(...e.expr);
  903. continue;
  904. }
  905. expr.push(e);
  906. }
  907. if (expr.length === 0 && hasTrue) {
  908. return ContextKeyTrueExpr.INSTANCE;
  909. }
  910. if (expr.length === 0) {
  911. return undefined;
  912. }
  913. if (expr.length === 1) {
  914. return expr[0];
  915. }
  916. expr.sort(cmp);
  917. // eliminate duplicate terms
  918. for (let i = 1; i < expr.length; i++) {
  919. if (expr[i - 1].equals(expr[i])) {
  920. expr.splice(i, 1);
  921. i--;
  922. }
  923. }
  924. if (expr.length === 1) {
  925. return expr[0];
  926. }
  927. // We must distribute any OR expression because we don't support parens
  928. // OR extensions will be at the end (due to sorting rules)
  929. while (expr.length > 1) {
  930. const lastElement = expr[expr.length - 1];
  931. if (lastElement.type !== 9 /* ContextKeyExprType.Or */) {
  932. break;
  933. }
  934. // pop the last element
  935. expr.pop();
  936. // pop the second to last element
  937. const secondToLastElement = expr.pop();
  938. const isFinished = (expr.length === 0);
  939. // distribute `lastElement` over `secondToLastElement`
  940. const resultElement = ContextKeyOrExpr.create(lastElement.expr.map(el => ContextKeyAndExpr.create([el, secondToLastElement], null)), null, isFinished);
  941. if (resultElement) {
  942. expr.push(resultElement);
  943. expr.sort(cmp);
  944. }
  945. }
  946. if (expr.length === 1) {
  947. return expr[0];
  948. }
  949. return new ContextKeyAndExpr(expr, negated);
  950. }
  951. serialize() {
  952. return this.expr.map(e => e.serialize()).join(' && ');
  953. }
  954. keys() {
  955. const result = [];
  956. for (const expr of this.expr) {
  957. result.push(...expr.keys());
  958. }
  959. return result;
  960. }
  961. negate() {
  962. if (!this.negated) {
  963. const result = [];
  964. for (const expr of this.expr) {
  965. result.push(expr.negate());
  966. }
  967. this.negated = ContextKeyOrExpr.create(result, this, true);
  968. }
  969. return this.negated;
  970. }
  971. }
  972. class ContextKeyOrExpr {
  973. constructor(expr, negated) {
  974. this.expr = expr;
  975. this.negated = negated;
  976. this.type = 9 /* ContextKeyExprType.Or */;
  977. }
  978. static create(_expr, negated, extraRedundantCheck) {
  979. return ContextKeyOrExpr._normalizeArr(_expr, negated, extraRedundantCheck);
  980. }
  981. cmp(other) {
  982. if (other.type !== this.type) {
  983. return this.type - other.type;
  984. }
  985. if (this.expr.length < other.expr.length) {
  986. return -1;
  987. }
  988. if (this.expr.length > other.expr.length) {
  989. return 1;
  990. }
  991. for (let i = 0, len = this.expr.length; i < len; i++) {
  992. const r = cmp(this.expr[i], other.expr[i]);
  993. if (r !== 0) {
  994. return r;
  995. }
  996. }
  997. return 0;
  998. }
  999. equals(other) {
  1000. if (other.type === this.type) {
  1001. if (this.expr.length !== other.expr.length) {
  1002. return false;
  1003. }
  1004. for (let i = 0, len = this.expr.length; i < len; i++) {
  1005. if (!this.expr[i].equals(other.expr[i])) {
  1006. return false;
  1007. }
  1008. }
  1009. return true;
  1010. }
  1011. return false;
  1012. }
  1013. substituteConstants() {
  1014. const exprArr = eliminateConstantsInArray(this.expr);
  1015. if (exprArr === this.expr) {
  1016. // no change
  1017. return this;
  1018. }
  1019. return ContextKeyOrExpr.create(exprArr, this.negated, false);
  1020. }
  1021. evaluate(context) {
  1022. for (let i = 0, len = this.expr.length; i < len; i++) {
  1023. if (this.expr[i].evaluate(context)) {
  1024. return true;
  1025. }
  1026. }
  1027. return false;
  1028. }
  1029. static _normalizeArr(arr, negated, extraRedundantCheck) {
  1030. let expr = [];
  1031. let hasFalse = false;
  1032. if (arr) {
  1033. for (let i = 0, len = arr.length; i < len; i++) {
  1034. const e = arr[i];
  1035. if (!e) {
  1036. continue;
  1037. }
  1038. if (e.type === 0 /* ContextKeyExprType.False */) {
  1039. // anything || false ==> anything
  1040. hasFalse = true;
  1041. continue;
  1042. }
  1043. if (e.type === 1 /* ContextKeyExprType.True */) {
  1044. // anything || true ==> true
  1045. return ContextKeyTrueExpr.INSTANCE;
  1046. }
  1047. if (e.type === 9 /* ContextKeyExprType.Or */) {
  1048. expr = expr.concat(e.expr);
  1049. continue;
  1050. }
  1051. expr.push(e);
  1052. }
  1053. if (expr.length === 0 && hasFalse) {
  1054. return ContextKeyFalseExpr.INSTANCE;
  1055. }
  1056. expr.sort(cmp);
  1057. }
  1058. if (expr.length === 0) {
  1059. return undefined;
  1060. }
  1061. if (expr.length === 1) {
  1062. return expr[0];
  1063. }
  1064. // eliminate duplicate terms
  1065. for (let i = 1; i < expr.length; i++) {
  1066. if (expr[i - 1].equals(expr[i])) {
  1067. expr.splice(i, 1);
  1068. i--;
  1069. }
  1070. }
  1071. if (expr.length === 1) {
  1072. return expr[0];
  1073. }
  1074. // eliminate redundant terms
  1075. if (extraRedundantCheck) {
  1076. for (let i = 0; i < expr.length; i++) {
  1077. for (let j = i + 1; j < expr.length; j++) {
  1078. if (implies(expr[i], expr[j])) {
  1079. expr.splice(j, 1);
  1080. j--;
  1081. }
  1082. }
  1083. }
  1084. if (expr.length === 1) {
  1085. return expr[0];
  1086. }
  1087. }
  1088. return new ContextKeyOrExpr(expr, negated);
  1089. }
  1090. serialize() {
  1091. return this.expr.map(e => e.serialize()).join(' || ');
  1092. }
  1093. keys() {
  1094. const result = [];
  1095. for (const expr of this.expr) {
  1096. result.push(...expr.keys());
  1097. }
  1098. return result;
  1099. }
  1100. negate() {
  1101. if (!this.negated) {
  1102. const result = [];
  1103. for (const expr of this.expr) {
  1104. result.push(expr.negate());
  1105. }
  1106. // We don't support parens, so here we distribute the AND over the OR terminals
  1107. // We always take the first 2 AND pairs and distribute them
  1108. while (result.length > 1) {
  1109. const LEFT = result.shift();
  1110. const RIGHT = result.shift();
  1111. const all = [];
  1112. for (const left of getTerminals(LEFT)) {
  1113. for (const right of getTerminals(RIGHT)) {
  1114. all.push(ContextKeyAndExpr.create([left, right], null));
  1115. }
  1116. }
  1117. const isFinished = (result.length === 0);
  1118. result.unshift(ContextKeyOrExpr.create(all, null, isFinished));
  1119. }
  1120. this.negated = result[0];
  1121. }
  1122. return this.negated;
  1123. }
  1124. }
  1125. export class RawContextKey extends ContextKeyDefinedExpr {
  1126. constructor(key, defaultValue, metaOrHide) {
  1127. super(key, null);
  1128. this._defaultValue = defaultValue;
  1129. // collect all context keys into a central place
  1130. if (typeof metaOrHide === 'object') {
  1131. RawContextKey._info.push(Object.assign(Object.assign({}, metaOrHide), { key }));
  1132. }
  1133. else if (metaOrHide !== true) {
  1134. RawContextKey._info.push({ key, description: metaOrHide, type: defaultValue !== null && defaultValue !== undefined ? typeof defaultValue : undefined });
  1135. }
  1136. }
  1137. static all() {
  1138. return RawContextKey._info.values();
  1139. }
  1140. bindTo(target) {
  1141. return target.createKey(this.key, this._defaultValue);
  1142. }
  1143. getValue(target) {
  1144. return target.getContextKeyValue(this.key);
  1145. }
  1146. toNegated() {
  1147. return this.negate();
  1148. }
  1149. isEqualTo(value) {
  1150. return ContextKeyEqualsExpr.create(this.key, value);
  1151. }
  1152. }
  1153. RawContextKey._info = [];
  1154. export const IContextKeyService = createDecorator('contextKeyService');
  1155. export const SET_CONTEXT_COMMAND_ID = 'setContext';
  1156. function cmp1(key1, key2) {
  1157. if (key1 < key2) {
  1158. return -1;
  1159. }
  1160. if (key1 > key2) {
  1161. return 1;
  1162. }
  1163. return 0;
  1164. }
  1165. function cmp2(key1, value1, key2, value2) {
  1166. if (key1 < key2) {
  1167. return -1;
  1168. }
  1169. if (key1 > key2) {
  1170. return 1;
  1171. }
  1172. if (value1 < value2) {
  1173. return -1;
  1174. }
  1175. if (value1 > value2) {
  1176. return 1;
  1177. }
  1178. return 0;
  1179. }
  1180. /**
  1181. * Returns true if it is provable `p` implies `q`.
  1182. */
  1183. export function implies(p, q) {
  1184. if (q.type === 6 /* ContextKeyExprType.And */ && (p.type !== 9 /* ContextKeyExprType.Or */ && p.type !== 6 /* ContextKeyExprType.And */)) {
  1185. // covers the case: A implies A && B
  1186. for (const qTerm of q.expr) {
  1187. if (p.equals(qTerm)) {
  1188. return true;
  1189. }
  1190. }
  1191. }
  1192. const notP = p.negate();
  1193. const expr = getTerminals(notP).concat(getTerminals(q));
  1194. expr.sort(cmp);
  1195. for (let i = 0; i < expr.length; i++) {
  1196. const a = expr[i];
  1197. const notA = a.negate();
  1198. for (let j = i + 1; j < expr.length; j++) {
  1199. const b = expr[j];
  1200. if (notA.equals(b)) {
  1201. return true;
  1202. }
  1203. }
  1204. }
  1205. return false;
  1206. }
  1207. function getTerminals(node) {
  1208. if (node.type === 9 /* ContextKeyExprType.Or */) {
  1209. return node.expr;
  1210. }
  1211. return [node];
  1212. }