in internal/langserver/handlers/hover/hover.go [21:128]
func HoverAtPos(ctx context.Context, data []byte, filename string, pos hcl.Pos, logger *log.Logger, sender telemetry.Sender) *lsp.Hover {
file, _ := hclsyntax.ParseConfig(data, filename, hcl.InitialPos)
body, isHcl := file.Body.(*hclsyntax.Body)
if !isHcl {
logger.Printf("file is not hcl")
return nil
}
block := parser.BlockAtPos(body, pos)
if block != nil && len(block.Labels) != 0 && strings.HasPrefix(block.Labels[0], "azapi") {
resourceName := fmt.Sprintf("%s.%s", block.Type, block.Labels[0])
resource := tfschema.GetResourceSchema(resourceName)
if resource == nil {
return nil
}
// hover on an attribute
if attribute := parser.AttributeAtPos(block, pos); attribute != nil {
property := resource.GetProperty(attribute.Name)
if property == nil {
return nil
}
switch attribute.Name {
case "parent_id":
if parser.ContainsPos(attribute.NameRange, pos) {
typeAttribute := parser.AttributeWithName(block, "type")
if typeAttribute != nil {
if typeValue := parser.ToLiteral(typeAttribute.Expr); typeValue != nil && len(*typeValue) != 0 {
parentType := GetParentType(*typeValue)
return Hover(property.Name, property.Modifier, property.Type,
fmt.Sprintf("The ID of `%s` which is the parent resource in which this resource is created.", parentType), attribute.NameRange)
}
}
}
case "body":
if parser.ContainsPos(attribute.NameRange, pos) {
return Hover(property.Name, property.Modifier, property.Type, property.Description, attribute.NameRange)
}
bodyDef := tfschema.BodyDefinitionFromBlock(block)
if bodyDef == nil {
return nil
}
hclNode := parser.JsonEncodeExpressionToHclNode(data, attribute.Expr)
if hclNode == nil {
tokens, _ := hclsyntax.LexExpression(data[attribute.Expr.Range().Start.Byte:attribute.Expr.Range().End.Byte], filename, attribute.Expr.Range().Start)
hclNode = parser.BuildHclNode(tokens)
}
if hclNode == nil {
break
}
return hoverOnBody(hclNode, pos, bodyDef)
default:
if !parser.ContainsPos(attribute.NameRange, pos) {
return nil
}
return Hover(property.Name, property.Modifier, property.Type, property.Description, attribute.NameRange)
}
}
// hover on a block
if nestedBlock := parser.BlockAtPos(block.Body, pos); nestedBlock != nil {
property := resource.GetProperty(nestedBlock.Type)
if property == nil {
return nil
}
if attribute := parser.AttributeAtPos(nestedBlock, pos); attribute != nil {
for _, p := range property.NestedProperties {
if p.Name == attribute.Name {
return Hover(p.Name, p.Modifier, p.Type, p.Description, attribute.NameRange)
}
}
} else {
return Hover(property.Name, property.Modifier, property.Type, property.Description, nestedBlock.TypeRange)
}
}
// hover on the resource definition
if block.DefRange().ContainsPos(pos) {
typeValue := ""
if typeAttribute := parser.AttributeWithName(block, "type"); typeAttribute != nil {
if v := parser.ToLiteral(typeAttribute.Expr); v != nil && len(*v) != 0 {
typeValue = *v
}
}
azureResourceType := ""
if parts := strings.Split(typeValue, "@"); len(parts) >= 2 {
azureResourceType = parts[0]
}
if azureResourceType == "" {
return nil
}
sender.SendEvent(ctx, "textDocument/hover", map[string]interface{}{
"kind": "resource-definition",
"type": typeValue,
})
return &lsp.Hover{
Range: ilsp.HCLRangeToLSP(block.DefRange()),
Contents: lsp.MarkupContent{
Kind: lsp.Markdown,
Value: fmt.Sprintf(`%s %s '%s'
[View Documentation](https://learn.microsoft.com/en-us/azure/templates/%s?pivots=deployment-language-terraform)`, block.Type, strings.Join(block.Labels, "."), typeValue, strings.ToLower(azureResourceType)),
},
}
}
}
return nil
}