Skip to content
This repository was archived by the owner on Oct 16, 2020. It is now read-only.

Commit 1f425f3

Browse files
tomv564felixfbecker
authored andcommitted
feat(completion): resolve completion details lazily (#344)
1 parent 7777d8a commit 1f425f3

File tree

3 files changed

+240
-41
lines changed

3 files changed

+240
-41
lines changed

src/request-type.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,30 @@ export interface PartialResultParams {
234234
*/
235235
patch: Operation[];
236236
}
237+
238+
/**
239+
* Restriction on vscode's CompletionItem interface
240+
*/
241+
export interface CompletionItem extends vscode.CompletionItem {
242+
data?: CompletionItemData;
243+
}
244+
245+
/**
246+
* The necessary fields for a completion item details to be resolved by typescript
247+
*/
248+
export interface CompletionItemData {
249+
/**
250+
* The document from which the completion was requested
251+
*/
252+
uri: string;
253+
254+
/**
255+
* The offset into the document at which the completion was requested
256+
*/
257+
offset: number;
258+
259+
/**
260+
* The name field from typescript's returned completion entry
261+
*/
262+
entryName: string;
263+
}

src/test/typescript-service-helpers.ts

Lines changed: 158 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { CompletionItemKind, CompletionList, DiagnosticSeverity, InsertTextForma
99
import { Command, Diagnostic, Hover, Location, SignatureHelp, SymbolInformation, SymbolKind } from 'vscode-languageserver-types';
1010
import { LanguageClient, RemoteLanguageClient } from '../lang-handler';
1111
import { DependencyReference, PackageInformation, ReferenceInformation, TextDocumentContentParams, WorkspaceFilesParams } from '../request-type';
12-
import { ClientCapabilities, SymbolLocationInformation } from '../request-type';
12+
import { ClientCapabilities, CompletionItem, SymbolLocationInformation } from '../request-type';
1313
import { TypeScriptService, TypeScriptServiceFactory } from '../typescript-service';
1414
import { observableFromIterable, toUnixPath, uri2path } from '../util';
1515

@@ -2154,7 +2154,62 @@ export function describeTypeScriptService(createService: TypeScriptServiceFactor
21542154

21552155
afterEach(shutdownService);
21562156

2157-
it('should produce completions with snippets if supported', async function (this: TestContext & ITestCallbackContext) {
2157+
it('should produce completions', async function (this: TestContext & ITestCallbackContext) {
2158+
const result: CompletionList = await this.service.textDocumentCompletion({
2159+
textDocument: {
2160+
uri: rootUri + 'a.ts'
2161+
},
2162+
position: {
2163+
line: 11,
2164+
character: 2
2165+
}
2166+
}).reduce<Operation, CompletionList>(applyReducer, null as any).toPromise();
2167+
assert.equal(result.isIncomplete, false);
2168+
assert.sameDeepMembers(result.items, [
2169+
{
2170+
label: 'bar',
2171+
kind: CompletionItemKind.Method,
2172+
sortText: '0',
2173+
data: {
2174+
entryName: 'bar',
2175+
offset: 210,
2176+
uri: rootUri + 'a.ts'
2177+
}
2178+
},
2179+
{
2180+
label: 'baz',
2181+
kind: CompletionItemKind.Method,
2182+
sortText: '0',
2183+
data: {
2184+
entryName: 'baz',
2185+
offset: 210,
2186+
uri: rootUri + 'a.ts'
2187+
}
2188+
},
2189+
{
2190+
label: 'foo',
2191+
kind: CompletionItemKind.Method,
2192+
sortText: '0',
2193+
data: {
2194+
entryName: 'foo',
2195+
offset: 210,
2196+
uri: rootUri + 'a.ts'
2197+
}
2198+
},
2199+
{
2200+
label: 'qux',
2201+
kind: CompletionItemKind.Property,
2202+
sortText: '0',
2203+
data: {
2204+
entryName: 'qux',
2205+
offset: 210,
2206+
uri: rootUri + 'a.ts'
2207+
}
2208+
}
2209+
]);
2210+
});
2211+
2212+
it('should resolve completions with snippets', async function (this: TestContext & ITestCallbackContext) {
21582213
const result: CompletionList = await this.service.textDocumentCompletion({
21592214
textDocument: {
21602215
uri: rootUri + 'a.ts'
@@ -2169,15 +2224,25 @@ export function describeTypeScriptService(createService: TypeScriptServiceFactor
21692224
// * the end of the snippet. Placeholders with equal identifiers are linked,
21702225
// * that is typing in one will update others too.
21712226
assert.equal(result.isIncomplete, false);
2172-
assert.sameDeepMembers(result.items, [
2227+
2228+
const resolvedItems = await Observable.from(result.items)
2229+
.mergeMap(item => this.service
2230+
.completionItemResolve(item)
2231+
.reduce<Operation, CompletionItem>(applyReducer, null as any)
2232+
)
2233+
.toArray()
2234+
.toPromise();
2235+
2236+
assert.sameDeepMembers(resolvedItems, [
21732237
{
21742238
label: 'bar',
21752239
kind: CompletionItemKind.Method,
21762240
documentation: 'bar doc',
21772241
sortText: '0',
21782242
insertTextFormat: InsertTextFormat.Snippet,
21792243
insertText: 'bar(${1:num})',
2180-
detail: '(method) A.bar(num: number): number'
2244+
detail: '(method) A.bar(num: number): number',
2245+
data: undefined
21812246
},
21822247
{
21832248
label: 'baz',
@@ -2186,7 +2251,8 @@ export function describeTypeScriptService(createService: TypeScriptServiceFactor
21862251
sortText: '0',
21872252
insertTextFormat: InsertTextFormat.Snippet,
21882253
insertText: 'baz(${1:num})',
2189-
detail: '(method) A.baz(num: number): string'
2254+
detail: '(method) A.baz(num: number): string',
2255+
data: undefined
21902256
},
21912257
{
21922258
label: 'foo',
@@ -2195,7 +2261,8 @@ export function describeTypeScriptService(createService: TypeScriptServiceFactor
21952261
sortText: '0',
21962262
insertTextFormat: InsertTextFormat.Snippet,
21972263
insertText: 'foo()',
2198-
detail: '(method) A.foo(): void'
2264+
detail: '(method) A.foo(): void',
2265+
data: undefined
21992266
},
22002267
{
22012268
label: 'qux',
@@ -2204,9 +2271,11 @@ export function describeTypeScriptService(createService: TypeScriptServiceFactor
22042271
sortText: '0',
22052272
insertTextFormat: InsertTextFormat.Snippet,
22062273
insertText: 'qux',
2207-
detail: '(property) A.qux: number'
2274+
detail: '(property) A.qux: number',
2275+
data: undefined
22082276
}
22092277
]);
2278+
22102279
});
22112280
});
22122281

@@ -2258,14 +2327,77 @@ export function describeTypeScriptService(createService: TypeScriptServiceFactor
22582327
}).reduce<Operation, CompletionList>(applyReducer, null as any).toPromise();
22592328
assert.equal(result.isIncomplete, false);
22602329
assert.sameDeepMembers(result.items, [
2330+
{
2331+
data: {
2332+
entryName: 'bar',
2333+
offset: 188,
2334+
uri: rootUri + 'a.ts'
2335+
},
2336+
label: 'bar',
2337+
kind: CompletionItemKind.Method,
2338+
sortText: '0'
2339+
},
2340+
{
2341+
data: {
2342+
entryName: 'baz',
2343+
offset: 188,
2344+
uri: rootUri + 'a.ts'
2345+
},
2346+
label: 'baz',
2347+
kind: CompletionItemKind.Method,
2348+
sortText: '0'
2349+
},
2350+
{
2351+
data: {
2352+
entryName: 'foo',
2353+
offset: 188,
2354+
uri: rootUri + 'a.ts'
2355+
},
2356+
label: 'foo',
2357+
kind: CompletionItemKind.Method,
2358+
sortText: '0'
2359+
},
2360+
{
2361+
data: {
2362+
entryName: 'qux',
2363+
offset: 188,
2364+
uri: rootUri + 'a.ts'
2365+
},
2366+
label: 'qux',
2367+
kind: CompletionItemKind.Property,
2368+
sortText: '0'
2369+
}
2370+
]);
2371+
});
2372+
2373+
it('resolves completions in the same file', async function (this: TestContext & ITestCallbackContext) {
2374+
const result: CompletionList = await this.service.textDocumentCompletion({
2375+
textDocument: {
2376+
uri: rootUri + 'a.ts'
2377+
},
2378+
position: {
2379+
line: 11,
2380+
character: 2
2381+
}
2382+
}).reduce<Operation, CompletionList>(applyReducer, null as any).toPromise();
2383+
assert.equal(result.isIncomplete, false);
2384+
2385+
const resolveItem = (item: CompletionItem) => this.service
2386+
.completionItemResolve(item)
2387+
.reduce<Operation, CompletionItem>(applyReducer, null as any).toPromise();
2388+
2389+
const resolvedItems = await Promise.all(result.items.map(resolveItem));
2390+
2391+
assert.sameDeepMembers(resolvedItems, [
22612392
{
22622393
label: 'bar',
22632394
kind: CompletionItemKind.Method,
22642395
documentation: 'bar doc',
22652396
insertText: 'bar',
22662397
insertTextFormat: InsertTextFormat.PlainText,
22672398
sortText: '0',
2268-
detail: '(method) A.bar(): number'
2399+
detail: '(method) A.bar(): number',
2400+
data: undefined
22692401
},
22702402
{
22712403
label: 'baz',
@@ -2274,7 +2406,8 @@ export function describeTypeScriptService(createService: TypeScriptServiceFactor
22742406
insertText: 'baz',
22752407
insertTextFormat: InsertTextFormat.PlainText,
22762408
sortText: '0',
2277-
detail: '(method) A.baz(): string'
2409+
detail: '(method) A.baz(): string',
2410+
data: undefined
22782411
},
22792412
{
22802413
label: 'foo',
@@ -2283,7 +2416,8 @@ export function describeTypeScriptService(createService: TypeScriptServiceFactor
22832416
insertText: 'foo',
22842417
insertTextFormat: InsertTextFormat.PlainText,
22852418
sortText: '0',
2286-
detail: '(method) A.foo(): void'
2419+
detail: '(method) A.foo(): void',
2420+
data: undefined
22872421
},
22882422
{
22892423
label: 'qux',
@@ -2292,9 +2426,11 @@ export function describeTypeScriptService(createService: TypeScriptServiceFactor
22922426
insertText: 'qux',
22932427
insertTextFormat: InsertTextFormat.PlainText,
22942428
sortText: '0',
2295-
detail: '(property) A.qux: number'
2429+
detail: '(property) A.qux: number',
2430+
data: undefined
22962431
}
22972432
]);
2433+
22982434
});
22992435

23002436
it('produces completions for imported symbols', async function (this: TestContext & ITestCallbackContext) {
@@ -2310,12 +2446,13 @@ export function describeTypeScriptService(createService: TypeScriptServiceFactor
23102446
assert.deepEqual(result, {
23112447
isIncomplete: false,
23122448
items: [{
2449+
data: {
2450+
entryName: 'd',
2451+
offset: 32,
2452+
uri: rootUri + 'uses-import.ts'
2453+
},
23132454
label: 'd',
23142455
kind: CompletionItemKind.Function,
2315-
documentation: 'd doc',
2316-
insertText: 'd',
2317-
insertTextFormat: InsertTextFormat.PlainText,
2318-
detail: 'function d(): void',
23192456
sortText: '0'
23202457
}]
23212458
});
@@ -2333,13 +2470,14 @@ export function describeTypeScriptService(createService: TypeScriptServiceFactor
23332470
assert.deepEqual(result, {
23342471
isIncomplete: false,
23352472
items: [{
2473+
data: {
2474+
entryName: 'bar',
2475+
offset: 51,
2476+
uri: rootUri + 'uses-reference.ts'
2477+
},
23362478
label: 'bar',
23372479
kind: CompletionItemKind.Interface,
2338-
documentation: 'bar doc',
2339-
insertText: 'bar',
2340-
insertTextFormat: InsertTextFormat.PlainText,
2341-
sortText: '0',
2342-
detail: 'interface foo.bar'
2480+
sortText: '0'
23432481
}]
23442482
});
23452483
});

0 commit comments

Comments
 (0)