Skip to content

Commit

Permalink
decoder: Add support for Set as Constraint (#194)
Browse files Browse the repository at this point in the history
* decoder: Implement completion for Set

* decoder: Implement hover for Set

* decoder: Implement semantic tokens for Set

* decoder: Implement reference origins for Set

* decoder: Implement reference targets for Set

* decoder: Test semantic tokens for Set

* decoder: Test hover for Set

* decoder: Test completion for Set

* decoder: Use EmptyCompletionData for Set

* Apply suggestions from code review

Co-authored-by: Radek Simko <radek.simko@gmail.com>

---------

Co-authored-by: Daniel Banck <daniel@dbanck.de>
Co-authored-by: Daniel Banck <dbanck@users.noreply.github.com>
  • Loading branch information
3 people authored Mar 13, 2023
1 parent 91de83d commit f51247a
Show file tree
Hide file tree
Showing 11 changed files with 1,416 additions and 27 deletions.
24 changes: 0 additions & 24 deletions decoder/expr_set.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
package decoder

import (
"context"

"github.com/hashicorp/hcl-lang/lang"
"github.com/hashicorp/hcl-lang/reference"
"github.com/hashicorp/hcl-lang/schema"
"github.com/hashicorp/hcl/v2"
)
Expand All @@ -14,23 +10,3 @@ type Set struct {
cons schema.Set
pathCtx *PathContext
}

func (s Set) CompletionAtPos(ctx context.Context, pos hcl.Pos) []lang.Candidate {
// TODO
return nil
}

func (s Set) HoverAtPos(ctx context.Context, pos hcl.Pos) *lang.HoverData {
// TODO
return nil
}

func (s Set) SemanticTokens(ctx context.Context) []lang.SemanticToken {
// TODO
return nil
}

func (s Set) ReferenceOrigins(ctx context.Context, allowSelfRefs bool) reference.Origins {
// TODO
return nil
}
88 changes: 88 additions & 0 deletions decoder/expr_set_completion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package decoder

import (
"context"
"fmt"

"github.com/hashicorp/hcl-lang/lang"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
)

func (set Set) CompletionAtPos(ctx context.Context, pos hcl.Pos) []lang.Candidate {
if isEmptyExpression(set.expr) {
label := "[ ]"

if set.cons.Elem != nil {
label = fmt.Sprintf("[ %s ]", set.cons.Elem.FriendlyName())
}

d := set.cons.EmptyCompletionData(1, 0)

return []lang.Candidate{
{
Label: label,
Detail: set.cons.FriendlyName(),
Kind: lang.SetCandidateKind,
Description: set.cons.Description,
TextEdit: lang.TextEdit{
NewText: d.NewText,
Snippet: d.Snippet,
Range: hcl.Range{
Filename: set.expr.Range().Filename,
Start: pos,
End: pos,
},
},
TriggerSuggest: d.TriggerSuggest,
},
}
}

eType, ok := set.expr.(*hclsyntax.TupleConsExpr)
if !ok {
return []lang.Candidate{}
}

if set.cons.Elem == nil {
return []lang.Candidate{}
}

betweenBraces := hcl.Range{
Filename: eType.Range().Filename,
Start: eType.OpenRange.End,
End: eType.Range().End,
}

if betweenBraces.ContainsPos(pos) {
if len(eType.Exprs) == 0 {
expr := newEmptyExpressionAtPos(eType.Range().Filename, pos)
return newExpression(set.pathCtx, expr, set.cons.Elem).CompletionAtPos(ctx, pos)
}

// TODO: depending on set.cons.Elem (Keyword, LiteralValue, Reference),
// filter out declared elements to provide uniqueness as that is the nature of set.
// See https://github.com/hashicorp/hcl-lang/issues/225

for _, elemExpr := range eType.Exprs {
// We cannot trust ranges of empty expressions, so we imply
// that invalid configuration follows and we stop here
// e.g. for completion between commas [keyword, ,keyword]
if isEmptyExpression(elemExpr) {
break
}
// We overshot the position and stop
if elemExpr.Range().Start.Byte > pos.Byte {
break
}
if elemExpr.Range().ContainsPos(pos) || elemExpr.Range().End.Byte == pos.Byte {
return newExpression(set.pathCtx, elemExpr, set.cons.Elem).CompletionAtPos(ctx, pos)
}
}

expr := newEmptyExpressionAtPos(eType.Range().Filename, pos)
return newExpression(set.pathCtx, expr, set.cons.Elem).CompletionAtPos(ctx, pos)
}

return []lang.Candidate{}
}
Loading

0 comments on commit f51247a

Please sign in to comment.