Skip to content

Commit

Permalink
feat:support tips of options
Browse files Browse the repository at this point in the history
  • Loading branch information
lyu571 committed Nov 13, 2023
1 parent b1e1d89 commit fbf8e98
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 96 deletions.
174 changes: 79 additions & 95 deletions src/autocomplete/TerraformTipsProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import resources from '../../config/tips/tiat-resources.json';
import * as _ from "lodash";
import * as vscode from 'vscode';

var topLevelTypes = ["output", "provider", "resource", "variable", "data"];
var topLevelRegexes = topLevelTypes.map(o => {
let topLevelTypes = ["output", "provider", "resource", "variable", "data"];
let topLevelRegexes = topLevelTypes.map(o => {
return {
type: o,
regex: new RegExp(o + ' "[A-Za-z0-9\-_]+" "[A-Za-z0-9\-_]*" \{')
Expand All @@ -19,17 +19,16 @@ export class TerraformTipsProvider implements CompletionItemProvider {
document: TextDocument;
position: Position;
token: CancellationToken;


resourceType: string | null = null;

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

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

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

if (parts.length === 1) {
// We're trying to type the resource type
var resourceTypePrefix = parts[1];
let resourceTypePrefix = parts[1];

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

// Get a list of all the names for this resource type
var names = this.getNamesForResourceType(document, resourceType);
let names = this.getNamesForResourceType(document, resourceType);
return _.map(names, o => new CompletionItem(o, CompletionItemKind.Field));
}
else if (parts.length === 3) {
// We're trying to type the exported field for the var
// We're trying to type the exported field for the let
const resourceType = parts[0];
var resourceName = parts[1];
var attrs = resources[resourceType].attrs;
var result = _.map(attrs, o => {
let resourceName = parts[1];
let attrs = resources[resourceType].attrs;
let result = _.map(attrs, o => {
let c = new CompletionItem(`${o.name} (${resourceType})`, CompletionItemKind.Property);
c.detail = o.description;
c.insertText = o.name;
Expand All @@ -85,36 +84,39 @@ export class TerraformTipsProvider implements CompletionItemProvider {
return this.getHintsForStrings(possibleResources);
}

// type '='
if (lineTillCurrentPosition.endsWith('=') && context.resourceType) {

// const completionItems: CompletionItem[] = [
// new CompletionItem('Option1', CompletionItemKind.Value),
// new CompletionItem('Option2', CompletionItemKind.Value)
// ];

const match = lineTillCurrentPosition.match(/(\w+)\s*=/);
if (match) {
const endwithEqual = lineTillCurrentPosition.endsWith('=');
const includeEqual = lineTillCurrentPosition.indexOf('=');
// handle options
if (this.resourceType) {
// when we typing a '=' character
if (endwithEqual) {
const lineBeforeEqualSign = lineTillCurrentPosition.substring(0, includeEqual).trim();
// load options
const name = match[1];
const strs = this.findArgByName(resources[context.resourceType].args, name);
return this.packOptionsFormStrings(strs);
const name = lineBeforeEqualSign;
const argStrs = this.findArgByName(resources[this.resourceType].args, name);
const options = this.getOptionsFormArg(argStrs);
// clear resource type
this.resourceType = "";
return (options).length ? options : [];
}
return [];
}

// Check if we're in a resource definition
for (var i = position.line - 1; i >= 0; i--) {
let line = document.lineAt(i).text;
let parentType = this.getParentType(line);
if (parentType && parentType.type === "resource") {
const resourceType = this.getResourceTypeFromLine(line);
let ret = this.getItemsForArgs(resources[resourceType].args, resourceType);
return ret;
}
else if (parentType && parentType.type !== "resource") {
// We don't want to accidentally include some other containers stuff
return [];
if (includeEqual < 0 && !endwithEqual) {
// we're not in options case
for (let i = position.line - 1; i >= 0; i--) {
let line = document.lineAt(i).text;
let parentType = this.getParentType(line);
if (parentType && parentType.type === "resource") {
const resourceType = this.getResourceTypeFromLine(line);
const ret = this.getItemsForArgs(resources[resourceType].args, resourceType);
return ret;
}
else if (parentType && parentType.type !== "resource") {
// We don't want to accidentally include some other containers stuff
return [];
}
}
}

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

for (let i = position.line - 1; i >= 0; i--) {
const line = document.lineAt(i).text;
const match = line.match(resourceRegex);
const match = RegExp(resourceRegex).exec(line);

if (match) {
return match[1];
Expand All @@ -136,22 +138,25 @@ export class TerraformTipsProvider implements CompletionItemProvider {
return undefined;
}

packOptionsFormStrings(strings: string[]): CompletionItem[] {
return _.map(strings, s => {
return new CompletionItem(s, CompletionItemKind.Enum);
getOptionsFormArg(opts: string[]): CompletionItem[] {
return _.map(opts, opt => {
let c = new CompletionItem(opt, CompletionItemKind.Value);
c.insertText = "\"" + opt + "\"";
return c;
});
}

findArgByName(args: any, name: string): any {
return args.find((arg) => arg.name === name);
const arg = args.find((arg) => arg.name === name);
return arg.options;
}

getNamesForResourceType(document: TextDocument, resourceType: string): string[] {
var r = new RegExp('resource "' + resourceType + '" "([a-zA-Z0-9\-_]+)"');
var found = [];
for (var i = 0; i < document.lineCount; i++) {
var line = document.lineAt(i).text;
var result = line.match(r);
let r = new RegExp('resource "' + resourceType + '" "([a-zA-Z0-9\-_]+)"');
let found = [];
for (let i = 0; i < document.lineCount; i++) {
let line = document.lineAt(i).text;
let result = RegExp(r).exec(line);
if (result && result.length > 1) {
found.push(result[1]);
}
Expand All @@ -163,11 +168,11 @@ export class TerraformTipsProvider implements CompletionItemProvider {
* Returns a list of resource type strings
*/
getDefinedResourceTypes(document: TextDocument) {
var r = /resource "([a-zA-Z0-9\-_]+)"/;
var found = [];
for (var i = 0; i < document.lineCount; i++) {
var line = document.lineAt(i).text;
var result = line.match(r);
let r = /resource "([a-zA-Z0-9\-_]+)"/;
let found = [];
for (let i = 0; i < document.lineCount; i++) {
let line = document.lineAt(i).text;
let result = line.match(r);
if (result && result.length > 1) {
found.push(result[1]);
}
Expand All @@ -176,33 +181,34 @@ export class TerraformTipsProvider implements CompletionItemProvider {
}

isTopLevelType(line: string): boolean {
for (var i = 0; i < topLevelTypes.length; i++) {
let resourceType = topLevelTypes[i];
if (resourceType.indexOf(line) === 0) {
for (const element of topLevelTypes) {
let resourceType = element;
if (resourceType.startsWith(line)) {
return true;
}
}
return false;
}

getTopLevelType(line: string): CompletionItem[] {
for (var i = 0; i < topLevelTypes.length; i++) {
let resourceType = topLevelTypes[i];
if (resourceType.indexOf(line) === 0) {
for (const element of topLevelTypes) {
let resourceType = element;
if (resourceType.startsWith(line)) {
return [new CompletionItem(resourceType, CompletionItemKind.Enum)];
}
}
return [];
}

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

getVariableString(line: string): string {
var r = /\$\{([0-9a-zA-Z_\.\-]*)$/;
var result = line.match(r);
let r = /\$\{([0-9a-zA-Z_\.\-]*)$/;
let result = RegExp(r).exec(line);
// let result = line.match(r);
if (result.length > 1) {
return result[1];
}
Expand All @@ -214,7 +220,7 @@ export class TerraformTipsProvider implements CompletionItemProvider {
if (parts.length === 2 && parts[0] === "resource") {
let r = parts[1].replace(/"/g, '');
let regex = new RegExp("^" + r);
var possibleResources = _.filter(_.keys(resources), k => {
let possibleResources = _.filter(_.keys(resources), k => {
if (regex.test(k)) {
return true;
}
Expand All @@ -232,8 +238,8 @@ export class TerraformTipsProvider implements CompletionItemProvider {
}

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

getResourceTypeFromLine(line: string): string {
var lineParts = line.split(" ");
var type = lineParts[1];
let lineParts = line.split(" ");
let type = lineParts[1];
return type.replace(/"/g, '');
}

getItemsForArgs(args, type) {
return _.map(args, o => {
let c = new CompletionItem(`${o.name} (${type})`, CompletionItemKind.Property);
let text = o.name;
if (o.default) {
text = text + ' = ' + o.default;
}
let desc = o.description;
if (o.options && o.options.length > 0) {
let options = "";
o.options.prototype.forEach(oo => {
options = options + oo + ',';
});
desc = 'Optional Values: ' + options;
}
c.insertText = text;
c.detail = desc;
c.detail = o.description;
c.insertText = o.name;
return c;
});
}
Expand All @@ -281,19 +275,9 @@ export class TerraformTipsProvider implements CompletionItemProvider {
const resourceType = this.findResourceType(event.document, position);

if (resourceType) {
setTimeout(() => {
const cancellationTokenSource = new vscode.CancellationTokenSource();
const context: TerraformCompletionContext = {
triggerKind: vscode.CompletionTriggerKind.Invoke,
triggerCharacter: undefined,
resourceType,
};
this.provideCompletionItems(event.document, position, cancellationTokenSource.token, context);
vscode.commands.executeCommand('editor.action.triggerSuggest');
}, 10);
this.resourceType = resourceType;
vscode.commands.executeCommand('editor.action.triggerSuggest');
}
}
}


}
2 changes: 1 addition & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,12 @@ export async function activate(context: vscode.ExtensionContext) {
// auto-complete
console.log('activate the auto complete(snippets and lint) feature');
const tipsProvider = new TerraformTipsProvider();
context.subscriptions.push(vscode.languages.registerCompletionItemProvider(TF_MODE, tipsProvider, '.'));
context.subscriptions.push(
vscode.workspace.onDidChangeTextDocument((event) => {
tipsProvider.handleCharacterEvent(event);
})
);
context.subscriptions.push(vscode.languages.registerCompletionItemProvider(TF_MODE, tipsProvider));
context.subscriptions.push(vscode.languages.registerDefinitionProvider(TF_MODE, new TerraformResDocProvider()));

// import-resource
Expand Down

0 comments on commit fbf8e98

Please sign in to comment.