Context & when expressions
Every rule can carry a when expression — a boolean gate evaluated against a context-key store.
The same keystroke can do different things in different contexts, without ad-hoc flags.
kb.context.set('scope', 'editor');kb.context.set('readOnly', false);
kb.add({ id: 'editor.bold', keys: 'mod+b', when: "scope == 'editor' && !readOnly", handler: toggleBold,});When you press ⌘B, the engine evaluates when against the current context and only fires if it’s
true.
The expression language
Section titled “The expression language”Modeled on VS Code’s when clauses:
| Feature | Example |
|---|---|
| Truthiness | editorFocus |
| Equality | scope == 'editor', mode != 'insert' |
| Boolean | a && b, a || b, !a |
| Grouping | a && (b || c) |
| Membership | lang in 'ts js tsx' |
Identifiers may contain dots (editor.langId) to match how hosts namespace context keys.
Scopes are just context keys
Section titled “Scopes are just context keys”There’s no separate “scope” concept to learn. A named scope is a context key:
kb.context.set('scope', 'editor'); // when: "scope == 'editor'"kb.context.set('scope.terminal', true); // when: "scope.terminal"In React, useScope gives you setScope, enableScope, and friends as a thin
convenience over exactly this.
Examples
Section titled “Examples”Editor + read-only
Section titled “Editor + read-only”kb.context.set('scope', 'editor');kb.context.set('readOnly', false);
kb.add({ id: 'bold', keys: 'mod+b', when: "scope == 'editor' && !readOnly", handler: bold });kb.add({ id: 'save', keys: 'mod+s', when: "scope == 'editor' && !readOnly", handler: save });Modal blocks background shortcuts
Section titled “Modal blocks background shortcuts”kb.context.set('modalOpen', true);
kb.add({ id: 'palette', keys: 'mod+k', when: '!modalOpen', handler: palette });kb.add({ id: 'modal.close', keys: 'escape', when: 'modalOpen', handler: closeModal });Language-specific binding
Section titled “Language-specific binding”kb.context.set('editor.langId', 'typescript');
kb.add({ id: 'rename', keys: 'f2', when: "editor.langId == 'typescript'", handler: rename,});Membership test
Section titled “Membership test”kb.context.set('mode', 'insert');
kb.add({ id: 'normal-mode', keys: 'escape', when: "mode in 'insert replace'", handler: () => kb.context.set('mode', 'normal'),});Next steps
Section titled “Next steps”- useScope — the React convenience layer over context keys
- Collision detection — what happens when two gated rules overlap
- Recipes — palettes and modals built on when-gating