Skip to content

Commit f235183

Browse files
committed
Hover Expresisons
1 parent 17d582c commit f235183

File tree

3 files changed

+174
-34
lines changed

3 files changed

+174
-34
lines changed

decoder/hover.go

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
package decoder
22

33
import (
4+
"context"
45
"fmt"
56
"sort"
67
"strings"
78

9+
"github.com/zclconf/go-cty/cty"
10+
11+
icontext "github.com/hashicorp/hcl-lang/context"
812
"github.com/hashicorp/hcl-lang/lang"
913
"github.com/hashicorp/hcl-lang/reference"
1014
"github.com/hashicorp/hcl-lang/schema"
1115
"github.com/hashicorp/hcl/v2"
1216
"github.com/hashicorp/hcl/v2/hclsyntax"
13-
"github.com/zclconf/go-cty/cty"
1417
)
1518

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

31-
data, err := d.hoverAtPos(rootBody, d.pathCtx.Schema, pos)
34+
data, err := d.hoverAtPos(ctx, rootBody, d.pathCtx.Schema, pos)
3235
if err != nil {
3336
return nil, err
3437
}
3538

3639
return data, nil
3740
}
3841

39-
func (d *PathDecoder) hoverAtPos(body *hclsyntax.Body, bodySchema *schema.BodySchema, pos hcl.Pos) (*lang.HoverData, error) {
42+
func (d *PathDecoder) hoverAtPos(ctx context.Context, body *hclsyntax.Body, bodySchema *schema.BodySchema, pos hcl.Pos) (*lang.HoverData, error) {
4043
if bodySchema == nil {
4144
return nil, nil
4245
}
4346

4447
filename := body.Range().Filename
4548

49+
if bodySchema.Extensions != nil {
50+
ctx = icontext.WithExtensions(ctx, bodySchema.Extensions)
51+
if bodySchema.Extensions.Count {
52+
if _, ok := body.Attributes["count"]; ok {
53+
// append to context we need count provided
54+
ctx = icontext.WithActiveCount(ctx)
55+
}
56+
}
57+
}
58+
4659
for name, attr := range body.Attributes {
4760
if attr.Range().ContainsPos(pos) {
61+
62+
if bodySchema.Extensions != nil {
63+
if name == "count" && bodySchema.Extensions.Count {
64+
return &lang.HoverData{
65+
Content: lang.MarkupContent{
66+
Kind: lang.MarkdownKind,
67+
Value: "**count** _optional, number_\n\nThe distinct index number (starting with 0) corresponding to the instance",
68+
},
69+
Range: attr.Range(),
70+
}, nil
71+
}
72+
}
73+
4874
aSchema, ok := bodySchema.Attributes[attr.Name]
4975
if !ok {
5076
if bodySchema.AnyAttribute == nil {
@@ -66,7 +92,7 @@ func (d *PathDecoder) hoverAtPos(body *hclsyntax.Body, bodySchema *schema.BodySc
6692

6793
if attr.Expr.Range().ContainsPos(pos) {
6894
exprCons := ExprConstraints(aSchema.Expr)
69-
data, err := d.hoverDataForExpr(attr.Expr, exprCons, 0, pos)
95+
data, err := d.hoverDataForExpr(ctx, attr.Expr, exprCons, 0, pos)
7096
if err != nil {
7197
return nil, &PositionalError{
7298
Filename: filename,
@@ -128,7 +154,7 @@ func (d *PathDecoder) hoverAtPos(body *hclsyntax.Body, bodySchema *schema.BodySc
128154
return nil, err
129155
}
130156

131-
return d.hoverAtPos(block.Body, mergedSchema, pos)
157+
return d.hoverAtPos(ctx, block.Body, mergedSchema, pos)
132158
}
133159
}
134160
}
@@ -215,7 +241,7 @@ func (d *PathDecoder) hoverContentForBlock(bType string, schema *schema.BlockSch
215241
}
216242
}
217243

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

261+
address, _ := lang.TraversalToAddress(e.AsTraversal())
262+
if address.Equals(lang.Address{
263+
lang.RootStep{
264+
Name: "count",
265+
},
266+
lang.AttrStep{
267+
Name: "index",
268+
},
269+
}) && icontext.ActiveCountFromContext(ctx) {
270+
return &lang.HoverData{
271+
Content: lang.Markdown("**count.index** fooooo"),
272+
Range: expr.Range(),
273+
}, nil
274+
}
275+
235276
tes, ok := constraints.TraversalExprs()
236277
if ok {
237278
content, err := d.hoverContentForTraversalExpr(e.AsTraversal(), tes)
@@ -261,7 +302,7 @@ func (d *PathDecoder) hoverDataForExpr(expr hcl.Expression, constraints ExprCons
261302
}
262303
case *hclsyntax.TemplateExpr:
263304
if e.IsStringLiteral() {
264-
data, err := d.hoverDataForExpr(e.Parts[0], constraints, nestingLvl, pos)
305+
data, err := d.hoverDataForExpr(ctx, e.Parts[0], constraints, nestingLvl, pos)
265306
if err != nil {
266307
return nil, err
267308
}
@@ -295,7 +336,7 @@ func (d *PathDecoder) hoverDataForExpr(expr hcl.Expression, constraints ExprCons
295336
}
296337
}
297338
case *hclsyntax.TemplateWrapExpr:
298-
data, err := d.hoverDataForExpr(e.Wrapped, constraints, nestingLvl, pos)
339+
data, err := d.hoverDataForExpr(ctx, e.Wrapped, constraints, nestingLvl, pos)
299340
if err != nil {
300341
return nil, err
301342
}
@@ -320,7 +361,7 @@ func (d *PathDecoder) hoverDataForExpr(expr hcl.Expression, constraints ExprCons
320361
if ok {
321362
for _, elemExpr := range e.Exprs {
322363
if elemExpr.Range().ContainsPos(pos) {
323-
return d.hoverDataForExpr(elemExpr, ExprConstraints(se.Elem), nestingLvl, pos)
364+
return d.hoverDataForExpr(ctx, elemExpr, ExprConstraints(se.Elem), nestingLvl, pos)
324365
}
325366
}
326367
content := fmt.Sprintf("_%s_", se.FriendlyName())
@@ -336,7 +377,7 @@ func (d *PathDecoder) hoverDataForExpr(expr hcl.Expression, constraints ExprCons
336377
if ok {
337378
for _, elemExpr := range e.Exprs {
338379
if elemExpr.Range().ContainsPos(pos) {
339-
return d.hoverDataForExpr(elemExpr, ExprConstraints(le.Elem), nestingLvl, pos)
380+
return d.hoverDataForExpr(ctx, elemExpr, ExprConstraints(le.Elem), nestingLvl, pos)
340381
}
341382
}
342383
content := fmt.Sprintf("_%s_", le.FriendlyName())
@@ -356,7 +397,7 @@ func (d *PathDecoder) hoverDataForExpr(expr hcl.Expression, constraints ExprCons
356397
return nil, &ConstraintMismatch{elemExpr}
357398
}
358399
ec := ExprConstraints(te.Elems[i])
359-
return d.hoverDataForExpr(elemExpr, ec, nestingLvl, pos)
400+
return d.hoverDataForExpr(ctx, elemExpr, ec, nestingLvl, pos)
360401
}
361402
}
362403
content := fmt.Sprintf("_%s_", te.FriendlyName())
@@ -393,7 +434,7 @@ func (d *PathDecoder) hoverDataForExpr(expr hcl.Expression, constraints ExprCons
393434
case *hclsyntax.ObjectConsExpr:
394435
objExpr, ok := constraints.ObjectExpr()
395436
if ok {
396-
return d.hoverDataForObjectExpr(e, objExpr, nestingLvl, pos)
437+
return d.hoverDataForObjectExpr(ctx, e, objExpr, nestingLvl, pos)
397438
}
398439
mapExpr, ok := constraints.MapExpr()
399440
if ok {
@@ -469,7 +510,7 @@ func (d *PathDecoder) hoverDataForExpr(expr hcl.Expression, constraints ExprCons
469510
return nil, fmt.Errorf("unsupported expression (%T)", expr)
470511
}
471512

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

487528
if item.ValueExpr.Range().ContainsPos(pos) {
488-
return d.hoverDataForExpr(item.ValueExpr, ExprConstraints(attr.Expr), nestingLvl+1, pos)
529+
return d.hoverDataForExpr(ctx, item.ValueExpr, ExprConstraints(attr.Expr), nestingLvl+1, pos)
489530
}
490531

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

528569
if attrExpr, ok := declaredAttributes[name]; ok {
529-
data, err := d.hoverDataForExpr(attrExpr, ExprConstraints(ec), nestingLvl+1, pos)
570+
data, err := d.hoverDataForExpr(ctx, attrExpr, ExprConstraints(ec), nestingLvl+1, pos)
530571
if err == nil && data.Content.Value != "" {
531572
attrData = data.Content.Value
532573
}

decoder/hover_expressions_test.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
package decoder
22

33
import (
4+
"context"
45
"errors"
56
"fmt"
67
"testing"
78

89
"github.com/google/go-cmp/cmp"
10+
"github.com/zclconf/go-cty-debug/ctydebug"
11+
"github.com/zclconf/go-cty/cty"
12+
913
"github.com/hashicorp/hcl-lang/lang"
1014
"github.com/hashicorp/hcl-lang/reference"
1115
"github.com/hashicorp/hcl-lang/schema"
1216
"github.com/hashicorp/hcl/v2"
1317
"github.com/hashicorp/hcl/v2/hclsyntax"
14-
"github.com/zclconf/go-cty-debug/ctydebug"
15-
"github.com/zclconf/go-cty/cty"
1618
)
1719

1820
func TestDecoder_HoverAtPos_expressions(t *testing.T) {
@@ -1282,7 +1284,8 @@ _object_`),
12821284
},
12831285
})
12841286

1285-
data, err := d.HoverAtPos("test.tf", tc.pos)
1287+
ctx := context.Background()
1288+
data, err := d.HoverAtPos(ctx, "test.tf", tc.pos)
12861289

12871290
if err != nil {
12881291
if tc.expectedErr != nil && !errors.As(err, &tc.expectedErr) {
@@ -1483,7 +1486,8 @@ func TestDecoder_HoverAtPos_traversalExpressions(t *testing.T) {
14831486
},
14841487
})
14851488

1486-
data, err := d.HoverAtPos("test.tf", tc.pos)
1489+
ctx := context.Background()
1490+
data, err := d.HoverAtPos(ctx, "test.tf", tc.pos)
14871491
if err != nil {
14881492
if tc.expectedErr != nil && !errors.As(err, &tc.expectedErr) {
14891493
t.Fatalf("unexpected error: %s\nexpected: %s\n",

0 commit comments

Comments
 (0)