Skip to content

Commit fbf8e98

Browse files
committed
feat:support tips of options
1 parent b1e1d89 commit fbf8e98

File tree

2 files changed

+80
-96
lines changed

2 files changed

+80
-96
lines changed

src/autocomplete/TerraformTipsProvider.ts

Lines changed: 79 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import resources from '../../config/tips/tiat-resources.json';
33
import * as _ from "lodash";
44
import * as vscode from 'vscode';
55

6-
var topLevelTypes = ["output", "provider", "resource", "variable", "data"];
7-
var topLevelRegexes = topLevelTypes.map(o => {
6+
let topLevelTypes = ["output", "provider", "resource", "variable", "data"];
7+
let topLevelRegexes = topLevelTypes.map(o => {
88
return {
99
type: o,
1010
regex: new RegExp(o + ' "[A-Za-z0-9\-_]+" "[A-Za-z0-9\-_]*" \{')
@@ -19,17 +19,16 @@ export class TerraformTipsProvider implements CompletionItemProvider {
1919
document: TextDocument;
2020
position: Position;
2121
token: CancellationToken;
22-
23-
22+
resourceType: string | null = null;
2423

2524
public provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken, context: TerraformCompletionContext): CompletionItem[] {
2625
this.document = document;
2726
this.position = position;
2827
this.token = token;
2928

3029
// Check if we're on the top level
31-
let lineText = document.lineAt(position.line).text;
32-
let lineTillCurrentPosition = lineText.substr(0, position.character);
30+
const lineText = document.lineAt(position.line).text;
31+
const lineTillCurrentPosition = lineText.substring(0, position.character);
3332

3433
// Are we trying to type a resource type?
3534
if (this.isTopLevelType(lineTillCurrentPosition)) {
@@ -39,16 +38,16 @@ export class TerraformTipsProvider implements CompletionItemProvider {
3938
// Are we trying to type a variable?
4039
if (this.isTypingTfCode(lineTillCurrentPosition)) {
4140
// These variables should always just have 3 parts, resource type, resource name, exported field
42-
var varString = this.getVariableString(lineTillCurrentPosition);
43-
var parts = varString.split(".");
41+
let varString = this.getVariableString(lineTillCurrentPosition);
42+
let parts = varString.split(".");
4443

4544
if (parts.length === 1) {
4645
// We're trying to type the resource type
47-
var resourceTypePrefix = parts[1];
46+
let resourceTypePrefix = parts[1];
4847

4948
// Get a list of all the resource types we've defined in this file
50-
var definedResourceTypes = this.getDefinedResourceTypes(document);
51-
var finalResourceTypes = _.filter(definedResourceTypes, o => (o.indexOf(resourceTypePrefix) === 0));
49+
let definedResourceTypes = this.getDefinedResourceTypes(document);
50+
let finalResourceTypes = _.filter(definedResourceTypes, o => (o.indexOf(resourceTypePrefix) === 0));
5251
return _.map(finalResourceTypes, o => {
5352
return new CompletionItem(o, CompletionItemKind.Field);
5453
});
@@ -58,15 +57,15 @@ export class TerraformTipsProvider implements CompletionItemProvider {
5857
const resourceType = parts[0];
5958

6059
// Get a list of all the names for this resource type
61-
var names = this.getNamesForResourceType(document, resourceType);
60+
let names = this.getNamesForResourceType(document, resourceType);
6261
return _.map(names, o => new CompletionItem(o, CompletionItemKind.Field));
6362
}
6463
else if (parts.length === 3) {
65-
// We're trying to type the exported field for the var
64+
// We're trying to type the exported field for the let
6665
const resourceType = parts[0];
67-
var resourceName = parts[1];
68-
var attrs = resources[resourceType].attrs;
69-
var result = _.map(attrs, o => {
66+
let resourceName = parts[1];
67+
let attrs = resources[resourceType].attrs;
68+
let result = _.map(attrs, o => {
7069
let c = new CompletionItem(`${o.name} (${resourceType})`, CompletionItemKind.Property);
7170
c.detail = o.description;
7271
c.insertText = o.name;
@@ -85,36 +84,39 @@ export class TerraformTipsProvider implements CompletionItemProvider {
8584
return this.getHintsForStrings(possibleResources);
8685
}
8786

88-
// type '='
89-
if (lineTillCurrentPosition.endsWith('=') && context.resourceType) {
90-
91-
// const completionItems: CompletionItem[] = [
92-
// new CompletionItem('Option1', CompletionItemKind.Value),
93-
// new CompletionItem('Option2', CompletionItemKind.Value)
94-
// ];
95-
96-
const match = lineTillCurrentPosition.match(/(\w+)\s*=/);
97-
if (match) {
87+
const endwithEqual = lineTillCurrentPosition.endsWith('=');
88+
const includeEqual = lineTillCurrentPosition.indexOf('=');
89+
// handle options
90+
if (this.resourceType) {
91+
// when we typing a '=' character
92+
if (endwithEqual) {
93+
const lineBeforeEqualSign = lineTillCurrentPosition.substring(0, includeEqual).trim();
9894
// load options
99-
const name = match[1];
100-
const strs = this.findArgByName(resources[context.resourceType].args, name);
101-
return this.packOptionsFormStrings(strs);
95+
const name = lineBeforeEqualSign;
96+
const argStrs = this.findArgByName(resources[this.resourceType].args, name);
97+
const options = this.getOptionsFormArg(argStrs);
98+
// clear resource type
99+
this.resourceType = "";
100+
return (options).length ? options : [];
102101
}
103102
return [];
104103
}
105104

106105
// Check if we're in a resource definition
107-
for (var i = position.line - 1; i >= 0; i--) {
108-
let line = document.lineAt(i).text;
109-
let parentType = this.getParentType(line);
110-
if (parentType && parentType.type === "resource") {
111-
const resourceType = this.getResourceTypeFromLine(line);
112-
let ret = this.getItemsForArgs(resources[resourceType].args, resourceType);
113-
return ret;
114-
}
115-
else if (parentType && parentType.type !== "resource") {
116-
// We don't want to accidentally include some other containers stuff
117-
return [];
106+
if (includeEqual < 0 && !endwithEqual) {
107+
// we're not in options case
108+
for (let i = position.line - 1; i >= 0; i--) {
109+
let line = document.lineAt(i).text;
110+
let parentType = this.getParentType(line);
111+
if (parentType && parentType.type === "resource") {
112+
const resourceType = this.getResourceTypeFromLine(line);
113+
const ret = this.getItemsForArgs(resources[resourceType].args, resourceType);
114+
return ret;
115+
}
116+
else if (parentType && parentType.type !== "resource") {
117+
// We don't want to accidentally include some other containers stuff
118+
return [];
119+
}
118120
}
119121
}
120122

@@ -126,7 +128,7 @@ export class TerraformTipsProvider implements CompletionItemProvider {
126128

127129
for (let i = position.line - 1; i >= 0; i--) {
128130
const line = document.lineAt(i).text;
129-
const match = line.match(resourceRegex);
131+
const match = RegExp(resourceRegex).exec(line);
130132

131133
if (match) {
132134
return match[1];
@@ -136,22 +138,25 @@ export class TerraformTipsProvider implements CompletionItemProvider {
136138
return undefined;
137139
}
138140

139-
packOptionsFormStrings(strings: string[]): CompletionItem[] {
140-
return _.map(strings, s => {
141-
return new CompletionItem(s, CompletionItemKind.Enum);
141+
getOptionsFormArg(opts: string[]): CompletionItem[] {
142+
return _.map(opts, opt => {
143+
let c = new CompletionItem(opt, CompletionItemKind.Value);
144+
c.insertText = "\"" + opt + "\"";
145+
return c;
142146
});
143147
}
144148

145149
findArgByName(args: any, name: string): any {
146-
return args.find((arg) => arg.name === name);
150+
const arg = args.find((arg) => arg.name === name);
151+
return arg.options;
147152
}
148153

149154
getNamesForResourceType(document: TextDocument, resourceType: string): string[] {
150-
var r = new RegExp('resource "' + resourceType + '" "([a-zA-Z0-9\-_]+)"');
151-
var found = [];
152-
for (var i = 0; i < document.lineCount; i++) {
153-
var line = document.lineAt(i).text;
154-
var result = line.match(r);
155+
let r = new RegExp('resource "' + resourceType + '" "([a-zA-Z0-9\-_]+)"');
156+
let found = [];
157+
for (let i = 0; i < document.lineCount; i++) {
158+
let line = document.lineAt(i).text;
159+
let result = RegExp(r).exec(line);
155160
if (result && result.length > 1) {
156161
found.push(result[1]);
157162
}
@@ -163,11 +168,11 @@ export class TerraformTipsProvider implements CompletionItemProvider {
163168
* Returns a list of resource type strings
164169
*/
165170
getDefinedResourceTypes(document: TextDocument) {
166-
var r = /resource "([a-zA-Z0-9\-_]+)"/;
167-
var found = [];
168-
for (var i = 0; i < document.lineCount; i++) {
169-
var line = document.lineAt(i).text;
170-
var result = line.match(r);
171+
let r = /resource "([a-zA-Z0-9\-_]+)"/;
172+
let found = [];
173+
for (let i = 0; i < document.lineCount; i++) {
174+
let line = document.lineAt(i).text;
175+
let result = line.match(r);
171176
if (result && result.length > 1) {
172177
found.push(result[1]);
173178
}
@@ -176,33 +181,34 @@ export class TerraformTipsProvider implements CompletionItemProvider {
176181
}
177182

178183
isTopLevelType(line: string): boolean {
179-
for (var i = 0; i < topLevelTypes.length; i++) {
180-
let resourceType = topLevelTypes[i];
181-
if (resourceType.indexOf(line) === 0) {
184+
for (const element of topLevelTypes) {
185+
let resourceType = element;
186+
if (resourceType.startsWith(line)) {
182187
return true;
183188
}
184189
}
185190
return false;
186191
}
187192

188193
getTopLevelType(line: string): CompletionItem[] {
189-
for (var i = 0; i < topLevelTypes.length; i++) {
190-
let resourceType = topLevelTypes[i];
191-
if (resourceType.indexOf(line) === 0) {
194+
for (const element of topLevelTypes) {
195+
let resourceType = element;
196+
if (resourceType.startsWith(line)) {
192197
return [new CompletionItem(resourceType, CompletionItemKind.Enum)];
193198
}
194199
}
195200
return [];
196201
}
197202

198203
isTypingTfCode(line: string): boolean {
199-
var r = /\$\{[0-9a-zA-Z_\.\-]*$/;
204+
let r = /\$\{[0-9a-zA-Z_\.\-]*$/;
200205
return r.test(line);
201206
}
202207

203208
getVariableString(line: string): string {
204-
var r = /\$\{([0-9a-zA-Z_\.\-]*)$/;
205-
var result = line.match(r);
209+
let r = /\$\{([0-9a-zA-Z_\.\-]*)$/;
210+
let result = RegExp(r).exec(line);
211+
// let result = line.match(r);
206212
if (result.length > 1) {
207213
return result[1];
208214
}
@@ -214,7 +220,7 @@ export class TerraformTipsProvider implements CompletionItemProvider {
214220
if (parts.length === 2 && parts[0] === "resource") {
215221
let r = parts[1].replace(/"/g, '');
216222
let regex = new RegExp("^" + r);
217-
var possibleResources = _.filter(_.keys(resources), k => {
223+
let possibleResources = _.filter(_.keys(resources), k => {
218224
if (regex.test(k)) {
219225
return true;
220226
}
@@ -232,8 +238,8 @@ export class TerraformTipsProvider implements CompletionItemProvider {
232238
}
233239

234240
getParentType(line: string): boolean | any {
235-
for (var i = 0; i < topLevelRegexes.length; i++) {
236-
let tl = topLevelRegexes[i];
241+
for (const element of topLevelRegexes) {
242+
let tl = element;
237243
if (tl.regex.test(line)) {
238244
return tl;
239245
}
@@ -242,28 +248,16 @@ export class TerraformTipsProvider implements CompletionItemProvider {
242248
}
243249

244250
getResourceTypeFromLine(line: string): string {
245-
var lineParts = line.split(" ");
246-
var type = lineParts[1];
251+
let lineParts = line.split(" ");
252+
let type = lineParts[1];
247253
return type.replace(/"/g, '');
248254
}
249255

250256
getItemsForArgs(args, type) {
251257
return _.map(args, o => {
252258
let c = new CompletionItem(`${o.name} (${type})`, CompletionItemKind.Property);
253-
let text = o.name;
254-
if (o.default) {
255-
text = text + ' = ' + o.default;
256-
}
257-
let desc = o.description;
258-
if (o.options && o.options.length > 0) {
259-
let options = "";
260-
o.options.prototype.forEach(oo => {
261-
options = options + oo + ',';
262-
});
263-
desc = 'Optional Values: ' + options;
264-
}
265-
c.insertText = text;
266-
c.detail = desc;
259+
c.detail = o.description;
260+
c.insertText = o.name;
267261
return c;
268262
});
269263
}
@@ -281,19 +275,9 @@ export class TerraformTipsProvider implements CompletionItemProvider {
281275
const resourceType = this.findResourceType(event.document, position);
282276

283277
if (resourceType) {
284-
setTimeout(() => {
285-
const cancellationTokenSource = new vscode.CancellationTokenSource();
286-
const context: TerraformCompletionContext = {
287-
triggerKind: vscode.CompletionTriggerKind.Invoke,
288-
triggerCharacter: undefined,
289-
resourceType,
290-
};
291-
this.provideCompletionItems(event.document, position, cancellationTokenSource.token, context);
292-
vscode.commands.executeCommand('editor.action.triggerSuggest');
293-
}, 10);
278+
this.resourceType = resourceType;
279+
vscode.commands.executeCommand('editor.action.triggerSuggest');
294280
}
295281
}
296282
}
297-
298-
299283
}

src/extension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,12 +96,12 @@ export async function activate(context: vscode.ExtensionContext) {
9696
// auto-complete
9797
console.log('activate the auto complete(snippets and lint) feature');
9898
const tipsProvider = new TerraformTipsProvider();
99-
context.subscriptions.push(vscode.languages.registerCompletionItemProvider(TF_MODE, tipsProvider, '.'));
10099
context.subscriptions.push(
101100
vscode.workspace.onDidChangeTextDocument((event) => {
102101
tipsProvider.handleCharacterEvent(event);
103102
})
104103
);
104+
context.subscriptions.push(vscode.languages.registerCompletionItemProvider(TF_MODE, tipsProvider));
105105
context.subscriptions.push(vscode.languages.registerDefinitionProvider(TF_MODE, new TerraformResDocProvider()));
106106

107107
// import-resource

0 commit comments

Comments
 (0)