2018-07-28 20:17:51 +00:00
|
|
|
package hclsyntax
|
|
|
|
|
|
|
|
import (
|
2019-09-09 23:08:19 +00:00
|
|
|
"github.com/hashicorp/hcl/v2"
|
2018-07-28 20:17:51 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// The methods in this file are all optional extension methods that serve to
|
|
|
|
// implement the methods of the same name on *hcl.File when its root body
|
|
|
|
// is provided by this package.
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// BlocksAtPos implements the method of the same name for an *hcl.File that
|
|
|
|
// is backed by a *Body.
|
|
|
|
func (b *Body) BlocksAtPos(pos hcl.Pos) []*hcl.Block {
|
|
|
|
list, _ := b.blocksAtPos(pos, true)
|
|
|
|
return list
|
|
|
|
}
|
|
|
|
|
|
|
|
// InnermostBlockAtPos implements the method of the same name for an *hcl.File
|
|
|
|
// that is backed by a *Body.
|
|
|
|
func (b *Body) InnermostBlockAtPos(pos hcl.Pos) *hcl.Block {
|
|
|
|
_, innermost := b.blocksAtPos(pos, false)
|
|
|
|
return innermost.AsHCLBlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
// OutermostBlockAtPos implements the method of the same name for an *hcl.File
|
|
|
|
// that is backed by a *Body.
|
|
|
|
func (b *Body) OutermostBlockAtPos(pos hcl.Pos) *hcl.Block {
|
|
|
|
return b.outermostBlockAtPos(pos).AsHCLBlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
// blocksAtPos is the internal engine of both BlocksAtPos and
|
|
|
|
// InnermostBlockAtPos, which both need to do the same logic but return a
|
|
|
|
// differently-shaped result.
|
|
|
|
//
|
|
|
|
// list is nil if makeList is false, avoiding an allocation. Innermost is
|
|
|
|
// always set, and if the returned list is non-nil it will always match the
|
|
|
|
// final element from that list.
|
|
|
|
func (b *Body) blocksAtPos(pos hcl.Pos, makeList bool) (list []*hcl.Block, innermost *Block) {
|
|
|
|
current := b
|
|
|
|
|
|
|
|
Blocks:
|
|
|
|
for current != nil {
|
|
|
|
for _, block := range current.Blocks {
|
|
|
|
wholeRange := hcl.RangeBetween(block.TypeRange, block.CloseBraceRange)
|
|
|
|
if wholeRange.ContainsPos(pos) {
|
|
|
|
innermost = block
|
|
|
|
if makeList {
|
|
|
|
list = append(list, innermost.AsHCLBlock())
|
|
|
|
}
|
|
|
|
current = block.Body
|
|
|
|
continue Blocks
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we fall out here then none of the current body's nested blocks
|
|
|
|
// contain the position we are looking for, and so we're done.
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// outermostBlockAtPos is the internal version of OutermostBlockAtPos that
|
|
|
|
// returns a hclsyntax.Block rather than an hcl.Block, allowing for further
|
|
|
|
// analysis if necessary.
|
|
|
|
func (b *Body) outermostBlockAtPos(pos hcl.Pos) *Block {
|
|
|
|
// This is similar to blocksAtPos, but simpler because we know it only
|
|
|
|
// ever needs to search the first level of nested blocks.
|
|
|
|
|
|
|
|
for _, block := range b.Blocks {
|
|
|
|
wholeRange := hcl.RangeBetween(block.TypeRange, block.CloseBraceRange)
|
|
|
|
if wholeRange.ContainsPos(pos) {
|
|
|
|
return block
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// AttributeAtPos implements the method of the same name for an *hcl.File
|
|
|
|
// that is backed by a *Body.
|
|
|
|
func (b *Body) AttributeAtPos(pos hcl.Pos) *hcl.Attribute {
|
|
|
|
return b.attributeAtPos(pos).AsHCLAttribute()
|
|
|
|
}
|
|
|
|
|
|
|
|
// attributeAtPos is the internal version of AttributeAtPos that returns a
|
|
|
|
// hclsyntax.Block rather than an hcl.Block, allowing for further analysis if
|
|
|
|
// necessary.
|
|
|
|
func (b *Body) attributeAtPos(pos hcl.Pos) *Attribute {
|
|
|
|
searchBody := b
|
|
|
|
_, block := b.blocksAtPos(pos, false)
|
|
|
|
if block != nil {
|
|
|
|
searchBody = block.Body
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, attr := range searchBody.Attributes {
|
|
|
|
if attr.SrcRange.ContainsPos(pos) {
|
|
|
|
return attr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// OutermostExprAtPos implements the method of the same name for an *hcl.File
|
|
|
|
// that is backed by a *Body.
|
|
|
|
func (b *Body) OutermostExprAtPos(pos hcl.Pos) hcl.Expression {
|
|
|
|
attr := b.attributeAtPos(pos)
|
|
|
|
if attr == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if !attr.Expr.Range().ContainsPos(pos) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return attr.Expr
|
|
|
|
}
|