Change:
VSCode Version: 1.12.0 OS Version: MacOS Sierra 10.12.4 In , we'd like to be able to provide context menus for all gradle files. The current clause is limited to language types () or a single file name (). It would be helpful if there was support for glob pattern matching, as mentioned in
Hi, Any update on this?
I will push an additional change that expands this to support normal regular expressions instead of just glob-patterns. We figured that's more powerful and closer to ST
Will this be usable in matching any when clause value? Can you give an example?
You write , so will execute this . A sample from my dummy extensions (matches filenames ending in )
This is AWESOME! Should reduce the number of duplicate menu items I need to define
Slight update on this: The value must be enclosed in slashes, so . I have updated above sample
FYI: I tried to apply this feature to the "loaded script view" by following the entry in the release notes: ! But without much success. After looking into the test item and the corresponding feature item, I noticed that the latest syntax uses regular regexp syntax. I've taken the liberty to change the release notes to this: ! I did not attempt to clarify why actually matches "Docker files".
Hmm, I am writing a simple extension, and would like to copy any resourceName. It works without any when clause, but the menu item also shows up, when r-clicking inside the empty space. I would like to prevent it. Is there something like this ?
Ok I found . And its actually what I was looking for. But I did not found it in the docs, but code base.

Discussion:
import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import Event from 'vs/base/common/event'; <ins> import { match } from 'vs/base/common/glob'; </ins> export enum ContextKeyExprType { Defined = 1, Not = 2, Equals = 3, NotEquals = 4, <del> And = 5 </del> <ins> And = 5, Glob = 6 </ins> } export abstract class ContextKeyExpr {

return new ContextKeyNotEqualsExpr(key, value); } <ins> public static glob(key: string, value: string): ContextKeyExpr { return new ContextKeyGlobExpr(key, value); } </ins> public static not(key: string): ContextKeyExpr { return new ContextKeyNotExpr(key); }

return new ContextKeyEqualsExpr(pieces[0].trim(), this._deserializeValue(pieces[1])); } <ins> if (serializedOne.indexOf('=~') >= 0) { let pieces = serializedOne.split('=~'); return new ContextKeyGlobExpr(pieces[0].trim(), this._deserializeValue(pieces[1])); } </ins> if (/^!s*/.test(serializedOne)) { return new ContextKeyNotExpr(serializedOne.substr(1).trim()); }

return (<ContextKeyEqualsExpr>a).cmp(<ContextKeyEqualsExpr>b); case ContextKeyExprType.NotEquals: return (<ContextKeyNotEqualsExpr>a).cmp(<ContextKeyNotEqualsExpr>b); <ins> case ContextKeyExprType.Glob: return (<ContextKeyGlobExpr>a).cmp(<ContextKeyGlobExpr>b); </ins> default: throw new Error('Unknown ContextKeyExpr!'); }

} } <ins> export class ContextKeyGlobExpr implements ContextKeyExpr { constructor(private key: string, private value: any) { } public getType(): ContextKeyExprType { return ContextKeyExprType.Glob; } public cmp(other: ContextKeyGlobExpr): number { if (this.key < other.key) { return -1; } if (this.key > other.key) { return 1; } if (this.value < other.value) { return -1; } if (this.value > other.value) { return 1; } return 0; } public equals(other: ContextKeyExpr): boolean { if (other instanceof ContextKeyGlobExpr) { return (this.key === other.key && this.value === other.value); } return false; } public evaluate(context: IContext): boolean { return match(this.value, context.getValue(this.key)); } public normalize(): ContextKeyExpr { return this; } public serialize(): string { return this.key + ' =~ '' + this.value + '''; } public keys(): string[] { return [this.key]; } } </ins> export class ContextKeyAndExpr implements ContextKeyExpr { public readonly expr: ContextKeyExpr[];

import * as assert from 'assert'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; <ins> import { match } from 'vs/base/common/glob'; </ins> function createContext(ctx: any) { return {

ContextKeyExpr.has('a1'), ContextKeyExpr.and(ContextKeyExpr.has('and.a')), ContextKeyExpr.has('a2'), <ins> ContextKeyExpr.glob('d3', '**/d*'), ContextKeyExpr.glob('d4', '**/3*'), </ins> ContextKeyExpr.equals('b1', 'bb1'), ContextKeyExpr.equals('b2', 'bb2'), ContextKeyExpr.notEquals('c1', 'cc1'),

ContextKeyExpr.equals('b2', 'bb2'), ContextKeyExpr.notEquals('c1', 'cc1'), ContextKeyExpr.not('d1'), <ins> ContextKeyExpr.glob('d4', '**/3*'), </ins> ContextKeyExpr.notEquals('c2', 'cc2'), ContextKeyExpr.has('a2'), ContextKeyExpr.equals('b1', 'bb1'), <ins> ContextKeyExpr.glob('d3', '**/d*'), </ins> ContextKeyExpr.has('a1'), ContextKeyExpr.and(ContextKeyExpr.equals('and.a', true)), ContextKeyExpr.not('d2')

let context = createContext({ 'a': true, 'b': false, <del> 'c': '5' </del> <ins> 'c': '5', 'd': 'd' </ins> }); function testExpression(expr: string, expected: boolean): void { <ins> console.log(expr + ' ' + expected); </ins> let rules = ContextKeyExpr.deserialize(expr); assert.equal(rules.evaluate(context), expected, expr); }

testExpression(expr + ' == 5', value == <any>'5'); testExpression(expr + ' != 5', value != <any>'5'); testExpression('!' + expr, !value); <ins> testExpression(expr + ' =~ **/d*', match('**/d*', value)); </ins> } testBatch('a', true); testBatch('b', false); testBatch('c', '5'); <ins> testBatch('d', 'd'); </ins> testBatch('z', undefined); testExpression('a && !b', true && !false);