Skip to content

Commit

Permalink
fix: allow any namespaced functions besides provider:: prefixed ones
Browse files Browse the repository at this point in the history
  • Loading branch information
ansgarm committed Mar 22, 2024
1 parent 2c9fc31 commit 607aba1
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 12 deletions.
129 changes: 127 additions & 2 deletions decoder/expr_any_completion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,21 @@ func TestCompletionAtPos_exprAny_functions(t *testing.T) {
},
},
},
{
Label: "namespaced::function",
Description: lang.Markdown("Example for hcl valid namespaced function"),
Detail: "namespaced::function() bool",
Kind: lang.FunctionCandidateKind,
TextEdit: lang.TextEdit{
NewText: "namespaced::function()",
Snippet: "namespaced::function(${0})",
Range: hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 1, Column: 8, Byte: 7},
End: hcl.Pos{Line: 1, Column: 8, Byte: 7},
},
},
},
{
Label: "provider::framework::example",
Detail: "provider::framework::example(input string) string",
Expand Down Expand Up @@ -222,6 +237,21 @@ func TestCompletionAtPos_exprAny_functions(t *testing.T) {
},
},
},
{
Label: "namespaced::function",
Description: lang.Markdown("Example for hcl valid namespaced function"),
Detail: "namespaced::function() bool",
Kind: lang.FunctionCandidateKind,
TextEdit: lang.TextEdit{
NewText: "namespaced::function()",
Snippet: "namespaced::function(${0})",
Range: hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 1, Column: 8, Byte: 7},
End: hcl.Pos{Line: 1, Column: 8, Byte: 7},
},
},
},
{
Label: "provider::framework::example",
Detail: "provider::framework::example(input string) string",
Expand Down Expand Up @@ -401,6 +431,21 @@ func TestCompletionAtPos_exprAny_functions(t *testing.T) {
},
},
},
{
Label: "namespaced::function",
Description: lang.Markdown("Example for hcl valid namespaced function"),
Detail: "namespaced::function() bool",
Kind: lang.FunctionCandidateKind,
TextEdit: lang.TextEdit{
NewText: "namespaced::function()",
Snippet: "namespaced::function(${0})",
Range: hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 1, Column: 14, Byte: 15},
End: hcl.Pos{Line: 1, Column: 14, Byte: 15},
},
},
},
{
Label: "provider::framework::example",
Detail: "provider::framework::example(input string) string",
Expand Down Expand Up @@ -694,6 +739,21 @@ func TestCompletionAtPos_exprAny_functions(t *testing.T) {
},
},
},
{
Label: "namespaced::function",
Description: lang.Markdown("Example for hcl valid namespaced function"),
Detail: "namespaced::function() bool",
Kind: lang.FunctionCandidateKind,
TextEdit: lang.TextEdit{
NewText: "namespaced::function()",
Snippet: "namespaced::function(${0})",
Range: hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 1, Column: 22, Byte: 21},
End: hcl.Pos{Line: 1, Column: 22, Byte: 21},
},
},
},
{
Label: "provider::framework::example",
Detail: "provider::framework::example(input string) string",
Expand Down Expand Up @@ -951,6 +1011,21 @@ func TestCompletionAtPos_exprAny_functions(t *testing.T) {
},
},
},
{
Label: "namespaced::function",
Description: lang.Markdown("Example for hcl valid namespaced function"),
Detail: "namespaced::function() bool",
Kind: lang.FunctionCandidateKind,
TextEdit: lang.TextEdit{
NewText: "namespaced::function()",
Snippet: "namespaced::function(${0})",
Range: hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 1, Column: 22, Byte: 23},
End: hcl.Pos{Line: 1, Column: 22, Byte: 23},
},
},
},
{
Label: "provider::framework::example",
Detail: "provider::framework::example(input string) string",
Expand Down Expand Up @@ -1009,7 +1084,7 @@ func TestCompletionAtPos_exprAny_functions(t *testing.T) {
},
reference.Targets{},
`attr = provider::framewo`,
hcl.Pos{Line: 1, Column: 17, Byte: 16}, // cursor is after second colon
hcl.Pos{Line: 1, Column: 18, Byte: 17}, // cursor is after second colon
lang.CompleteCandidates([]lang.Candidate{
{
Label: "provider::framework::example",
Expand All @@ -1022,7 +1097,37 @@ func TestCompletionAtPos_exprAny_functions(t *testing.T) {
Range: hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 1, Column: 8, Byte: 7},
End: hcl.Pos{Line: 1, Column: 17, Byte: 16},
End: hcl.Pos{Line: 1, Column: 18, Byte: 17},
},
},
},
}),
},
{
"in namespaced function call with only one namespace",
map[string]*schema.AttributeSchema{
"attr": {
Constraint: schema.AnyExpression{
OfType: cty.String,
},
},
},
reference.Targets{},
`attr = namespaced::function()`,
hcl.Pos{Line: 1, Column: 23, Byte: 22}, // within "function"
lang.CompleteCandidates([]lang.Candidate{
{
Label: "namespaced::function",
Description: lang.Markdown("Example for hcl valid namespaced function"),
Detail: "namespaced::function() bool",
Kind: lang.FunctionCandidateKind,
TextEdit: lang.TextEdit{
NewText: "namespaced::function()",
Snippet: "namespaced::function(${0})",
Range: hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 1, Column: 8, Byte: 7},
End: hcl.Pos{Line: 1, Column: 30, Byte: 29},
},
},
},
Expand Down Expand Up @@ -1173,6 +1278,21 @@ func TestCompletionAtPos_exprAny_combinedExpressions(t *testing.T) {
},
},
},
{
Label: "namespaced::function",
Description: lang.Markdown("Example for hcl valid namespaced function"),
Detail: "namespaced::function() bool",
Kind: lang.FunctionCandidateKind,
TextEdit: lang.TextEdit{
NewText: "namespaced::function()",
Snippet: "namespaced::function(${0})",
Range: hcl.Range{
Filename: "test.tf",
Start: hcl.Pos{Line: 1, Column: 8, Byte: 7},
End: hcl.Pos{Line: 1, Column: 8, Byte: 7},
},
},
},
{
Label: "provider::framework::example",
Detail: "provider::framework::example(input string) string",
Expand Down Expand Up @@ -1452,6 +1572,11 @@ func testFunctionSignatures() map[string]schema.FunctionSignature {
Description: "Echoes given argument as result",
Detail: "bflad/framework 0.2.0",
},
"namespaced::function": {
Params: []function.Parameter{},
ReturnType: cty.Bool,
Description: "Example for hcl valid namespaced function",
},
}
}

Expand Down
16 changes: 6 additions & 10 deletions decoder/expr_function.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,7 @@ func (fe functionExpr) CompletionAtPos(ctx context.Context, pos hcl.Pos) []lang.
return fe.matchingFunctions(prefix, eType.Range())

case *hclsyntax.ExprSyntaxError:
// TODO: "provider:" does not jump here, seems to be some other expression?

// This range can range up until the end of the file in case of invalid config
// Note: this range can range up until the end of the file in case of invalid config
if eType.SrcRange.ContainsPos(pos) {
// we are somewhere in the range for this attribute but we don't have an expression range to check
// so we look back to check whether we are in a partially written provider defined function
Expand All @@ -82,13 +80,11 @@ func (fe functionExpr) CompletionAtPos(ctx context.Context, pos hcl.Pos) []lang.

recoveredIdentifier := append(recoveredPrefixBytes, recoveredSuffixBytes...)

// TODO: this is specific to Terraform provider defined functions, we should generalize this
// and not rely on the "provider:" prefix

// check if our recovered identifier starts with "provider:"
// Why just one colon? For no colons the parser would return a traversal expression
// and a single colon will be the first prefix of a future provider defined function
if bytes.HasPrefix(recoveredIdentifier, []byte("provider:")) {
// check if our recovered identifier contains "::"
// Why two colons? For no colons the parser would return a traversal expression
// and a single colon will apparently be treated as a traversal and a partial object expression
// (refer to this follow-up issue for more on that case: TODOTODOTODOTODOTODOTODOTODOTODO)
if bytes.Contains(recoveredIdentifier, []byte("::")) {

editRange := hcl.Range{
Filename: fe.expr.Range().Filename,
Expand Down

0 comments on commit 607aba1

Please sign in to comment.