123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
- return c > 3 && r && Object.defineProperty(target, key, r), r;
- };
- var __param = (this && this.__param) || function (paramIndex, decorator) {
- return function (target, key) { decorator(target, key, paramIndex); }
- };
- import { PauseableEmitter } from '../../../base/common/event.js';
- import { Iterable } from '../../../base/common/iterator.js';
- import { DisposableStore, MutableDisposable } from '../../../base/common/lifecycle.js';
- import { TernarySearchTree } from '../../../base/common/map.js';
- import { localize } from '../../../nls.js';
- import { CommandsRegistry } from '../../commands/common/commands.js';
- import { IConfigurationService } from '../../configuration/common/configuration.js';
- import { IContextKeyService, RawContextKey, SET_CONTEXT_COMMAND_ID } from '../common/contextkey.js';
- import { KeybindingResolver } from '../../keybinding/common/keybindingResolver.js';
- const KEYBINDING_CONTEXT_ATTR = 'data-keybinding-context';
- export class Context {
- constructor(id, parent) {
- this._id = id;
- this._parent = parent;
- this._value = Object.create(null);
- this._value['_contextId'] = id;
- }
- setValue(key, value) {
- // console.log('SET ' + key + ' = ' + value + ' ON ' + this._id);
- if (this._value[key] !== value) {
- this._value[key] = value;
- return true;
- }
- return false;
- }
- removeValue(key) {
- // console.log('REMOVE ' + key + ' FROM ' + this._id);
- if (key in this._value) {
- delete this._value[key];
- return true;
- }
- return false;
- }
- getValue(key) {
- const ret = this._value[key];
- if (typeof ret === 'undefined' && this._parent) {
- return this._parent.getValue(key);
- }
- return ret;
- }
- }
- class NullContext extends Context {
- constructor() {
- super(-1, null);
- }
- setValue(key, value) {
- return false;
- }
- removeValue(key) {
- return false;
- }
- getValue(key) {
- return undefined;
- }
- }
- NullContext.INSTANCE = new NullContext();
- class ConfigAwareContextValuesContainer extends Context {
- constructor(id, _configurationService, emitter) {
- super(id, null);
- this._configurationService = _configurationService;
- this._values = TernarySearchTree.forConfigKeys();
- this._listener = this._configurationService.onDidChangeConfiguration(event => {
- if (event.source === 6 /* DEFAULT */) {
- // new setting, reset everything
- const allKeys = Array.from(Iterable.map(this._values, ([k]) => k));
- this._values.clear();
- emitter.fire(new ArrayContextKeyChangeEvent(allKeys));
- }
- else {
- const changedKeys = [];
- for (const configKey of event.affectedKeys) {
- const contextKey = `config.${configKey}`;
- const cachedItems = this._values.findSuperstr(contextKey);
- if (cachedItems !== undefined) {
- changedKeys.push(...Iterable.map(cachedItems, ([key]) => key));
- this._values.deleteSuperstr(contextKey);
- }
- if (this._values.has(contextKey)) {
- changedKeys.push(contextKey);
- this._values.delete(contextKey);
- }
- }
- emitter.fire(new ArrayContextKeyChangeEvent(changedKeys));
- }
- });
- }
- dispose() {
- this._listener.dispose();
- }
- getValue(key) {
- if (key.indexOf(ConfigAwareContextValuesContainer._keyPrefix) !== 0) {
- return super.getValue(key);
- }
- 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 = undefined;
- switch (typeof configValue) {
- case 'number':
- case 'boolean':
- case 'string':
- value = configValue;
- break;
- default:
- if (Array.isArray(configValue)) {
- value = JSON.stringify(configValue);
- }
- else {
- value = configValue;
- }
- }
- this._values.set(key, value);
- return value;
- }
- setValue(key, value) {
- return super.setValue(key, value);
- }
- removeValue(key) {
- return super.removeValue(key);
- }
- }
- ConfigAwareContextValuesContainer._keyPrefix = 'config.';
- class ContextKey {
- constructor(service, key, defaultValue) {
- this._service = service;
- this._key = key;
- this._defaultValue = defaultValue;
- this.reset();
- }
- set(value) {
- this._service.setContext(this._key, value);
- }
- reset() {
- if (typeof this._defaultValue === 'undefined') {
- this._service.removeContext(this._key);
- }
- else {
- this._service.setContext(this._key, this._defaultValue);
- }
- }
- get() {
- return this._service.getContextKeyValue(this._key);
- }
- }
- class SimpleContextKeyChangeEvent {
- constructor(key) {
- this.key = key;
- }
- affectsSome(keys) {
- return keys.has(this.key);
- }
- }
- class ArrayContextKeyChangeEvent {
- constructor(keys) {
- this.keys = keys;
- }
- affectsSome(keys) {
- for (const key of this.keys) {
- if (keys.has(key)) {
- return true;
- }
- }
- return false;
- }
- }
- class CompositeContextKeyChangeEvent {
- constructor(events) {
- this.events = events;
- }
- affectsSome(keys) {
- for (const e of this.events) {
- if (e.affectsSome(keys)) {
- return true;
- }
- }
- return false;
- }
- }
- export class AbstractContextKeyService {
- constructor(myContextId) {
- this._onDidChangeContext = new PauseableEmitter({ merge: input => new CompositeContextKeyChangeEvent(input) });
- this.onDidChangeContext = this._onDidChangeContext.event;
- this._isDisposed = false;
- this._myContextId = myContextId;
- }
- createKey(key, defaultValue) {
- if (this._isDisposed) {
- throw new Error(`AbstractContextKeyService has been disposed`);
- }
- return new ContextKey(this, key, defaultValue);
- }
- bufferChangeEvents(callback) {
- this._onDidChangeContext.pause();
- try {
- callback();
- }
- finally {
- this._onDidChangeContext.resume();
- }
- }
- createScoped(domNode) {
- if (this._isDisposed) {
- throw new Error(`AbstractContextKeyService has been disposed`);
- }
- return new ScopedContextKeyService(this, domNode);
- }
- contextMatchesRules(rules) {
- 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);
- // rules.keys().forEach(key => { console.log(key, ctx[key]); });
- // console.groupEnd();
- return result;
- }
- getContextKeyValue(key) {
- if (this._isDisposed) {
- return undefined;
- }
- return this.getContextValuesContainer(this._myContextId).getValue(key);
- }
- setContext(key, value) {
- if (this._isDisposed) {
- return;
- }
- const myContext = this.getContextValuesContainer(this._myContextId);
- if (!myContext) {
- return;
- }
- if (myContext.setValue(key, value)) {
- this._onDidChangeContext.fire(new SimpleContextKeyChangeEvent(key));
- }
- }
- removeContext(key) {
- if (this._isDisposed) {
- return;
- }
- if (this.getContextValuesContainer(this._myContextId).removeValue(key)) {
- this._onDidChangeContext.fire(new SimpleContextKeyChangeEvent(key));
- }
- }
- getContext(target) {
- if (this._isDisposed) {
- return NullContext.INSTANCE;
- }
- return this.getContextValuesContainer(findContextAttr(target));
- }
- }
- let ContextKeyService = class ContextKeyService extends AbstractContextKeyService {
- constructor(configurationService) {
- super(0);
- this._contexts = new Map();
- this._toDispose = new DisposableStore();
- this._lastContextId = 0;
- const myContext = new ConfigAwareContextValuesContainer(this._myContextId, configurationService, this._onDidChangeContext);
- this._contexts.set(this._myContextId, myContext);
- this._toDispose.add(myContext);
- // Uncomment this to see the contexts continuously logged
- // 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');
- // if (lastLoggedValue !== logValue) {
- // lastLoggedValue = logValue;
- // console.log(lastLoggedValue);
- // }
- // }, 2000);
- }
- dispose() {
- this._onDidChangeContext.dispose();
- this._isDisposed = true;
- this._toDispose.dispose();
- }
- getContextValuesContainer(contextId) {
- if (this._isDisposed) {
- return NullContext.INSTANCE;
- }
- return this._contexts.get(contextId) || NullContext.INSTANCE;
- }
- createChildContext(parentContextId = this._myContextId) {
- if (this._isDisposed) {
- throw new Error(`ContextKeyService has been disposed`);
- }
- let id = (++this._lastContextId);
- this._contexts.set(id, new Context(id, this.getContextValuesContainer(parentContextId)));
- return id;
- }
- disposeContext(contextId) {
- if (!this._isDisposed) {
- this._contexts.delete(contextId);
- }
- }
- };
- ContextKeyService = __decorate([
- __param(0, IConfigurationService)
- ], ContextKeyService);
- export { ContextKeyService };
- class ScopedContextKeyService extends AbstractContextKeyService {
- constructor(parent, domNode) {
- super(parent.createChildContext());
- this._parentChangeListener = new MutableDisposable();
- this._parent = parent;
- this._updateParentChangeListener();
- this._domNode = domNode;
- if (this._domNode.hasAttribute(KEYBINDING_CONTEXT_ATTR)) {
- let extraInfo = '';
- if (this._domNode.classList) {
- extraInfo = Array.from(this._domNode.classList.values()).join(', ');
- }
- console.error(`Element already has context attribute${extraInfo ? ': ' + extraInfo : ''}`);
- }
- this._domNode.setAttribute(KEYBINDING_CONTEXT_ATTR, String(this._myContextId));
- }
- _updateParentChangeListener() {
- // Forward parent events to this listener. Parent will change.
- this._parentChangeListener.value = this._parent.onDidChangeContext(this._onDidChangeContext.fire, this._onDidChangeContext);
- }
- dispose() {
- if (this._isDisposed) {
- return;
- }
- this._onDidChangeContext.dispose();
- this._parent.disposeContext(this._myContextId);
- this._parentChangeListener.dispose();
- this._domNode.removeAttribute(KEYBINDING_CONTEXT_ATTR);
- this._isDisposed = true;
- }
- getContextValuesContainer(contextId) {
- if (this._isDisposed) {
- return NullContext.INSTANCE;
- }
- return this._parent.getContextValuesContainer(contextId);
- }
- createChildContext(parentContextId = this._myContextId) {
- if (this._isDisposed) {
- throw new Error(`ScopedContextKeyService has been disposed`);
- }
- return this._parent.createChildContext(parentContextId);
- }
- disposeContext(contextId) {
- if (this._isDisposed) {
- return;
- }
- this._parent.disposeContext(contextId);
- }
- }
- function findContextAttr(domNode) {
- while (domNode) {
- if (domNode.hasAttribute(KEYBINDING_CONTEXT_ATTR)) {
- const attr = domNode.getAttribute(KEYBINDING_CONTEXT_ATTR);
- if (attr) {
- return parseInt(attr, 10);
- }
- return NaN;
- }
- domNode = domNode.parentElement;
- }
- return 0;
- }
- CommandsRegistry.registerCommand(SET_CONTEXT_COMMAND_ID, function (accessor, contextKey, contextValue) {
- accessor.get(IContextKeyService).createKey(String(contextKey), contextValue);
- });
- CommandsRegistry.registerCommand({
- id: 'getContextKeyInfo',
- handler() {
- return [...RawContextKey.all()].sort((a, b) => a.key.localeCompare(b.key));
- },
- description: {
- description: localize('getContextKeyInfo', "A command that returns information about context keys"),
- args: []
- }
- });
- CommandsRegistry.registerCommand('_generateContextKeyInfo', function () {
- const result = [];
- const seen = new Set();
- for (let info of RawContextKey.all()) {
- if (!seen.has(info.key)) {
- seen.add(info.key);
- result.push(info);
- }
- }
- result.sort((a, b) => a.key.localeCompare(b.key));
- console.log(JSON.stringify(result, undefined, 2));
- });
|