Skip to content

Commit

Permalink
Hover Expresisons
Browse files Browse the repository at this point in the history
  • Loading branch information
jpogran committed Sep 27, 2022
1 parent 9da56b1 commit 2da2a6d
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 34 deletions.
73 changes: 57 additions & 16 deletions decoder/hover.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
package decoder

import (
"context"
"fmt"
"sort"
"strings"

"github.com/zclconf/go-cty/cty"

icontext "github.com/hashicorp/hcl-lang/context"
"github.com/hashicorp/hcl-lang/lang"
"github.com/hashicorp/hcl-lang/reference"
"github.com/hashicorp/hcl-lang/schema"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/zclconf/go-cty/cty"
)

func (d *PathDecoder) HoverAtPos(filename string, pos hcl.Pos) (*lang.HoverData, error) {
func (d *PathDecoder) HoverAtPos(ctx context.Context, filename string, pos hcl.Pos) (*lang.HoverData, error) {
f, err := d.fileByName(filename)
if err != nil {
return nil, err
Expand All @@ -28,23 +31,46 @@ func (d *PathDecoder) HoverAtPos(filename string, pos hcl.Pos) (*lang.HoverData,
return nil, &NoSchemaError{}
}

data, err := d.hoverAtPos(rootBody, d.pathCtx.Schema, pos)
data, err := d.hoverAtPos(ctx, rootBody, d.pathCtx.Schema, pos)
if err != nil {
return nil, err
}

return data, nil
}

func (d *PathDecoder) hoverAtPos(body *hclsyntax.Body, bodySchema *schema.BodySchema, pos hcl.Pos) (*lang.HoverData, error) {
func (d *PathDecoder) hoverAtPos(ctx context.Context, body *hclsyntax.Body, bodySchema *schema.BodySchema, pos hcl.Pos) (*lang.HoverData, error) {
if bodySchema == nil {
return nil, nil
}

filename := body.Range().Filename

if bodySchema.Extensions != nil {
ctx = icontext.WithExtensions(ctx, bodySchema.Extensions)
if bodySchema.Extensions.Count {
if _, ok := body.Attributes["count"]; ok {
// append to context we need count provided
ctx = icontext.WithActiveCount(ctx)
}
}
}

for name, attr := range body.Attributes {
if attr.Range().ContainsPos(pos) {

if bodySchema.Extensions != nil {
if name == "count" && bodySchema.Extensions.Count {
return &lang.HoverData{
Content: lang.MarkupContent{
Kind: lang.MarkdownKind,
Value: "**count** _optional, number_\n\nThe distinct index number (starting with 0) corresponding to the instance",
},
Range: attr.Range(),
}, nil
}
}

aSchema, ok := bodySchema.Attributes[attr.Name]
if !ok {
if bodySchema.AnyAttribute == nil {
Expand All @@ -66,7 +92,7 @@ func (d *PathDecoder) hoverAtPos(body *hclsyntax.Body, bodySchema *schema.BodySc

if attr.Expr.Range().ContainsPos(pos) {
exprCons := ExprConstraints(aSchema.Expr)
data, err := d.hoverDataForExpr(attr.Expr, exprCons, 0, pos)
data, err := d.hoverDataForExpr(ctx, attr.Expr, exprCons, 0, pos)
if err != nil {
return nil, &PositionalError{
Filename: filename,
Expand Down Expand Up @@ -128,7 +154,7 @@ func (d *PathDecoder) hoverAtPos(body *hclsyntax.Body, bodySchema *schema.BodySc
return nil, err
}

return d.hoverAtPos(block.Body, mergedSchema, pos)
return d.hoverAtPos(ctx, block.Body, mergedSchema, pos)
}
}
}
Expand Down Expand Up @@ -215,7 +241,7 @@ func (d *PathDecoder) hoverContentForBlock(bType string, schema *schema.BlockSch
}
}

func (d *PathDecoder) hoverDataForExpr(expr hcl.Expression, constraints ExprConstraints, nestingLvl int, pos hcl.Pos) (*lang.HoverData, error) {
func (d *PathDecoder) hoverDataForExpr(ctx context.Context, expr hcl.Expression, constraints ExprConstraints, nestingLvl int, pos hcl.Pos) (*lang.HoverData, error) {
switch e := expr.(type) {
case *hclsyntax.ScopeTraversalExpr:
kw, ok := constraints.KeywordExpr()
Expand All @@ -232,6 +258,21 @@ func (d *PathDecoder) hoverDataForExpr(expr hcl.Expression, constraints ExprCons
}, nil
}

address, _ := lang.TraversalToAddress(e.AsTraversal())
if address.Equals(lang.Address{
lang.RootStep{
Name: "count",
},
lang.AttrStep{
Name: "index",
},
}) && icontext.ActiveCountFromContext(ctx) {
return &lang.HoverData{
Content: lang.Markdown("**count.index** fooooo"),
Range: expr.Range(),
}, nil
}

tes, ok := constraints.TraversalExprs()
if ok {
content, err := d.hoverContentForTraversalExpr(e.AsTraversal(), tes)
Expand Down Expand Up @@ -261,7 +302,7 @@ func (d *PathDecoder) hoverDataForExpr(expr hcl.Expression, constraints ExprCons
}
case *hclsyntax.TemplateExpr:
if e.IsStringLiteral() {
data, err := d.hoverDataForExpr(e.Parts[0], constraints, nestingLvl, pos)
data, err := d.hoverDataForExpr(ctx, e.Parts[0], constraints, nestingLvl, pos)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -295,7 +336,7 @@ func (d *PathDecoder) hoverDataForExpr(expr hcl.Expression, constraints ExprCons
}
}
case *hclsyntax.TemplateWrapExpr:
data, err := d.hoverDataForExpr(e.Wrapped, constraints, nestingLvl, pos)
data, err := d.hoverDataForExpr(ctx, e.Wrapped, constraints, nestingLvl, pos)
if err != nil {
return nil, err
}
Expand All @@ -320,7 +361,7 @@ func (d *PathDecoder) hoverDataForExpr(expr hcl.Expression, constraints ExprCons
if ok {
for _, elemExpr := range e.Exprs {
if elemExpr.Range().ContainsPos(pos) {
return d.hoverDataForExpr(elemExpr, ExprConstraints(se.Elem), nestingLvl, pos)
return d.hoverDataForExpr(ctx, elemExpr, ExprConstraints(se.Elem), nestingLvl, pos)
}
}
content := fmt.Sprintf("_%s_", se.FriendlyName())
Expand All @@ -336,7 +377,7 @@ func (d *PathDecoder) hoverDataForExpr(expr hcl.Expression, constraints ExprCons
if ok {
for _, elemExpr := range e.Exprs {
if elemExpr.Range().ContainsPos(pos) {
return d.hoverDataForExpr(elemExpr, ExprConstraints(le.Elem), nestingLvl, pos)
return d.hoverDataForExpr(ctx, elemExpr, ExprConstraints(le.Elem), nestingLvl, pos)
}
}
content := fmt.Sprintf("_%s_", le.FriendlyName())
Expand All @@ -356,7 +397,7 @@ func (d *PathDecoder) hoverDataForExpr(expr hcl.Expression, constraints ExprCons
return nil, &ConstraintMismatch{elemExpr}
}
ec := ExprConstraints(te.Elems[i])
return d.hoverDataForExpr(elemExpr, ec, nestingLvl, pos)
return d.hoverDataForExpr(ctx, elemExpr, ec, nestingLvl, pos)
}
}
content := fmt.Sprintf("_%s_", te.FriendlyName())
Expand Down Expand Up @@ -393,7 +434,7 @@ func (d *PathDecoder) hoverDataForExpr(expr hcl.Expression, constraints ExprCons
case *hclsyntax.ObjectConsExpr:
objExpr, ok := constraints.ObjectExpr()
if ok {
return d.hoverDataForObjectExpr(e, objExpr, nestingLvl, pos)
return d.hoverDataForObjectExpr(ctx, e, objExpr, nestingLvl, pos)
}
mapExpr, ok := constraints.MapExpr()
if ok {
Expand Down Expand Up @@ -469,7 +510,7 @@ func (d *PathDecoder) hoverDataForExpr(expr hcl.Expression, constraints ExprCons
return nil, fmt.Errorf("unsupported expression (%T)", expr)
}

func (d *PathDecoder) hoverDataForObjectExpr(objExpr *hclsyntax.ObjectConsExpr, oe schema.ObjectExpr, nestingLvl int, pos hcl.Pos) (*lang.HoverData, error) {
func (d *PathDecoder) hoverDataForObjectExpr(ctx context.Context, objExpr *hclsyntax.ObjectConsExpr, oe schema.ObjectExpr, nestingLvl int, pos hcl.Pos) (*lang.HoverData, error) {
declaredAttributes := make(map[string]hclsyntax.Expression, 0)
for _, item := range objExpr.Items {
key, _ := item.KeyExpr.Value(nil)
Expand All @@ -485,7 +526,7 @@ func (d *PathDecoder) hoverDataForObjectExpr(objExpr *hclsyntax.ObjectConsExpr,
}

if item.ValueExpr.Range().ContainsPos(pos) {
return d.hoverDataForExpr(item.ValueExpr, ExprConstraints(attr.Expr), nestingLvl+1, pos)
return d.hoverDataForExpr(ctx, item.ValueExpr, ExprConstraints(attr.Expr), nestingLvl+1, pos)
}

itemRng := hcl.RangeBetween(item.KeyExpr.Range(), item.ValueExpr.Range())
Expand Down Expand Up @@ -526,7 +567,7 @@ func (d *PathDecoder) hoverDataForObjectExpr(objExpr *hclsyntax.ObjectConsExpr,
attrData := ec.FriendlyName()

if attrExpr, ok := declaredAttributes[name]; ok {
data, err := d.hoverDataForExpr(attrExpr, ExprConstraints(ec), nestingLvl+1, pos)
data, err := d.hoverDataForExpr(ctx, attrExpr, ExprConstraints(ec), nestingLvl+1, pos)
if err == nil && data.Content.Value != "" {
attrData = data.Content.Value
}
Expand Down
12 changes: 8 additions & 4 deletions decoder/hover_expressions_test.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
package decoder

import (
"context"
"errors"
"fmt"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/zclconf/go-cty-debug/ctydebug"
"github.com/zclconf/go-cty/cty"

"github.com/hashicorp/hcl-lang/lang"
"github.com/hashicorp/hcl-lang/reference"
"github.com/hashicorp/hcl-lang/schema"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/zclconf/go-cty-debug/ctydebug"
"github.com/zclconf/go-cty/cty"
)

func TestDecoder_HoverAtPos_expressions(t *testing.T) {
Expand Down Expand Up @@ -1282,7 +1284,8 @@ _object_`),
},
})

data, err := d.HoverAtPos("test.tf", tc.pos)
ctx := context.Background()
data, err := d.HoverAtPos(ctx, "test.tf", tc.pos)

if err != nil {
if tc.expectedErr != nil && !errors.As(err, &tc.expectedErr) {
Expand Down Expand Up @@ -1483,7 +1486,8 @@ func TestDecoder_HoverAtPos_traversalExpressions(t *testing.T) {
},
})

data, err := d.HoverAtPos("test.tf", tc.pos)
ctx := context.Background()
data, err := d.HoverAtPos(ctx, "test.tf", tc.pos)
if err != nil {
if tc.expectedErr != nil && !errors.As(err, &tc.expectedErr) {
t.Fatalf("unexpected error: %s\nexpected: %s\n",
Expand Down
Loading

0 comments on commit 2da2a6d

Please sign in to comment.