Skip to content
This repository was archived by the owner on Nov 6, 2018. It is now read-only.

Commit ade1094

Browse files
committed
feat: support scoped component when computing contributions
This allows multiple contribution points, such as multiple editor/title menus when multiple editors are shown on the screen at once. Each contribution point will be scoped to the document it is actually showing, which lets contributions use those scoped values when determining visibility, labels, etc.
1 parent 514b048 commit ade1094

File tree

3 files changed

+50
-33
lines changed

3 files changed

+50
-33
lines changed

src/environment/context/context.ts

+14-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { basename, dirname, extname } from 'path'
2-
import { Environment } from '../environment'
2+
import { Component, Environment } from '../environment'
33

44
/**
55
* Returns a new context created by applying the update context to the base context. It is equivalent to `{...base,
@@ -29,11 +29,12 @@ export const EMPTY_CONTEXT: Context = {}
2929

3030
/**
3131
* Looks up a key in the computed context, which consists of special context properties (with higher precedence)
32-
* and the environment's context properties (with lower precedence). environment.
32+
* and the environment's context properties (with lower precedence).
3333
*
3434
* @param key the context property key to look up
35+
* @param scope the user interface component in whose scope this computation should occur
3536
*/
36-
export function getComputedContextProperty(environment: Environment, key: string): any {
37+
export function getComputedContextProperty(environment: Environment, key: string, scope?: Component): any {
3738
if (key.startsWith('config.')) {
3839
const prop = key.slice('config.'.length)
3940
const value = environment.configuration.merged[prop]
@@ -42,11 +43,12 @@ export function getComputedContextProperty(environment: Environment, key: string
4243
// which a falsey null default is useful).
4344
return value === undefined ? null : value
4445
}
46+
const component = scope || environment.component
4547
if (key === 'resource' || key === 'component') {
46-
return !!environment.component
48+
return !!component
4749
}
4850
if (key.startsWith('resource.')) {
49-
if (!environment.component) {
51+
if (!component) {
5052
return undefined
5153
}
5254
// TODO(sqs): Define these precisely. If the resource is in a repository, what is the "path"? Is it the
@@ -55,23 +57,23 @@ export function getComputedContextProperty(environment: Environment, key: string
5557
const prop = key.slice('resource.'.length)
5658
switch (prop) {
5759
case 'uri':
58-
return environment.component.document.uri
60+
return component.document.uri
5961
case 'basename':
60-
return basename(environment.component.document.uri)
62+
return basename(component.document.uri)
6163
case 'dirname':
62-
return dirname(environment.component.document.uri)
64+
return dirname(component.document.uri)
6365
case 'extname':
64-
return extname(environment.component.document.uri)
66+
return extname(component.document.uri)
6567
case 'language':
66-
return environment.component.document.languageId
68+
return component.document.languageId
6769
case 'textContent':
68-
return environment.component.document.text
70+
return component.document.text
6971
case 'type':
7072
return 'textDocument'
7173
}
7274
}
7375
if (key.startsWith('component.')) {
74-
if (!environment.component) {
76+
if (!component) {
7577
return undefined
7678
}
7779
const prop = key.slice('component.'.length)

src/environment/providers/contribution.test.ts

+20-12
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,15 @@ describe('ContributionRegistry', () => {
9898
describe('contributions observable', () => {
9999
it('emits stream of results of registrations', () => {
100100
const registry = new class extends ContributionRegistry {
101-
public getContributions(entries: Observable<ContributionsEntry[]>): Observable<Contributions> {
102-
return super.getContributions(entries)
101+
public getContributionsFromEntries(
102+
entries: Observable<ContributionsEntry[]>
103+
): Observable<Contributions> {
104+
return super.getContributionsFromEntries(entries)
103105
}
104106
}(EMPTY_OBSERVABLE_ENVIRONMENT.environment)
105107
scheduler().run(({ cold, expectObservable }) =>
106108
expectObservable(
107-
registry.getContributions(
109+
registry.getContributionsFromEntries(
108110
cold<ContributionsEntry[]>('-a-b-c-|', {
109111
a: [{ contributions: FIXTURE_CONTRIBUTIONS_1 }],
110112
b: [{ contributions: FIXTURE_CONTRIBUTIONS_1 }, { contributions: {} }],
@@ -120,13 +122,15 @@ describe('ContributionRegistry', () => {
120122

121123
it('supports registration of an observable', () => {
122124
const registry = new class extends ContributionRegistry {
123-
public getContributions(entries: Observable<ContributionsEntry[]>): Observable<Contributions> {
124-
return super.getContributions(entries)
125+
public getContributionsFromEntries(
126+
entries: Observable<ContributionsEntry[]>
127+
): Observable<Contributions> {
128+
return super.getContributionsFromEntries(entries)
125129
}
126130
}(EMPTY_OBSERVABLE_ENVIRONMENT.environment)
127131
scheduler().run(({ cold, expectObservable }) =>
128132
expectObservable(
129-
registry.getContributions(
133+
registry.getContributionsFromEntries(
130134
cold<ContributionsEntry[]>('-a-----|', {
131135
a: [
132136
{
@@ -157,12 +161,14 @@ describe('ContributionRegistry', () => {
157161
)
158162
}
159163

160-
public getContributions(entries: Observable<ContributionsEntry[]>): Observable<Contributions> {
161-
return super.getContributions(entries)
164+
public getContributionsFromEntries(
165+
entries: Observable<ContributionsEntry[]>
166+
): Observable<Contributions> {
167+
return super.getContributionsFromEntries(entries)
162168
}
163169
}()
164170
expectObservable(
165-
registry.getContributions(
171+
registry.getContributionsFromEntries(
166172
of([
167173
{
168174
contributions: { menus: { commandPalette: [{ action: 'a', when: 'x == y' }] } },
@@ -183,12 +189,14 @@ describe('ContributionRegistry', () => {
183189
super(cold<Environment>('a', { a: EMPTY_ENVIRONMENT }))
184190
}
185191

186-
public getContributions(entries: Observable<ContributionsEntry[]>): Observable<Contributions> {
187-
return super.getContributions(entries)
192+
public getContributionsFromEntries(
193+
entries: Observable<ContributionsEntry[]>
194+
): Observable<Contributions> {
195+
return super.getContributionsFromEntries(entries)
188196
}
189197
}()
190198
expectObservable(
191-
registry.getContributions(
199+
registry.getContributionsFromEntries(
192200
of([
193201
{
194202
// Expression "!" will cause an error to be thrown.

src/environment/providers/contribution.ts

+16-9
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { flatten, isEqual } from '../../util'
1212
import { getComputedContextProperty } from '../context/context'
1313
import { ComputedContext, evaluate, evaluateTemplate } from '../context/expr/evaluator'
1414
import { TEMPLATE_BEGIN } from '../context/expr/lexer'
15-
import { Environment } from '../environment'
15+
import { Component, Environment } from '../environment'
1616

1717
/** A registered set of contributions from an extension in the registry. */
1818
export interface ContributionsEntry {
@@ -71,11 +71,17 @@ export class ContributionRegistry {
7171
}
7272

7373
/**
74-
* All contributions (merged) that are enabled for the current context, emitted whenever the set changes.
74+
* Returns an observable that emits all contributions (merged) evaluated in the current
75+
* environment (with the optional scope). It emits whenever there is any change.
7576
*/
76-
public readonly contributions: Observable<Contributions> = this.getContributions(this._entries)
77+
public getContributions(scope?: Component): Observable<Contributions> {
78+
return this.getContributionsFromEntries(this._entries, scope)
79+
}
7780

78-
protected getContributions(entries: Observable<ContributionsEntry[]>): Observable<Contributions> {
81+
protected getContributionsFromEntries(
82+
entries: Observable<ContributionsEntry[]>,
83+
scope?: Component
84+
): Observable<Contributions> {
7985
return combineLatest(
8086
entries.pipe(
8187
switchMap(entries =>
@@ -89,7 +95,7 @@ export class ContributionRegistry {
8995
this.environment
9096
).pipe(
9197
map(([multiContributions, environment]) => {
92-
const computedContext = { get: (key: string) => getComputedContextProperty(environment, key) }
98+
const computedContext = { get: (key: string) => getComputedContextProperty(environment, key, scope) }
9399
return flatten(multiContributions).map(contributions => {
94100
try {
95101
return evaluateContributions(
@@ -115,17 +121,18 @@ export class ContributionRegistry {
115121
/**
116122
* All contribution entries, emitted whenever the set of registered contributions changes.
117123
*
118-
* Most callers should use ContributionsRegistry#contributions. Only use #entries if the caller needs
119-
* information that is discarded when the contributions are merged (such as the extension that registered each
120-
* set of contributions).
124+
* Most callers should use ContributionsRegistry#getContributions. Only use #entries if the
125+
* caller needs information that is discarded when the contributions are merged (such as the
126+
* extension that registered each set of contributions).
121127
*/
122128
public readonly entries: Observable<ContributionsEntry[]> & { value: ContributionsEntry[] } = this._entries
123129
}
124130

125131
/**
126132
* Merges the contributions.
127133
*
128-
* Most callers should use ContributionRegistry's contributions field, which merges all registered contributions.
134+
* Most callers should use ContributionRegistry#getContributions, which merges all registered
135+
* contributions.
129136
*/
130137
export function mergeContributions(contributions: Contributions[]): Contributions {
131138
if (contributions.length === 0) {

0 commit comments

Comments
 (0)