Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upcoming when clause context parser #175540

Open
ulugbekna opened this issue Feb 27, 2023 · 9 comments
Open

Upcoming when clause context parser #175540

ulugbekna opened this issue Feb 27, 2023 · 9 comments
Assignees
Labels
context-keys under-discussion Issue is under discussion for relevance, priority, approach
Milestone

Comments

@ulugbekna
Copy link
Contributor

ulugbekna commented Feb 27, 2023

What's a when clause?

When clauses allow to selectively enable and disable various extension contributions such as commands and UI elements (e.g., menus or views). When clauses are simple expressions that are put in an extension’s manifest (i.e., package.json).

New parser

The next VS Code release is planned to include a new parser of when clauses. The new parser will come with new features, more precise but stricter parsing rules, and a linter to see incorrect when clauses right away in package.json files.

Below we outline new features, breakages, and a way to make sure your extension works as intended. Please, subscribe to this issue to stay up-to-date with other changes that may happen before the next VS Code release 1.77.

New features

  1. Support for parentheses

    (requested in Add support for parenthesis in "when" conditions #91473)

    Note: Negation of expressions such as !(editorTextFocus && debugState == 'running') is still work-in-progress. A comment will be posted to this issue, when it’s ready. Currently, one can only negate a context key, e.g., !editorTextFocus.

    Negation of expressions (e.g., !(editorTextFocus && debugState == 'running')) is also now supported.

  2. Support for more regular expression flags

    Key-value when clause operator =~ currently supports the i flag for case-insensitive regular expression search, but the new parser will support the following flags are supported: i, s, m, u. VS Code will not throw an error if g and y flags are put in the regular expression but will not use them.

  3. Support operators === and !==

    The new parser allows === and !== operators, but they behave the same as == and !=. We noticed that there are already extensions that use these operators, assuming that they are supported, so we designed the new parser to be more flexible and support such operators.

Breakages

We tried our best to keep old parser’s behavior on most when clauses so that existing when clauses work as they did before. There are three cases to keep in mind, however, for a when clause to work as intended:

  1. When used with key-value when clause operator, a regular expression needs to be put between slash characters / just as in JavaScript, e.g., view =~ /[a-z]+/.

    Also important to note that a slash character within a regular expression needs to be escaped with two backslash characters, e.g., "when": "workspacePath =~ /my\\/path\//" . The first backslash is to escape the second backslash in the JSON string within package.json and the second backslash is to escape the slash character.

  2. A string value containing whitespace must be quoted, e.g.,

    "when": "myContextKey == 'two words'"

    Note: only single quotes are currently supported.

  3. Comparison operators need to be separated by whitespace from its operands, i.e.,

    correct: count < 2

    incorrect: count<2

Migration

VS Code Insiders comes with a linter for when clauses when an extension manifest file package.json is open. See no errors are reported for your extension’s package.json.

image

VS Code Insiders will also run the new parser by default to see how extensions work with the new parser -- a comment will be posted when this happens as a notification to check out how your extension works with it.

Latest parsing grammar

In EBNF.

expression ::= or

or ::= and { '||' and }*

and ::= term { '&&' term }*

term ::=
	| '!' (KEY | true | false | parenthesized)
	| primary

primary ::=
	| 'true'
	| 'false'
	| parenthesized
	| KEY '=~' REGEX
	| KEY [ ('==' | '!=' | '<' | '<=' | '>' | '>=' | 'not' 'in' | 'in') value ]

parenthesized ::=
	| '(' expression ')'

value ::=
	| 'true'
	| 'false'
	| 'in'      	
	| VALUE 
	| SINGLE_QUOTED_STR
	| EMPTY_STR  	

Please, let me know if you have any feedback! :-)

@bwateratmsft
Copy link
Contributor

Will "when": "never" still continue to work equivalently to "when": "false"?

@Eskibear
Copy link
Member

Eskibear commented Mar 6, 2023

AFAIU, "never" is not a keyword or a pre-defined constant. Currently it's equivalent because context key "never" is undefined. Technically I can run vscode.commands.executeCommand("setContext", "never", true) in any extension to break the assumption.

@ulugbekna
Copy link
Contributor Author

Hi @bwateratmsft,

@Eskibear is right, never is interpreted just as a context key. So unless anyone sets a value to it, it evaluates to false :-)

@ulugbekna
Copy link
Contributor Author

ulugbekna commented Mar 6, 2023

Hello everyone,

  • The latest VS Code Insiders runs with the new parser as the default one to parse context key expressions, so you should be able to test your extensions.

  • The latest Insiders also includes negation of arbitrary expressions, which means that you can now negate parenthesized expressions, e.g., "when": "foo && !(bar || baz)".

I also updated the EBNF grammar in this issue's description above.

Please, let me know if you have any feedback! :-)

@starball5
Copy link

starball5 commented Mar 8, 2023

In preparation for any future breakages related to extensions or user-local keybindings, I have created a Q&A on Stack Overflow, which you can (where appropriate) use as a duplicate-target. A fair number of people often go to Stack Overflow with problems like this. Feel free also to suggest edits to the question and answer posts to improve them.

Here it is: Why are some of my extensions or keybindings' when clauses broken in VS Code 1.77's official and insiders releases?

@ulugbekna
Copy link
Contributor Author

ulugbekna commented Apr 3, 2023

The new parser now runs by default in VS Code 1.77 (stable).

Thanks everyone!

I will keep this issue around in case there are any future changes to the parser.

@ian-h-chamberlain
Copy link

VS Code Insiders comes with a linter for when clauses when an extension manifest file package.json is open. See no errors are reported for your extension’s package.json.

Is there any plan to port this to the user settings keybindings.json? When setting up some new keybindings I accidentally left a when clause with a trailing && in it, and it seems to just evaluate to true, without any indication of an error that I could see. I'm running stable VSCode 1.80.1 so I assume it should be using this new parser, correct?

Should I file a separate issue for that, or is this issue the right place to report that?

@ulugbekna
Copy link
Contributor Author

@ian-h-chamberlain made a request #188427. Thanks for the heads up 😊

@jimasp
Copy link

jimasp commented Nov 18, 2023

One thing I really feel is missing is the ability to inject a regex context string, e.g.

extension.js

const myRegexWildcardPaths = myFolderPrefixList.map(f => `${f}.*`).join("|");
vscode.commands.executeCommand('setContext', 'extensionContext.myRegexWildcardPaths', myRegexWildcardPaths);

package.json:

"when": "resourcePath =~ /extensionContext.myRegexWildcardPaths/ && !isInEmbeddedEditor && editorTextFocus"

@ulugbekna ulugbekna added the under-discussion Issue is under discussion for relevance, priority, approach label Dec 5, 2023
@ulugbekna ulugbekna added this to the Backlog milestone Dec 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
context-keys under-discussion Issue is under discussion for relevance, priority, approach
Projects
None yet
Development

No branches or pull requests

7 participants
@jimasp @Eskibear @ian-h-chamberlain @ulugbekna @bwateratmsft @starball5 and others