printer: implement a working version
This commit is contained in:
parent
5918e3592b
commit
958093df59
@ -3,30 +3,38 @@ package printer
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/fatih/hcl/ast"
|
||||
)
|
||||
|
||||
const (
|
||||
blank = byte(' ')
|
||||
newline = byte('\n')
|
||||
tab = byte('\t')
|
||||
)
|
||||
|
||||
func (p *printer) printNode(n ast.Node) []byte {
|
||||
var buf bytes.Buffer
|
||||
|
||||
switch t := n.(type) {
|
||||
case *ast.ObjectList:
|
||||
fmt.Println("printing objectList", t)
|
||||
for _, item := range t.Items {
|
||||
for i, item := range t.Items {
|
||||
buf.Write(p.printObjectItem(item))
|
||||
if i != len(t.Items)-1 {
|
||||
buf.WriteByte(newline)
|
||||
}
|
||||
}
|
||||
case *ast.ObjectKey:
|
||||
fmt.Println("printing objectKey", t)
|
||||
buf.WriteString(t.Token.Text)
|
||||
case *ast.ObjectItem:
|
||||
fmt.Println("printing objectItem", t)
|
||||
buf.Write(p.printObjectItem(t))
|
||||
case *ast.LiteralType:
|
||||
buf.Write(p.printLiteral(t))
|
||||
buf.WriteString(t.Token.Text)
|
||||
case *ast.ListType:
|
||||
buf.Write(p.printList(t))
|
||||
case *ast.ObjectType:
|
||||
fmt.Println("printing ObjectType", t)
|
||||
buf.Write(p.printObjectType(t))
|
||||
default:
|
||||
fmt.Printf(" unknown type: %T\n", n)
|
||||
}
|
||||
@ -39,14 +47,12 @@ func (p *printer) printObjectItem(o *ast.ObjectItem) []byte {
|
||||
|
||||
for i, k := range o.Keys {
|
||||
buf.WriteString(k.Token.Text)
|
||||
if i != len(o.Keys)-1 || len(o.Keys) == 1 {
|
||||
buf.WriteString(" ")
|
||||
}
|
||||
buf.WriteByte(blank)
|
||||
|
||||
// reach end of key
|
||||
if i == len(o.Keys)-1 {
|
||||
buf.WriteString("=")
|
||||
buf.WriteString(" ")
|
||||
buf.WriteByte(blank)
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,6 +64,26 @@ func (p *printer) printLiteral(l *ast.LiteralType) []byte {
|
||||
return []byte(l.Token.Text)
|
||||
}
|
||||
|
||||
func (p *printer) printObjectType(o *ast.ObjectType) []byte {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString("{")
|
||||
buf.WriteByte(newline)
|
||||
|
||||
for _, item := range o.List.Items {
|
||||
// buf.WriteByte(tab)
|
||||
// buf.Write(p.printObjectItem(item))
|
||||
|
||||
a := p.printObjectItem(item)
|
||||
a = indent(a)
|
||||
buf.Write(a)
|
||||
|
||||
buf.WriteByte(newline)
|
||||
}
|
||||
|
||||
buf.WriteString("}")
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func (p *printer) printList(l *ast.ListType) []byte {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString("[")
|
||||
@ -65,20 +91,44 @@ func (p *printer) printList(l *ast.ListType) []byte {
|
||||
for i, item := range l.List {
|
||||
if item.Pos().Line != l.Lbrack.Line {
|
||||
// not same line
|
||||
buf.WriteString("\n")
|
||||
buf.WriteByte(newline)
|
||||
}
|
||||
|
||||
buf.WriteByte(tab)
|
||||
buf.Write(p.printNode(item))
|
||||
|
||||
if i != len(l.List)-1 {
|
||||
buf.WriteString(",")
|
||||
buf.WriteString(" ")
|
||||
buf.WriteByte(blank)
|
||||
} else if item.Pos().Line != l.Lbrack.Line {
|
||||
buf.WriteString(",")
|
||||
buf.WriteString("\n")
|
||||
buf.WriteByte(newline)
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteString("]")
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func writeBlank(buf io.ByteWriter, indent int) {
|
||||
for i := 0; i < indent; i++ {
|
||||
buf.WriteByte(blank)
|
||||
}
|
||||
}
|
||||
|
||||
func indent(buf []byte) []byte {
|
||||
splitted := bytes.Split(buf, []byte{newline})
|
||||
newBuf := make([]byte, len(splitted))
|
||||
for i, s := range splitted {
|
||||
s = append(s, 0)
|
||||
copy(s[1:], s[0:])
|
||||
s[0] = tab
|
||||
newBuf = append(newBuf, s...)
|
||||
|
||||
if i != len(splitted)-1 {
|
||||
newBuf = append(newBuf, newline)
|
||||
}
|
||||
}
|
||||
|
||||
return newBuf
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package printer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"text/tabwriter"
|
||||
|
||||
@ -15,24 +14,12 @@ type printer struct {
|
||||
}
|
||||
|
||||
func (p *printer) output() []byte {
|
||||
fmt.Println("STARTING OUTPUT")
|
||||
return p.printNode(p.node)
|
||||
}
|
||||
|
||||
// A Mode value is a set of flags (or 0). They control printing.
|
||||
type Mode uint
|
||||
|
||||
const (
|
||||
RawFormat Mode = 1 << iota // do not use a tabwriter; if set, UseSpaces is ignored
|
||||
TabIndent // use tabs for indentation independent of UseSpaces
|
||||
UseSpaces // use spaces instead of tabs for alignment
|
||||
)
|
||||
|
||||
// A Config node controls the output of Fprint.
|
||||
type Config struct {
|
||||
Mode Mode // default: 0
|
||||
Tabwidth int // default: 4
|
||||
Indent int // default: 0 (all code is indented at least by this much)
|
||||
SpaceWidth int // if set, it will use spaces instead of tabs for alignment
|
||||
}
|
||||
|
||||
func (c *Config) fprint(output io.Writer, node ast.Node) error {
|
||||
@ -41,32 +28,6 @@ func (c *Config) fprint(output io.Writer, node ast.Node) error {
|
||||
node: node,
|
||||
}
|
||||
|
||||
// TODO(arslan): implement this
|
||||
// redirect output through a trimmer to eliminate trailing whitespace
|
||||
// (Input to a tabwriter must be untrimmed since trailing tabs provide
|
||||
// formatting information. The tabwriter could provide trimming
|
||||
// functionality but no tabwriter is used when RawFormat is set.)
|
||||
// output = &trimmer{output: output}
|
||||
|
||||
// redirect output through a tabwriter if necessary
|
||||
if c.Mode&RawFormat == 0 {
|
||||
minwidth := c.Tabwidth
|
||||
|
||||
padchar := byte('\t')
|
||||
if c.Mode&UseSpaces != 0 {
|
||||
padchar = ' '
|
||||
}
|
||||
|
||||
twmode := tabwriter.DiscardEmptyColumns
|
||||
if c.Mode&TabIndent != 0 {
|
||||
minwidth = 0
|
||||
twmode |= tabwriter.TabIndent
|
||||
}
|
||||
|
||||
output = tabwriter.NewWriter(output, minwidth, c.Tabwidth, 1, padchar, twmode)
|
||||
}
|
||||
|
||||
// write printer result via tabwriter/trimmer to output
|
||||
if _, err := output.Write(p.output()); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -87,5 +48,5 @@ func (c *Config) Fprint(output io.Writer, node ast.Node) error {
|
||||
// Fprint "pretty-prints" an HCL node to output
|
||||
// It calls Config.Fprint with default settings.
|
||||
func Fprint(output io.Writer, node ast.Node) error {
|
||||
return (&Config{Tabwidth: 4}).Fprint(output, node)
|
||||
return (&Config{}).Fprint(output, node)
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package printer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
@ -9,7 +10,7 @@ import (
|
||||
|
||||
var listHCL = `foo = ["fatih", "arslan"]`
|
||||
var listHCL2 = `foo = [
|
||||
"fatih",
|
||||
"fatih",
|
||||
"arslan",
|
||||
]`
|
||||
|
||||
@ -58,8 +59,8 @@ output "web_ip" {
|
||||
`
|
||||
|
||||
func TestPrint(t *testing.T) {
|
||||
// node, err := parser.Parse([]byte(complexHcl))
|
||||
node, err := parser.Parse([]byte(listHCL2))
|
||||
node, err := parser.Parse([]byte(complexHcl))
|
||||
// node, err := parser.Parse([]byte(listHCL2))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -67,4 +68,6 @@ func TestPrint(t *testing.T) {
|
||||
if err := Fprint(os.Stdout, node); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
fmt.Println("")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user