Skip to content

Commit 7a915f6

Browse files
committed
Add type guessing
1 parent 0a83b53 commit 7a915f6

File tree

5 files changed

+74
-19
lines changed

5 files changed

+74
-19
lines changed

.vscode/settings.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,10 @@
77
"out": true // set this to false to include "out" folder in search results
88
},
99
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
10-
"typescript.tsc.autoDetect": "off"
10+
"typescript.tsc.autoDetect": "off",
11+
"[typescript]": {
12+
"editor.rulers": [
13+
120
14+
]
15+
}
1116
}

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
{
22
"name": "vscode-python-typehint",
33
"displayName": "Python Type Hint",
4-
"description": "VSCode extension for Python type hint autocompletion.",
4+
"description": "VSCode extension for Python type hint autocompletion.",
5+
"publisher": "nj2532",
56
"repository": {
67
"type": "git",
78
"url": "https://github.com/nj2532/vscode-python-typehint.git"

src/completionProvider.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@ export class ParamHintCompletionProvider implements CompletionItemProvider {
3636
if (hint) {
3737
items.push(new CompletionItem(" " + hint, CompletionItemKind.TypeParameter));
3838
} else {
39-
for (const type of Object.values(Type)) {
40-
items.push(new CompletionItem(" " + type, CompletionItemKind.TypeParameter));
41-
}
39+
pushDefaultCompletionItems(items);
4240
}
4341
}
4442
return Promise.resolve(new CompletionList(items, false));
@@ -85,11 +83,10 @@ export class ReturnHintCompletionProvider implements CompletionItemProvider {
8583
}
8684

8785
private shouldProvideReturnHint(line: TextLine, pos: Position): boolean {
86+
8887
if (pos.character > 0 && line.text.substr(pos.character - 2, 2) === "->") {
8988

90-
if (new RegExp("^[*\t]*def.*\\) *->[: ]*$", "m").test(line.text)) {
91-
return true;
92-
}
89+
return new RegExp("^[*\t]*def.*\\) *->[: ]*$", "m").test(line.text);
9390
}
9491
return false;
9592
}

src/typeResolver.ts

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,78 @@
11
import { TextDocument } from "vscode";
22
import * as search from "./codeSearch";
3+
import { Type, returnHintTrigger } from "./syntax";
4+
import { ToTitleCase } from "./utils";
35

46
export class TypeResolver {
57

8+
private likelyTypes: Type[] = [ Type.String, Type.List, Type.Dict, Type.Bool, Type.Int, Type.Tuple, Type.Float ];
9+
610
/**
7-
* Estimates the type of a parameter.
11+
* Estimates the type of a parameter,
12+
* by searching the document for an initialized variable with the same name.
13+
*
814
* @param doc The document to search.
915
* @param param The parameter name.
1016
*/
1117
public EstimateType(doc: TextDocument, param: string): string | null {
1218
const documentText = doc.getText();
13-
let type: string | null = "";
14-
const match = new RegExp(`^[ \t]*${param} *=.`, "m").exec(documentText);
19+
20+
let type = this.GetTypeIfEndsWith(param, "_", ...this.likelyTypes);
21+
if (type) {
22+
return type;
23+
}
24+
25+
const variableMatch = new RegExp(`^[ \t]*${param} *=.`, "m").exec(documentText);
1526

16-
if (match && match[0]) {
17-
const valueStartPosition = doc.positionAt(match.index + match[0].length);
27+
if (variableMatch && variableMatch[0]) {
28+
const valueStartPosition = doc.positionAt(variableMatch.index + variableMatch[0].length);
1829
const line = doc.lineAt(valueStartPosition);
1930

20-
type = search.detectBasicType(line.text);
31+
let typeName = search.detectBasicType(line.text);
2132

22-
if (type === null) {
23-
type = search.detectNonBasicType(line.text, documentText);
33+
if (typeName === null) {
34+
typeName = search.detectNonBasicType(line.text, documentText);
2435
}
2536

26-
if (type !== null) {
27-
if (!search.invalidTernaryOperator(type, line.text)) {
28-
return type;
37+
if (typeName !== null) {
38+
if (!search.invalidTernaryOperator(typeName, line.text)) {
39+
return typeName;
2940
}
3041
}
3142
}
43+
type = this.GuessType(param);
44+
return type ? type : this.GetTypeIfEndsWith(param, "", Type.List, Type.Dict);
45+
}
46+
47+
private GetTypeIfEndsWith(param: string, prefix: string, ...typesToCheckFor: Type[]): Type | null {
48+
49+
for (const type of typesToCheckFor) {
50+
if (param.endsWith(`${prefix}${type}`)) {
51+
return type;
52+
}
53+
}
3254
return null;
3355
}
56+
57+
private GuessType(param: string): Type | null {
58+
if (param in this.TypeGuesses) {
59+
return this.TypeGuesses[param];
60+
}
61+
return null;
62+
}
63+
64+
/**
65+
* Guesses used if a param with the same name is not found in the active document.
66+
*/
67+
private TypeGuesses: { [key: string]: Type } = {
68+
"string": Type.String,
69+
"text": Type.String,
70+
"path": Type.String,
71+
"url": Type.String,
72+
"uri": Type.String,
73+
"fullpath": Type.String,
74+
"full_path": Type.String,
75+
"number": Type.Int,
76+
"num": Type.Int
77+
};
3478
}

src/utils.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
/**
3+
*
4+
* @param s A string longer than 2 chars
5+
*/
6+
export function ToTitleCase(s: string) {
7+
return `${s[0].toUpperCase}${s.substr(1)}`;
8+
}

0 commit comments

Comments
 (0)