diff --git a/helper/file.go b/helper/file.go index ef60ce9..12453b6 100644 --- a/helper/file.go +++ b/helper/file.go @@ -88,7 +88,11 @@ func FindOffset(fileText string, line, column int) int { } func DumpLog(res interface{}) { - log.Debug(spew.Sdump(res)) + result := spew.Sdump(res) + strSlice:=strings.Split(result, "\n") + for _, s := range strSlice { + log.Debug(s) + } } func ParseVariables(vars hcl.Traversal, configVars map[string]*configs.Variable, completionItems []lsp.CompletionItem) []lsp.CompletionItem { diff --git a/tfstructs/diags.go b/tfstructs/diags.go index 434bbae..238b842 100644 --- a/tfstructs/diags.go +++ b/tfstructs/diags.go @@ -2,6 +2,7 @@ package tfstructs import ( "fmt" + "os" v2 "github.com/hashicorp/hcl/v2" "github.com/hashicorp/terraform/configs" "github.com/zclconf/go-cty/cty" @@ -13,6 +14,7 @@ import ( terragruntOptions "github.com/gruntwork-io/terragrunt/options" oldHCL2 "github.com/hashicorp/hcl2/hcl" "github.com/juliosueiras/terraform-lsp/memfs" + //"github.com/juliosueiras/terraform-lsp/helper" "github.com/sourcegraph/go-lsp" "github.com/spf13/afero" "path/filepath" @@ -131,10 +133,22 @@ func GetDiagnostics(fileName string, originalFile string) []lsp.Diagnostic { resourceTypes[v.Type][v.Name] = cty.DynamicVal } + targetDir := filepath.Dir(originalFileNameDecoded) + resultedDir := "" + searchLevel := 4 + for dir := targetDir; dir != "" && searchLevel != 0; dir = filepath.Dir(dir) { + if _, err := os.Stat(filepath.Join(dir, ".terraform")); err == nil { + resultedDir = dir + break + } + searchLevel -= 1 + } + variables := map[string]cty.Value{ "path": cty.ObjectVal(map[string]cty.Value{ "cwd": cty.StringVal(filepath.Dir(originalFileNameDecoded)), "module": cty.StringVal(filepath.Dir(originalFileNameDecoded)), + "root": cty.StringVal(resultedDir), }), "var": cty.DynamicVal, // Need to check for undefined vars "module": cty.DynamicVal, @@ -195,6 +209,31 @@ func GetDiagnostics(fileName string, originalFile string) []lsp.Diagnostic { Source: "Terraform", }) } + + for _, local := range cfg.Locals { + diags := GetLocalsForDiags(*local, filepath.Dir(originalFile), variables) + + if diags != nil { + for _, diag := range diags { + result = append(result, lsp.Diagnostic{ + Severity: lsp.DiagnosticSeverity(diag.Severity), + Message: diag.Detail, + Range: lsp.Range{ + Start: lsp.Position{ + Line: diag.Subject.Start.Line - 1, + Character: diag.Subject.Start.Column - 1, + }, + End: lsp.Position{ + Line: diag.Subject.End.Line - 1, + Character: diag.Subject.End.Column - 1, + }, + }, + Source: "Terraform Schema", + }) + } + } + } + // cfg, diags := configload.NewLoader(&configload.Config{ // ModulesDir: ".terraform/modules", // }) diff --git a/tfstructs/main.go b/tfstructs/main.go index b688c40..20e8578 100644 --- a/tfstructs/main.go +++ b/tfstructs/main.go @@ -37,6 +37,26 @@ func GetModuleVariables(moduleAddr string, config hcl.Body, targetDir string) (m return t.Variables, true } +func GetLocalsForDiags(local configs.Local, targetDir string, variables map[string]cty.Value) hcl.Diagnostics { + scope := lang.Scope{} + + //_, diags := scope.EvalExpr(local, cty.DynamicPseudoType) + _, diags := local.Expr.Value( + &hcl.EvalContext{ + // Build Full Tree + Variables: variables, + Functions: scope.Functions(), + }, + ) + //res, _, diags := hcldec.PartialDecode(config, nil, &hcl.EvalContext{ + // // Build Full Tree + // Variables: variables, + // Functions: scope.Functions(), + //}) + + return diags +} + func GetResourceSchemaForDiags(resourceType string, config hcl.Body, targetDir string, overrideProvider string, variables map[string]cty.Value) *TerraformSchema { var provider *Client var err error diff --git a/tfstructs/vars.go b/tfstructs/vars.go index 7a68419..0fbd251 100644 --- a/tfstructs/vars.go +++ b/tfstructs/vars.go @@ -7,9 +7,13 @@ import ( "github.com/hashicorp/terraform/addrs" "github.com/hashicorp/terraform/configs" "github.com/juliosueiras/terraform-lsp/hclstructs" + "github.com/zclconf/go-cty/cty" "github.com/juliosueiras/terraform-lsp/helper" + "github.com/hashicorp/terraform/lang" "github.com/sourcegraph/go-lsp" "reflect" + "path/filepath" + "os" ) type GetVarAttributeRequest struct { @@ -21,6 +25,36 @@ type GetVarAttributeRequest struct { } func GetVarAttributeCompletion(request GetVarAttributeRequest) []lsp.CompletionItem { + scope := lang.Scope{} + + targetDir := filepath.Dir(request.FileDir) + resultedDir := "" + searchLevel := 4 + for dir := targetDir; dir != "" && searchLevel != 0; dir = filepath.Dir(dir) { + if _, err := os.Stat(filepath.Join(dir, ".terraform")); err == nil { + resultedDir = dir + break + } + searchLevel -= 1 + } + + variables := map[string]cty.Value{ + "path": cty.ObjectVal(map[string]cty.Value{ + "cwd": cty.StringVal(filepath.Dir(request.FileDir)), + "module": cty.StringVal(filepath.Dir(request.FileDir)), + "root": cty.StringVal(resultedDir), + }), + "var": cty.DynamicVal, // Need to check for undefined vars + "module": cty.DynamicVal, + "local": cty.DynamicVal, + "each": cty.DynamicVal, + "count": cty.DynamicVal, + "terraform": cty.ObjectVal(map[string]cty.Value{ + "workspace": cty.StringVal(""), + }), + } + + if request.Variables.RootName() == "var" { vars := request.Variables @@ -35,7 +69,18 @@ func GetVarAttributeCompletion(request GetVarAttributeRequest) []lsp.CompletionI } } - origType := reflect.TypeOf(found.Expr) + + testVal, _ := found.Expr.Value( + &hcl.EvalContext{ + // Build Full Tree + Variables: variables, + Functions: scope.Functions(), + }, + ) + + helper.DumpLog(testVal) + + origType := reflect.TypeOf(found.Expr) if origType == hclstructs.ObjectConsExpr() { items := found.Expr.(*hclsyntax.ObjectConsExpr).Items @@ -61,6 +106,10 @@ func GetVarAttributeCompletion(request GetVarAttributeRequest) []lsp.CompletionI } } + helper.DumpLog(request.Variables[2:]) + helper.DumpLog(testVal.Type()) + request.Result = append(request.Result, helper.ParseOtherAttr(request.Variables[2:], testVal.Type(), request.Result)...) + return request.Result } else if len(request.Variables) == 1 {