|
1 | 1 | 'use strict';
|
2 | 2 |
|
3 | 3 | import * as vscode from 'vscode';
|
4 |
| -import { Position, ProviderResult, SnippetString, Uri } from 'vscode'; |
5 |
| -import { PythonSettings } from '../common/configSettings'; |
6 |
| -import { Tokenizer } from '../language/tokenizer'; |
7 |
| -import { TokenType } from '../language/types'; |
| 4 | +import { isTestExecution } from '../common/configSettings'; |
8 | 5 | import { JediFactory } from '../languageServices/jediProxyFactory';
|
9 | 6 | import { captureTelemetry } from '../telemetry';
|
10 | 7 | import { COMPLETION } from '../telemetry/constants';
|
11 |
| -import { extractSignatureAndDocumentation } from './jediHelpers'; |
12 |
| -import * as proxy from './jediProxy'; |
| 8 | +import { CompletionSource } from './completionSource'; |
13 | 9 |
|
14 | 10 | export class PythonCompletionItemProvider implements vscode.CompletionItemProvider {
|
| 11 | + private completionSource: CompletionSource; |
15 | 12 |
|
16 |
| - public constructor(private jediFactory: JediFactory) { } |
17 |
| - private static parseData(data: proxy.ICompletionResult, resource: Uri): vscode.CompletionItem[] { |
18 |
| - if (data && data.items.length > 0) { |
19 |
| - return data.items.map(item => { |
20 |
| - const sigAndDocs = extractSignatureAndDocumentation(item); |
21 |
| - const completionItem = new vscode.CompletionItem(item.text); |
22 |
| - completionItem.kind = item.type; |
23 |
| - completionItem.documentation = sigAndDocs[1].length === 0 ? item.description : sigAndDocs[1]; |
24 |
| - completionItem.detail = sigAndDocs[0].split(/\r?\n/).join(''); |
25 |
| - if (PythonSettings.getInstance(resource).autoComplete.addBrackets === true && |
26 |
| - (item.kind === vscode.SymbolKind.Function || item.kind === vscode.SymbolKind.Method)) { |
27 |
| - completionItem.insertText = new SnippetString(item.text).appendText('(').appendTabstop().appendText(')'); |
28 |
| - } |
29 |
| - |
30 |
| - // ensure the built in memebers are at the bottom |
31 |
| - completionItem.sortText = (completionItem.label.startsWith('__') ? 'z' : (completionItem.label.startsWith('_') ? 'y' : '__')) + completionItem.label; |
32 |
| - return completionItem; |
33 |
| - }); |
34 |
| - } |
35 |
| - return []; |
| 13 | + constructor(jediFactory: JediFactory) { |
| 14 | + this.completionSource = new CompletionSource(jediFactory); |
36 | 15 | }
|
| 16 | + |
37 | 17 | @captureTelemetry(COMPLETION)
|
38 |
| - public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): ProviderResult<vscode.CompletionItem[]> { |
39 |
| - if (position.character <= 0) { |
40 |
| - return Promise.resolve([]); |
41 |
| - } |
42 |
| - const filename = document.fileName; |
43 |
| - const lineText = document.lineAt(position.line).text; |
44 |
| - if (lineText.match(/^\s*\/\//)) { |
45 |
| - return Promise.resolve([]); |
| 18 | + public async provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): |
| 19 | + Promise<vscode.CompletionItem[]> { |
| 20 | + const items = await this.completionSource.getVsCodeCompletionItems(document, position, token); |
| 21 | + if (isTestExecution()) { |
| 22 | + for (let i = 0; i < Math.min(3, items.length); i += 1) { |
| 23 | + items[i] = await this.resolveCompletionItem(items[i], token); |
| 24 | + } |
46 | 25 | }
|
47 |
| - // Suppress completion inside string and comments |
48 |
| - if (this.isPositionInsideStringOrComment(document, position)) { |
49 |
| - return Promise.resolve([]); |
50 |
| - } |
51 |
| - const type = proxy.CommandType.Completions; |
52 |
| - const columnIndex = position.character; |
53 |
| - |
54 |
| - const source = document.getText(); |
55 |
| - const cmd: proxy.ICommand<proxy.ICommandResult> = { |
56 |
| - command: type, |
57 |
| - fileName: filename, |
58 |
| - columnIndex: columnIndex, |
59 |
| - lineIndex: position.line, |
60 |
| - source: source |
61 |
| - }; |
62 |
| - |
63 |
| - return this.jediFactory.getJediProxyHandler<proxy.ICompletionResult>(document.uri).sendCommand(cmd, token).then(data => { |
64 |
| - return PythonCompletionItemProvider.parseData(data, document.uri); |
65 |
| - }); |
| 26 | + return items; |
66 | 27 | }
|
67 | 28 |
|
68 |
| - private isPositionInsideStringOrComment(document: vscode.TextDocument, position: vscode.Position): boolean { |
69 |
| - const tokenizeTo = position.translate(1, 0); |
70 |
| - const text = document.getText(new vscode.Range(new Position(0, 0), tokenizeTo)); |
71 |
| - const t = new Tokenizer(); |
72 |
| - const tokens = t.Tokenize(text); |
73 |
| - const index = tokens.getItemContaining(document.offsetAt(position)); |
74 |
| - return index >= 0 && (tokens[index].TokenType === TokenType.String || tokens[index].TokenType === TokenType.Comment); |
| 29 | + public async resolveCompletionItem(item: vscode.CompletionItem, token: vscode.CancellationToken): Promise<vscode.CompletionItem> { |
| 30 | + if (!item.documentation) { |
| 31 | + const itemInfos = await this.completionSource.getDocumentation(item, token); |
| 32 | + if (itemInfos && itemInfos.length > 0) { |
| 33 | + item.detail = itemInfos[0].detail; |
| 34 | + item.documentation = itemInfos[0].documentation; |
| 35 | + } |
| 36 | + } |
| 37 | + return item; |
75 | 38 | }
|
76 | 39 | }
|
0 commit comments