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

Commit 454a7e3

Browse files
committed
feat: add method to get locations with provider name
add TextDocumentLocationProviderRegistry.getLocationsWithProviderName method
1 parent d445230 commit 454a7e3

12 files changed

+96
-12
lines changed

src/client/client.test.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,15 @@ describe('Client', () => {
8484

8585
// Request registration.
8686
client.handleRegistrationRequest({
87-
registrations: [{ id: 'a', method: 'm', registerOptions: { a: 1 }, overwriteExisting: true }],
87+
registrations: [
88+
{ id: 'a', method: 'm', registerOptions: { a: 1, providerName: '' }, overwriteExisting: true },
89+
],
8890
})
8991
assert.deepStrictEqual(registerCalls, [
90-
{ message: { method: 'm' }, data: { id: 'a', registerOptions: { a: 1 }, overwriteExisting: true } },
92+
{
93+
message: { method: 'm' },
94+
data: { id: 'a', registerOptions: { a: 1, providerName: '' }, overwriteExisting: true },
95+
},
9196
] as typeof registerCalls)
9297

9398
// Request unregistration.

src/client/client.ts

+1
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,7 @@ export class Client implements Unsubscribable {
468468
if (!options.documentSelector && this.options.documentSelector) {
469469
options.documentSelector = this.options.documentSelector
470470
}
471+
options.providerName = this.name
471472
const data: RegistrationData<any> = {
472473
id: registration.id,
473474
registerOptions: options,

src/client/features/common.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class TextDocumentFeature extends AbstractTextDocumentFeature<TextDocumentRegist
2828
}
2929
}
3030

31-
const FIXTURE_REGISTER_OPTIONS: TextDocumentRegistrationOptions = { documentSelector: ['*'] }
31+
const FIXTURE_REGISTER_OPTIONS: TextDocumentRegistrationOptions = { documentSelector: ['*'], providerName: 'test' }
3232

3333
describe('TextDocumentFeature', () => {
3434
describe('dynamic registration', () => {

src/client/features/hover.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ export class TextDocumentHoverFeature extends Feature<TextDocumentRegistrationOp
4242
}
4343
this.register(this.messages, {
4444
id: uuidv4(),
45-
registerOptions: { documentSelector },
45+
registerOptions: {
46+
documentSelector,
47+
providerName: this.client.name,
48+
},
4649
})
4750
}
4851

src/client/features/location.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const create = <P extends TextDocumentPositionParams, F extends TextDocumentLoca
2525
registry: TextDocumentLocationProviderRegistry<P>
2626
feature: F
2727
} => {
28-
const client = { options: { middleware: {} } } as Client
28+
const client = { options: { middleware: {} }, name: 'test' } as Client
2929
const registry = new RegistryClass()
3030
const feature = new FeatureClass(client, registry)
3131
return { client, registry, feature }

src/client/features/location.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@ export abstract class TextDocumentLocationFeature<
5858
}
5959
this.register(this.messages, {
6060
id: uuidv4(),
61-
registerOptions: { documentSelector },
61+
registerOptions: {
62+
documentSelector,
63+
providerName: this.client.name,
64+
},
6265
})
6366
}
6467

src/client/features/textDocument.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ describe('TextDocumentNotificationFeature', () => {
4646
}
4747
}
4848

49-
const FIXTURE_REGISTER_OPTIONS: TextDocumentRegistrationOptions = { documentSelector: ['*'] }
49+
const FIXTURE_REGISTER_OPTIONS: TextDocumentRegistrationOptions = { documentSelector: ['*'], providerName: 'test' }
5050

5151
describe('registration', () => {
5252
it('supports dynamic registration and unregistration', () => {

src/client/features/textDocument.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,10 @@ export class TextDocumentDidOpenFeature extends TextDocumentNotificationFeature<
124124
if (documentSelector && textDocumentSyncOptions && textDocumentSyncOptions.openClose) {
125125
this.register(this.messages, {
126126
id: uuidv4(),
127-
registerOptions: { documentSelector },
127+
registerOptions: {
128+
documentSelector,
129+
providerName: this.client.name,
130+
},
128131
})
129132
}
130133
}
@@ -171,7 +174,10 @@ export class TextDocumentDidCloseFeature extends TextDocumentNotificationFeature
171174
if (documentSelector && textDocumentSyncOptions && textDocumentSyncOptions.openClose) {
172175
this.register(this.messages, {
173176
id: uuidv4(),
174-
registerOptions: { documentSelector },
177+
registerOptions: {
178+
documentSelector,
179+
providerName: this.client.name,
180+
},
175181
})
176182
}
177183
}

src/environment/providers/location.ts

+58-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { combineLatest, from, Observable } from 'rxjs'
1+
import { combineLatest, from, Observable, Unsubscribable } from 'rxjs'
22
import { map, switchMap } from 'rxjs/operators'
33
import { Location } from 'vscode-languageserver-types'
44
import { ReferenceParams, TextDocumentPositionParams, TextDocumentRegistrationOptions } from '../../protocol'
55
import { FeatureProviderRegistry } from './registry'
6-
import { flattenAndCompact } from './util'
6+
import { flattenAndCompact, flattenAndCompactNonNull } from './util'
77

88
/**
99
* Function signature for retrieving related locations given a location (e.g., definition, implementation, and type
@@ -22,6 +22,33 @@ export class TextDocumentLocationProviderRegistry<
2222
public getLocation(params: P): Observable<L | L[] | null> {
2323
return getLocation<P, L>(this.providers, params)
2424
}
25+
26+
public getLocationsWithProviderName(params: P): Observable<{ providerName: string; location: L }[] | null> {
27+
return getLocationsWithProviderName<P, L>(this.providersWithName, params)
28+
}
29+
30+
public readonly providersWithName: Observable<
31+
{ name: string; provider: ProvideTextDocumentLocationSignature<P, L> }[]
32+
> = this.entries.pipe(
33+
map(providers =>
34+
providers.map(({ provider, registrationOptions }) => ({
35+
name: registrationOptions.providerName,
36+
provider,
37+
}))
38+
)
39+
)
40+
41+
public registerProvider(
42+
registrationOptions: TextDocumentRegistrationOptions,
43+
provider: ProvideTextDocumentLocationSignature<P, L>
44+
): Unsubscribable {
45+
if (!registrationOptions.providerName) {
46+
// Input validation is necessary here, because registrationOptions is deserialized from
47+
// the registration request and this is the first place where where we have the provider type.
48+
throw new Error('registered provider must have name')
49+
}
50+
return super.registerProvider(registrationOptions, provider)
51+
}
2552
}
2653

2754
/**
@@ -62,6 +89,35 @@ export function getLocations<
6289
)
6390
}
6491

92+
export function getLocationsWithProviderName<
93+
P extends TextDocumentPositionParams = TextDocumentPositionParams,
94+
L extends Location = Location
95+
>(
96+
providersWithName: Observable<{ name: string; provider: ProvideTextDocumentLocationSignature<P, L> }[]>,
97+
params: P
98+
): Observable<{ providerName: string; location: L }[]> {
99+
return providersWithName.pipe(
100+
switchMap(async providersWithName => {
101+
const resultsByProvider = await Promise.all(
102+
providersWithName.map(async ({ provider, name }) => {
103+
const providerRes = await provider(params).toPromise()
104+
return flattenAndCompactNonNull([providerRes]).map(loc => ({
105+
providerName: name,
106+
location: loc,
107+
}))
108+
})
109+
)
110+
const flattenedResults: { providerName: string; location: L }[] = []
111+
for (const providerResults of resultsByProvider) {
112+
for (const res of providerResults) {
113+
flattenedResults.push(res)
114+
}
115+
}
116+
return flattenedResults
117+
})
118+
)
119+
}
120+
65121
/**
66122
* Provides reference results from all extensions.
67123
*

src/environment/providers/registry.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ interface Entry<O, P> {
99

1010
/** Base class for provider registries for features. */
1111
export abstract class FeatureProviderRegistry<O, P> {
12-
private entries = new BehaviorSubject<Entry<O, P>[]>([])
12+
protected entries = new BehaviorSubject<Entry<O, P>[]>([])
1313

1414
public constructor(initialEntries?: Entry<O, P>[]) {
1515
if (initialEntries) {

src/environment/providers/util.ts

+5
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,8 @@ export function flattenAndCompact<T>(value: (T | T[] | null)[] | null): T[] | nu
88
const merged = flatten(compact(value))
99
return merged.length === 0 ? null : merged
1010
}
11+
12+
/** Flattens and compacts the argument. If it is null or if the result is empty, it returns null. */
13+
export function flattenAndCompactNonNull<T>(value: (T | T[] | null)[] | null): T[] {
14+
return value ? flatten(compact(value)) : []
15+
}

src/protocol/textDocument.ts

+5
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,11 @@ export interface TextDocumentRegistrationOptions {
358358
* the document selector provided on the client side will be used.
359359
*/
360360
documentSelector: DocumentSelector | null
361+
362+
/**
363+
* User-visible name of the of the provider being registered.
364+
*/
365+
providerName: string
361366
}
362367

363368
/**

0 commit comments

Comments
 (0)