terraform-ls icon indicating copy to clipboard operation
terraform-ls copied to clipboard

Recognize individual expressions when nested

Open radeksimko opened this issue 4 years ago • 0 comments

Background (current state)

Through the logic in hcl-lang/schema and related schema in terraform-schema we currently provide completion, hover and semantic highlighting for the outermost expression (with a few exceptions for HCL objects and tuples) and generally don't take into account (potentially infinite) nesting.

Completion

resource "aws_instance" "example" {
  ami = # HERE
  depends_on = [ HERE ]
}

For ami we can provide completion of any string candidates, for completion within depends_on brackets we can provide references to other resources and data sources.

Hover

resource "aws_instance" "example" {
  ami = "test"
  depends_on = [ aws_vpc.test ]
}

When hovering over "test" we can match the string constant against schema (string type) and show relevant popup ("test" string). Similarly when hovering over [ aws_vpc.test ] we can match it against schema (set of references) and show relevant popup (set of references).

Semantic Tokens

resource "aws_instance" "example" {
  ami = "test"
  depends_on = [ aws_vpc.test ]
}

Here "test" is expected to be string (per schema) and aws_vpc.test is expected to be a reference (per schema), so LS will report relevant semantic tokens in both cases.

Use-cases

User would benefit from recognition of arbitrarily nested expressions in all relevant functions of the LS, as described in more detail below.

Completion

resource "aws_instance" "example" {
  ami = "ami-${HERE}"
  depends_on = [
    aws_vpc.test,
    # HERE
  ]
}

within ${} we should provide any compatible expressions (presumably all primitive types). for the second position we should provide any available references other than aws_vpc.test.

Hover

resource "aws_instance" "example" {
  ami = "ami-${data.aws_ami.example.test.image_id}"
  depends_on = [
    aws_vpc.test,
  ]
}

when hovering over data.aws_ami.example.test.id we display popup with details about the reference (string The ID of the AMI.) when hover over aws_vpc.test we display popup with details about the reference (resource).

Semantic Tokens

resource "aws_instance" "example" {
  ami = "ami-${data.aws_ami.example.test.image_id}"
  cpu_core_count = 2 * var.core_count
}

"ami-${data.aws_ami.example.test.image_id}" is highlighted as a template expression with ami- highlighted as string and data.aws_ami.example.test.image_id as reference.

2 * var.core_count is highlighted as multiplication expression with 2 highlighted as number and var.core_count as a reference.

Proposal

  • hashicorp/hcl-lang
    • [ ] Deprecate schema.TupleConsExpr
    • [ ] Create Expression interface in decoder such that completion for any expression type can be delegated and each type can also delegate completion of nested expressions to other expression types
    • [ ] Implement decoder.NewExpression(expr hcl.Expression, cons schema.ExprConstraints) Expression
    • [ ] Implement schema.ObjectTypeDeclItemExpr
    • [ ] Implement new completion candidate kinds?
      • [ ] lang.PrimitiveTypeDeclExpr
      • [ ] lang.ComplexTypeDeclExpr
      • [ ] lang.ObjectTypeDeclItemExpr
    • [ ] Implement schema.AnyExprOfType{Type: cty.Type} to act as an alias to
      • schema.LiteralTypeExpr
      • schema.TraversalExpr
      • (future) dynamically express function calls which return the Type
      • (future) dynamically express templates which return the Type
      • (future) dynamically express conditional expressions which return the Type
      • (future) dynamically express operator expressions which return the Type
    • [ ] Implement LiteralValueExpr as decoder.Expression
    • [ ] Implement ScopeTraversalExpr as decoder.Expression (for type declarations, references and keywords)
    • [ ] Implement TupleConsExpr as decoder.Expression
    • [ ] Implement ObjectConsExpr as decoder.Expression
    • [ ] Implement (basic) FunctionCallExpr as decoder.Expression (for type declarations)
    • [ ] Implement (basic) TemplateExpr as decoder.Expression
    • [ ] Implement (basic) TemplateWrapExpr as decoder.Expression
    • [ ] Plumb all new decoder.Expression types into PathDecoder - CandidatesAtPos
    • [ ] Plumb all new decoder.Expression types into PathDecoder - HoverAtPos
    • [ ] Plumb all new decoder.Expression types into PathDecoder - SemanticTokensInFile
type Expression interface {
	CandidatesAtPos(ctx context.Context, pos hcl.Pos) []lang.Candidate
	HoverAtPos(ctx context.Context, pos hcl.Pos) *lang.HoverData
	SemanticTokens(ctx context.Context) []lang.SemanticToken
	// TODO: Validate()
}

Prototype WIP: https://github.com/hashicorp/hcl-lang/commit/d21a86326111de083c8adea196252d7bc55d42c5

radeksimko avatar May 07 '21 13:05 radeksimko