Skip to content

Commit

Permalink
hcled: Introduce ContextDefRange (hashicorp#58)
Browse files Browse the repository at this point in the history
This can be used for looking up range of block definition
so that we can render it alongside attribute-agnostic errors
  • Loading branch information
radeksimko committed Nov 26, 2018
1 parent 0467c0c commit 67424e4
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 0 deletions.
18 changes: 18 additions & 0 deletions hcl/hclsyntax/navigation.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package hclsyntax
import (
"bytes"
"fmt"

"github.com/hashicorp/hcl2/hcl"
)

type navigation struct {
Expand Down Expand Up @@ -39,3 +41,19 @@ func (n navigation) ContextString(offset int) string {
}
return buf.String()
}

func (n navigation) ContextDefRange(offset int) hcl.Range {
var block *Block
for _, candidate := range n.root.Blocks {
if candidate.Range().ContainsOffset(offset) {
block = candidate
break
}
}

if block == nil {
return hcl.Range{}
}

return block.DefRange()
}
133 changes: 133 additions & 0 deletions hcl/hclsyntax/navigation_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package hclsyntax

import (
"fmt"
"strconv"
"testing"

"github.com/hashicorp/hcl2/hcl"
)

func TestNavigationContextString(t *testing.T) {
cfg := `
resource {
}
resource "random_type" {
}
resource "null_resource" "baz" {
name = "foo"
boz = {
one = "111"
two = "22222"
}
}
data "another" "baz" {
name = "foo"
boz = {
one = "111"
two = "22222"
}
}
`
file, diags := ParseConfig([]byte(cfg), "", hcl.Pos{Byte: 0, Line: 1, Column: 1})
if len(diags) != 0 {
fmt.Printf("offset %d\n", diags[0].Subject.Start.Byte)
t.Errorf("Unexpected diagnostics: %s", diags)
}
if file == nil {
t.Fatalf("Got nil file")
}
nav := file.Nav.(navigation)

testCases := []struct {
Offset int
Want string
}{
{0, ``},
{2, ``},
{4, `resource`},
{17, `resource "random_type"`},
{25, `resource "random_type"`},
{45, `resource "null_resource" "baz"`},
{142, `data "another" "baz"`},
{180, `data "another" "baz"`},
{99999, ``},
}

for _, tc := range testCases {
t.Run(strconv.Itoa(tc.Offset), func(t *testing.T) {
got := nav.ContextString(tc.Offset)

if got != tc.Want {
t.Errorf("wrong result\ngot: %s\nwant: %s", got, tc.Want)
}
})
}
}

func TestNavigationContextDefRange(t *testing.T) {
cfg := `
resource {
}
resource "random_type" {
}
resource "null_resource" "baz" {
name = "foo"
boz = {
one = "111"
two = "22222"
}
}
data "another" "baz" {
name = "foo"
boz = {
one = "111"
two = "22222"
}
}
`
file, diags := ParseConfig([]byte(cfg), "", hcl.Pos{Byte: 0, Line: 1, Column: 1})
if len(diags) != 0 {
fmt.Printf("offset %d\n", diags[0].Subject.Start.Byte)
t.Errorf("Unexpected diagnostics: %s", diags)
}
if file == nil {
t.Fatalf("Got nil file")
}
nav := file.Nav.(navigation)

testCases := []struct {
Offset int
WantRange hcl.Range
}{
{0, hcl.Range{}},
{2, hcl.Range{}},
{4, hcl.Range{Filename: "", Start: hcl.Pos{Line: 4, Column: 1, Byte: 3}, End: hcl.Pos{Line: 4, Column: 11, Byte: 13}}},
{17, hcl.Range{Filename: "", Start: hcl.Pos{Line: 7, Column: 1, Byte: 17}, End: hcl.Pos{Line: 7, Column: 25, Byte: 41}}},
{25, hcl.Range{Filename: "", Start: hcl.Pos{Line: 7, Column: 1, Byte: 17}, End: hcl.Pos{Line: 7, Column: 25, Byte: 41}}},
{45, hcl.Range{Filename: "", Start: hcl.Pos{Line: 10, Column: 1, Byte: 45}, End: hcl.Pos{Line: 10, Column: 33, Byte: 77}}},
{142, hcl.Range{Filename: "", Start: hcl.Pos{Line: 18, Column: 1, Byte: 142}, End: hcl.Pos{Line: 18, Column: 23, Byte: 164}}},
{180, hcl.Range{Filename: "", Start: hcl.Pos{Line: 18, Column: 1, Byte: 142}, End: hcl.Pos{Line: 18, Column: 23, Byte: 164}}},
{99999, hcl.Range{}},
}

for _, tc := range testCases {
t.Run(strconv.Itoa(tc.Offset), func(t *testing.T) {
got := nav.ContextDefRange(tc.Offset)

if got != tc.WantRange {
t.Errorf("wrong range\ngot: %#v\nwant: %#v", got, tc.WantRange)
}
})
}
}
4 changes: 4 additions & 0 deletions hcl/hclsyntax/structure.go
Original file line number Diff line number Diff line change
Expand Up @@ -384,3 +384,7 @@ func (b *Block) walkChildNodes(w internalWalkFunc) {
func (b *Block) Range() hcl.Range {
return hcl.RangeBetween(b.TypeRange, b.CloseBraceRange)
}

func (b *Block) DefRange() hcl.Range {
return hcl.RangeBetween(b.TypeRange, b.OpenBraceRange)
}
14 changes: 14 additions & 0 deletions hcled/navigation.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,17 @@ func ContextString(file *hcl.File, offset int) string {
}
return ""
}

type contextDefRanger interface {
ContextDefRange(offset int) hcl.Range
}

func ContextDefRange(file *hcl.File, offset int) hcl.Range {
if cser, ok := file.Nav.(contextDefRanger); ok {
defRange := cser.ContextDefRange(offset)
if !defRange.Empty() {
return defRange
}
}
return file.Body.MissingItemRange()
}

0 comments on commit 67424e4

Please sign in to comment.