awa
This commit is contained in:
@@ -0,0 +1,467 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { Event, PauseableEmitter } from '../../../base/common/event.js';
|
||||
import { Iterable } from '../../../base/common/iterator.js';
|
||||
import { Disposable, DisposableStore, MutableDisposable } from '../../../base/common/lifecycle.js';
|
||||
import { cloneAndChange } from '../../../base/common/objects.js';
|
||||
import { TernarySearchTree } from '../../../base/common/ternarySearchTree.js';
|
||||
import { URI } from '../../../base/common/uri.js';
|
||||
import { localize } from '../../../nls.js';
|
||||
import { CommandsRegistry } from '../../commands/common/commands.js';
|
||||
import { IConfigurationService } from '../../configuration/common/configuration.js';
|
||||
import { IContextKeyService, RawContextKey } from '../common/contextkey.js';
|
||||
import { InputFocusedContext } from '../common/contextkeys.js';
|
||||
import { mainWindow } from '../../../base/browser/window.js';
|
||||
import { addDisposableListener, EventType, getActiveWindow, isEditableElement, onDidRegisterWindow, trackFocus } from '../../../base/browser/dom.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;
|
||||
}
|
||||
get value() {
|
||||
return { ...this._value };
|
||||
}
|
||||
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 {
|
||||
static { this.INSTANCE = new NullContext(); }
|
||||
constructor() {
|
||||
super(-1, null);
|
||||
}
|
||||
setValue(key, value) {
|
||||
return false;
|
||||
}
|
||||
removeValue(key) {
|
||||
return false;
|
||||
}
|
||||
getValue(key) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
class ConfigAwareContextValuesContainer extends Context {
|
||||
static { this._keyPrefix = 'config.'; }
|
||||
constructor(id, _configurationService, emitter) {
|
||||
super(id, null);
|
||||
this._configurationService = _configurationService;
|
||||
this._values = TernarySearchTree.forConfigKeys();
|
||||
this._listener = this._configurationService.onDidChangeConfiguration(event => {
|
||||
if (event.source === 7 /* ConfigurationTarget.DEFAULT */) {
|
||||
// new setting, reset everything
|
||||
const allKeys = Array.from(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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
allKeysContainedIn(keys) {
|
||||
return this.affectsSome(keys);
|
||||
}
|
||||
}
|
||||
class ArrayContextKeyChangeEvent {
|
||||
constructor(keys) {
|
||||
this.keys = keys;
|
||||
}
|
||||
affectsSome(keys) {
|
||||
for (const key of this.keys) {
|
||||
if (keys.has(key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
allKeysContainedIn(keys) {
|
||||
return this.keys.every(key => keys.has(key));
|
||||
}
|
||||
}
|
||||
class CompositeContextKeyChangeEvent {
|
||||
constructor(events) {
|
||||
this.events = events;
|
||||
}
|
||||
affectsSome(keys) {
|
||||
for (const e of this.events) {
|
||||
if (e.affectsSome(keys)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
allKeysContainedIn(keys) {
|
||||
return this.events.every(evt => evt.allKeysContainedIn(keys));
|
||||
}
|
||||
}
|
||||
function allEventKeysInContext(event, context) {
|
||||
return event.allKeysContainedIn(new Set(Object.keys(context)));
|
||||
}
|
||||
export class AbstractContextKeyService extends Disposable {
|
||||
get onDidChangeContext() { return this._onDidChangeContext.event; }
|
||||
constructor(myContextId) {
|
||||
super();
|
||||
this._onDidChangeContext = this._register(new PauseableEmitter({ merge: input => new CompositeContextKeyChangeEvent(input) }));
|
||||
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 = (rules ? rules.evaluate(context) : true);
|
||||
// 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));
|
||||
}
|
||||
dispose() {
|
||||
super.dispose();
|
||||
this._isDisposed = true;
|
||||
}
|
||||
}
|
||||
let ContextKeyService = class ContextKeyService extends AbstractContextKeyService {
|
||||
constructor(configurationService) {
|
||||
super(0);
|
||||
this._contexts = new Map();
|
||||
this._lastContextId = 0;
|
||||
this.inputFocusedContext = InputFocusedContext.bindTo(this);
|
||||
const myContext = this._register(new ConfigAwareContextValuesContainer(this._myContextId, configurationService, this._onDidChangeContext));
|
||||
this._contexts.set(this._myContextId, 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);
|
||||
this._register(Event.runAndSubscribe(onDidRegisterWindow, ({ window, disposables }) => {
|
||||
const onFocusDisposables = disposables.add(new MutableDisposable());
|
||||
disposables.add(addDisposableListener(window, EventType.FOCUS_IN, () => {
|
||||
onFocusDisposables.value = new DisposableStore();
|
||||
this.updateInputContextKeys(window.document, onFocusDisposables.value);
|
||||
}, true));
|
||||
}, { window: mainWindow, disposables: this._store }));
|
||||
}
|
||||
updateInputContextKeys(ownerDocument, disposables) {
|
||||
function activeElementIsInput() {
|
||||
return !!ownerDocument.activeElement && isEditableElement(ownerDocument.activeElement);
|
||||
}
|
||||
const isInputFocused = activeElementIsInput();
|
||||
this.inputFocusedContext.set(isInputFocused);
|
||||
if (isInputFocused) {
|
||||
const tracker = disposables.add(trackFocus(ownerDocument.activeElement));
|
||||
Event.once(tracker.onDidBlur)(() => {
|
||||
// Ensure we are only updating the context key if we are
|
||||
// still in the same document that we are tracking. This
|
||||
// fixes a race condition in multi-window setups where
|
||||
// the blur event arrives in the inactive window overwriting
|
||||
// the context key of the active window. This is because
|
||||
// blur events from the focus tracker are emitted with a
|
||||
// timeout of 0.
|
||||
if (getActiveWindow().document === ownerDocument) {
|
||||
this.inputFocusedContext.set(activeElementIsInput());
|
||||
}
|
||||
tracker.dispose();
|
||||
}, undefined, disposables);
|
||||
}
|
||||
}
|
||||
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`);
|
||||
}
|
||||
const 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 = this._register(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(e => {
|
||||
const thisContainer = this._parent.getContextValuesContainer(this._myContextId);
|
||||
const thisContextValues = thisContainer.value;
|
||||
if (!allEventKeysInContext(e, thisContextValues)) {
|
||||
this._onDidChangeContext.fire(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
dispose() {
|
||||
if (this._isDisposed) {
|
||||
return;
|
||||
}
|
||||
this._parent.disposeContext(this._myContextId);
|
||||
this._domNode.removeAttribute(KEYBINDING_CONTEXT_ATTR);
|
||||
super.dispose();
|
||||
}
|
||||
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;
|
||||
}
|
||||
export function setContext(accessor, contextKey, contextValue) {
|
||||
const contextKeyService = accessor.get(IContextKeyService);
|
||||
contextKeyService.createKey(String(contextKey), stringifyURIs(contextValue));
|
||||
}
|
||||
function stringifyURIs(contextValue) {
|
||||
return cloneAndChange(contextValue, (obj) => {
|
||||
if (typeof obj === 'object' && obj.$mid === 1 /* MarshalledId.Uri */) {
|
||||
return URI.revive(obj).toString();
|
||||
}
|
||||
if (obj instanceof URI) {
|
||||
return obj.toString();
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
CommandsRegistry.registerCommand('_setContext', setContext);
|
||||
CommandsRegistry.registerCommand({
|
||||
id: 'getContextKeyInfo',
|
||||
handler() {
|
||||
return [...RawContextKey.all()].sort((a, b) => a.key.localeCompare(b.key));
|
||||
},
|
||||
metadata: {
|
||||
description: localize(1659, "A command that returns information about context keys"),
|
||||
args: []
|
||||
}
|
||||
});
|
||||
CommandsRegistry.registerCommand('_generateContextKeyInfo', function () {
|
||||
const result = [];
|
||||
const seen = new Set();
|
||||
for (const 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));
|
||||
});
|
||||
//# sourceMappingURL=contextKeyService.js.map
|
||||
File diff suppressed because one or more lines are too long
1548
_internal/editor/esm/vs/platform/contextkey/common/contextkey.js
Normal file
1548
_internal/editor/esm/vs/platform/contextkey/common/contextkey.js
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,19 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { isIOS, isLinux, isMacintosh, isMobile, isWeb, isWindows } from '../../../base/common/platform.js';
|
||||
import { localize } from '../../../nls.js';
|
||||
import { RawContextKey } from './contextkey.js';
|
||||
export const IsMacContext = new RawContextKey('isMac', isMacintosh, localize(1669, "Whether the operating system is macOS"));
|
||||
export const IsLinuxContext = new RawContextKey('isLinux', isLinux, localize(1670, "Whether the operating system is Linux"));
|
||||
export const IsWindowsContext = new RawContextKey('isWindows', isWindows, localize(1671, "Whether the operating system is Windows"));
|
||||
export const IsWebContext = new RawContextKey('isWeb', isWeb, localize(1672, "Whether the platform is a web browser"));
|
||||
export const IsMacNativeContext = new RawContextKey('isMacNative', isMacintosh && !isWeb, localize(1673, "Whether the operating system is macOS on a non-browser platform"));
|
||||
export const IsIOSContext = new RawContextKey('isIOS', isIOS, localize(1674, "Whether the operating system is iOS"));
|
||||
export const IsMobileContext = new RawContextKey('isMobile', isMobile, localize(1675, "Whether the platform is a mobile web browser"));
|
||||
export const IsDevelopmentContext = new RawContextKey('isDevelopment', false, true);
|
||||
export const ProductQualityContext = new RawContextKey('productQualityType', '', localize(1676, "Quality type of VS Code"));
|
||||
export const InputFocusedContextKey = 'inputFocus';
|
||||
export const InputFocusedContext = new RawContextKey(InputFocusedContextKey, false, localize(1677, "Whether keyboard focus is inside an input box"));
|
||||
//# sourceMappingURL=contextkeys.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["vs/platform/contextkey/common/contextkeys.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAEhG,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAC3G,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,aAAa,CAAU,OAAO,EAAE,WAAW,EAAE,QAAQ,CAAC,IAAO,EAAE,uCAAuC,CAAC,CAAC,CAAC;AACzI,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,aAAa,CAAU,SAAS,EAAE,OAAO,EAAE,QAAQ,CAAC,IAAS,EAAE,uCAAuC,CAAC,CAAC,CAAC;AAC3I,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,aAAa,CAAU,WAAW,EAAE,SAAS,EAAE,QAAQ,CAAC,IAAW,EAAE,yCAAyC,CAAC,CAAC,CAAC;AAErJ,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,aAAa,CAAU,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,IAAO,EAAE,uCAAuC,CAAC,CAAC,CAAC;AACnI,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,aAAa,CAAU,aAAa,EAAE,WAAW,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAa,EAAE,iEAAiE,CAAC,CAAC,CAAC;AAC/L,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,aAAa,CAAU,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,IAAO,EAAE,qCAAqC,CAAC,CAAC,CAAC;AACjI,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,aAAa,CAAU,UAAU,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAU,EAAE,8CAA8C,CAAC,CAAC,CAAC;AAEtJ,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,aAAa,CAAU,eAAe,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;AAC7F,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,aAAa,CAAS,oBAAoB,EAAE,EAAE,EAAE,QAAQ,CAAC,IAAoB,EAAE,yBAAyB,CAAC,CAAC,CAAC;AAEpJ,MAAM,CAAC,MAAM,sBAAsB,GAAG,YAAY,CAAC;AACnD,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,aAAa,CAAU,sBAAsB,EAAE,KAAK,EAAE,QAAQ,CAAC,IAAY,EAAE,+CAA+C,CAAC,CAAC,CAAC","file":"contextkeys.js","sourceRoot":"file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { isIOS, isLinux, isMacintosh, isMobile, isWeb, isWindows } from '../../../base/common/platform.js';\nimport { localize } from '../../../nls.js';\nimport { RawContextKey } from './contextkey.js';\n\nexport const IsMacContext = new RawContextKey<boolean>('isMac', isMacintosh, localize('isMac', \"Whether the operating system is macOS\"));\nexport const IsLinuxContext = new RawContextKey<boolean>('isLinux', isLinux, localize('isLinux', \"Whether the operating system is Linux\"));\nexport const IsWindowsContext = new RawContextKey<boolean>('isWindows', isWindows, localize('isWindows', \"Whether the operating system is Windows\"));\n\nexport const IsWebContext = new RawContextKey<boolean>('isWeb', isWeb, localize('isWeb', \"Whether the platform is a web browser\"));\nexport const IsMacNativeContext = new RawContextKey<boolean>('isMacNative', isMacintosh && !isWeb, localize('isMacNative', \"Whether the operating system is macOS on a non-browser platform\"));\nexport const IsIOSContext = new RawContextKey<boolean>('isIOS', isIOS, localize('isIOS', \"Whether the operating system is iOS\"));\nexport const IsMobileContext = new RawContextKey<boolean>('isMobile', isMobile, localize('isMobile', \"Whether the platform is a mobile web browser\"));\n\nexport const IsDevelopmentContext = new RawContextKey<boolean>('isDevelopment', false, true);\nexport const ProductQualityContext = new RawContextKey<string>('productQualityType', '', localize('productQualityType', \"Quality type of VS Code\"));\n\nexport const InputFocusedContextKey = 'inputFocus';\nexport const InputFocusedContext = new RawContextKey<boolean>(InputFocusedContextKey, false, localize('inputFocus', \"Whether keyboard focus is inside an input box\"));\n"]}
|
||||
285
_internal/editor/esm/vs/platform/contextkey/common/scanner.js
Normal file
285
_internal/editor/esm/vs/platform/contextkey/common/scanner.js
Normal file
@@ -0,0 +1,285 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { illegalState } from '../../../base/common/errors.js';
|
||||
import { localize } from '../../../nls.js';
|
||||
function hintDidYouMean(...meant) {
|
||||
switch (meant.length) {
|
||||
case 1:
|
||||
return localize(1678, "Did you mean {0}?", meant[0]);
|
||||
case 2:
|
||||
return localize(1679, "Did you mean {0} or {1}?", meant[0], meant[1]);
|
||||
case 3:
|
||||
return localize(1680, "Did you mean {0}, {1} or {2}?", meant[0], meant[1], meant[2]);
|
||||
default: // we just don't expect that many
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
const hintDidYouForgetToOpenOrCloseQuote = localize(1681, "Did you forget to open or close the quote?");
|
||||
const hintDidYouForgetToEscapeSlash = localize(1682, "Did you forget to escape the '/' (slash) character? Put two backslashes before it to escape, e.g., '\\\\/\'.");
|
||||
/**
|
||||
* A simple scanner for context keys.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```ts
|
||||
* const scanner = new Scanner().reset('resourceFileName =~ /docker/ && !config.docker.enabled');
|
||||
* const tokens = [...scanner];
|
||||
* if (scanner.errorTokens.length > 0) {
|
||||
* scanner.errorTokens.forEach(err => console.error(`Unexpected token at ${err.offset}: ${err.lexeme}\nHint: ${err.additional}`));
|
||||
* } else {
|
||||
* // process tokens
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export class Scanner {
|
||||
constructor() {
|
||||
this._input = '';
|
||||
this._start = 0;
|
||||
this._current = 0;
|
||||
this._tokens = [];
|
||||
this._errors = [];
|
||||
// u - unicode, y - sticky // TODO@ulugbekna: we accept double quotes as part of the string rather than as a delimiter (to preserve old parser's behavior)
|
||||
this.stringRe = /[a-zA-Z0-9_<>\-\./\\:\*\?\+\[\]\^,#@;"%\$\p{L}-]+/uy;
|
||||
}
|
||||
static getLexeme(token) {
|
||||
switch (token.type) {
|
||||
case 0 /* TokenType.LParen */:
|
||||
return '(';
|
||||
case 1 /* TokenType.RParen */:
|
||||
return ')';
|
||||
case 2 /* TokenType.Neg */:
|
||||
return '!';
|
||||
case 3 /* TokenType.Eq */:
|
||||
return token.isTripleEq ? '===' : '==';
|
||||
case 4 /* TokenType.NotEq */:
|
||||
return token.isTripleEq ? '!==' : '!=';
|
||||
case 5 /* TokenType.Lt */:
|
||||
return '<';
|
||||
case 6 /* TokenType.LtEq */:
|
||||
return '<=';
|
||||
case 7 /* TokenType.Gt */:
|
||||
return '>=';
|
||||
case 8 /* TokenType.GtEq */:
|
||||
return '>=';
|
||||
case 9 /* TokenType.RegexOp */:
|
||||
return '=~';
|
||||
case 10 /* TokenType.RegexStr */:
|
||||
return token.lexeme;
|
||||
case 11 /* TokenType.True */:
|
||||
return 'true';
|
||||
case 12 /* TokenType.False */:
|
||||
return 'false';
|
||||
case 13 /* TokenType.In */:
|
||||
return 'in';
|
||||
case 14 /* TokenType.Not */:
|
||||
return 'not';
|
||||
case 15 /* TokenType.And */:
|
||||
return '&&';
|
||||
case 16 /* TokenType.Or */:
|
||||
return '||';
|
||||
case 17 /* TokenType.Str */:
|
||||
return token.lexeme;
|
||||
case 18 /* TokenType.QuotedStr */:
|
||||
return token.lexeme;
|
||||
case 19 /* TokenType.Error */:
|
||||
return token.lexeme;
|
||||
case 20 /* TokenType.EOF */:
|
||||
return 'EOF';
|
||||
default:
|
||||
throw illegalState(`unhandled token type: ${JSON.stringify(token)}; have you forgotten to add a case?`);
|
||||
}
|
||||
}
|
||||
static { this._regexFlags = new Set(['i', 'g', 's', 'm', 'y', 'u'].map(ch => ch.charCodeAt(0))); }
|
||||
static { this._keywords = new Map([
|
||||
['not', 14 /* TokenType.Not */],
|
||||
['in', 13 /* TokenType.In */],
|
||||
['false', 12 /* TokenType.False */],
|
||||
['true', 11 /* TokenType.True */],
|
||||
]); }
|
||||
reset(value) {
|
||||
this._input = value;
|
||||
this._start = 0;
|
||||
this._current = 0;
|
||||
this._tokens = [];
|
||||
this._errors = [];
|
||||
return this;
|
||||
}
|
||||
scan() {
|
||||
while (!this._isAtEnd()) {
|
||||
this._start = this._current;
|
||||
const ch = this._advance();
|
||||
switch (ch) {
|
||||
case 40 /* CharCode.OpenParen */:
|
||||
this._addToken(0 /* TokenType.LParen */);
|
||||
break;
|
||||
case 41 /* CharCode.CloseParen */:
|
||||
this._addToken(1 /* TokenType.RParen */);
|
||||
break;
|
||||
case 33 /* CharCode.ExclamationMark */:
|
||||
if (this._match(61 /* CharCode.Equals */)) {
|
||||
const isTripleEq = this._match(61 /* CharCode.Equals */); // eat last `=` if `!==`
|
||||
this._tokens.push({ type: 4 /* TokenType.NotEq */, offset: this._start, isTripleEq });
|
||||
}
|
||||
else {
|
||||
this._addToken(2 /* TokenType.Neg */);
|
||||
}
|
||||
break;
|
||||
case 39 /* CharCode.SingleQuote */:
|
||||
this._quotedString();
|
||||
break;
|
||||
case 47 /* CharCode.Slash */:
|
||||
this._regex();
|
||||
break;
|
||||
case 61 /* CharCode.Equals */:
|
||||
if (this._match(61 /* CharCode.Equals */)) { // support `==`
|
||||
const isTripleEq = this._match(61 /* CharCode.Equals */); // eat last `=` if `===`
|
||||
this._tokens.push({ type: 3 /* TokenType.Eq */, offset: this._start, isTripleEq });
|
||||
}
|
||||
else if (this._match(126 /* CharCode.Tilde */)) {
|
||||
this._addToken(9 /* TokenType.RegexOp */);
|
||||
}
|
||||
else {
|
||||
this._error(hintDidYouMean('==', '=~'));
|
||||
}
|
||||
break;
|
||||
case 60 /* CharCode.LessThan */:
|
||||
this._addToken(this._match(61 /* CharCode.Equals */) ? 6 /* TokenType.LtEq */ : 5 /* TokenType.Lt */);
|
||||
break;
|
||||
case 62 /* CharCode.GreaterThan */:
|
||||
this._addToken(this._match(61 /* CharCode.Equals */) ? 8 /* TokenType.GtEq */ : 7 /* TokenType.Gt */);
|
||||
break;
|
||||
case 38 /* CharCode.Ampersand */:
|
||||
if (this._match(38 /* CharCode.Ampersand */)) {
|
||||
this._addToken(15 /* TokenType.And */);
|
||||
}
|
||||
else {
|
||||
this._error(hintDidYouMean('&&'));
|
||||
}
|
||||
break;
|
||||
case 124 /* CharCode.Pipe */:
|
||||
if (this._match(124 /* CharCode.Pipe */)) {
|
||||
this._addToken(16 /* TokenType.Or */);
|
||||
}
|
||||
else {
|
||||
this._error(hintDidYouMean('||'));
|
||||
}
|
||||
break;
|
||||
// TODO@ulugbekna: 1) rewrite using a regex 2) reconsider what characters are considered whitespace, including unicode, nbsp, etc.
|
||||
case 32 /* CharCode.Space */:
|
||||
case 13 /* CharCode.CarriageReturn */:
|
||||
case 9 /* CharCode.Tab */:
|
||||
case 10 /* CharCode.LineFeed */:
|
||||
case 160 /* CharCode.NoBreakSpace */: //  
|
||||
break;
|
||||
default:
|
||||
this._string();
|
||||
}
|
||||
}
|
||||
this._start = this._current;
|
||||
this._addToken(20 /* TokenType.EOF */);
|
||||
return Array.from(this._tokens);
|
||||
}
|
||||
_match(expected) {
|
||||
if (this._isAtEnd()) {
|
||||
return false;
|
||||
}
|
||||
if (this._input.charCodeAt(this._current) !== expected) {
|
||||
return false;
|
||||
}
|
||||
this._current++;
|
||||
return true;
|
||||
}
|
||||
_advance() {
|
||||
return this._input.charCodeAt(this._current++);
|
||||
}
|
||||
_peek() {
|
||||
return this._isAtEnd() ? 0 /* CharCode.Null */ : this._input.charCodeAt(this._current);
|
||||
}
|
||||
_addToken(type) {
|
||||
this._tokens.push({ type, offset: this._start });
|
||||
}
|
||||
_error(additional) {
|
||||
const offset = this._start;
|
||||
const lexeme = this._input.substring(this._start, this._current);
|
||||
const errToken = { type: 19 /* TokenType.Error */, offset: this._start, lexeme };
|
||||
this._errors.push({ offset, lexeme, additionalInfo: additional });
|
||||
this._tokens.push(errToken);
|
||||
}
|
||||
_string() {
|
||||
this.stringRe.lastIndex = this._start;
|
||||
const match = this.stringRe.exec(this._input);
|
||||
if (match) {
|
||||
this._current = this._start + match[0].length;
|
||||
const lexeme = this._input.substring(this._start, this._current);
|
||||
const keyword = Scanner._keywords.get(lexeme);
|
||||
if (keyword) {
|
||||
this._addToken(keyword);
|
||||
}
|
||||
else {
|
||||
this._tokens.push({ type: 17 /* TokenType.Str */, lexeme, offset: this._start });
|
||||
}
|
||||
}
|
||||
}
|
||||
// captures the lexeme without the leading and trailing '
|
||||
_quotedString() {
|
||||
while (this._peek() !== 39 /* CharCode.SingleQuote */ && !this._isAtEnd()) { // TODO@ulugbekna: add support for escaping ' ?
|
||||
this._advance();
|
||||
}
|
||||
if (this._isAtEnd()) {
|
||||
this._error(hintDidYouForgetToOpenOrCloseQuote);
|
||||
return;
|
||||
}
|
||||
// consume the closing '
|
||||
this._advance();
|
||||
this._tokens.push({ type: 18 /* TokenType.QuotedStr */, lexeme: this._input.substring(this._start + 1, this._current - 1), offset: this._start + 1 });
|
||||
}
|
||||
/*
|
||||
* Lexing a regex expression: /.../[igsmyu]*
|
||||
* Based on https://github.com/microsoft/TypeScript/blob/9247ef115e617805983740ba795d7a8164babf89/src/compiler/scanner.ts#L2129-L2181
|
||||
*
|
||||
* Note that we want slashes within a regex to be escaped, e.g., /file:\\/\\/\\// should match `file:///`
|
||||
*/
|
||||
_regex() {
|
||||
let p = this._current;
|
||||
let inEscape = false;
|
||||
let inCharacterClass = false;
|
||||
while (true) {
|
||||
if (p >= this._input.length) {
|
||||
this._current = p;
|
||||
this._error(hintDidYouForgetToEscapeSlash);
|
||||
return;
|
||||
}
|
||||
const ch = this._input.charCodeAt(p);
|
||||
if (inEscape) { // parsing an escape character
|
||||
inEscape = false;
|
||||
}
|
||||
else if (ch === 47 /* CharCode.Slash */ && !inCharacterClass) { // end of regex
|
||||
p++;
|
||||
break;
|
||||
}
|
||||
else if (ch === 91 /* CharCode.OpenSquareBracket */) {
|
||||
inCharacterClass = true;
|
||||
}
|
||||
else if (ch === 92 /* CharCode.Backslash */) {
|
||||
inEscape = true;
|
||||
}
|
||||
else if (ch === 93 /* CharCode.CloseSquareBracket */) {
|
||||
inCharacterClass = false;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
// Consume flags // TODO@ulugbekna: use regex instead
|
||||
while (p < this._input.length && Scanner._regexFlags.has(this._input.charCodeAt(p))) {
|
||||
p++;
|
||||
}
|
||||
this._current = p;
|
||||
const lexeme = this._input.substring(this._start, this._current);
|
||||
this._tokens.push({ type: 10 /* TokenType.RegexStr */, lexeme, offset: this._start });
|
||||
}
|
||||
_isAtEnd() {
|
||||
return this._current >= this._input.length;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=scanner.js.map
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user