printer: implement a working version
This commit is contained in:
parent
5918e3592b
commit
958093df59
@ -3,30 +3,38 @@ package printer
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
"github.com/fatih/hcl/ast"
|
"github.com/fatih/hcl/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
blank = byte(' ')
|
||||||
|
newline = byte('\n')
|
||||||
|
tab = byte('\t')
|
||||||
|
)
|
||||||
|
|
||||||
func (p *printer) printNode(n ast.Node) []byte {
|
func (p *printer) printNode(n ast.Node) []byte {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
|
||||||
switch t := n.(type) {
|
switch t := n.(type) {
|
||||||
case *ast.ObjectList:
|
case *ast.ObjectList:
|
||||||
fmt.Println("printing objectList", t)
|
for i, item := range t.Items {
|
||||||
for _, item := range t.Items {
|
|
||||||
buf.Write(p.printObjectItem(item))
|
buf.Write(p.printObjectItem(item))
|
||||||
|
if i != len(t.Items)-1 {
|
||||||
|
buf.WriteByte(newline)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case *ast.ObjectKey:
|
case *ast.ObjectKey:
|
||||||
fmt.Println("printing objectKey", t)
|
buf.WriteString(t.Token.Text)
|
||||||
case *ast.ObjectItem:
|
case *ast.ObjectItem:
|
||||||
fmt.Println("printing objectItem", t)
|
|
||||||
buf.Write(p.printObjectItem(t))
|
buf.Write(p.printObjectItem(t))
|
||||||
case *ast.LiteralType:
|
case *ast.LiteralType:
|
||||||
buf.Write(p.printLiteral(t))
|
buf.WriteString(t.Token.Text)
|
||||||
case *ast.ListType:
|
case *ast.ListType:
|
||||||
buf.Write(p.printList(t))
|
buf.Write(p.printList(t))
|
||||||
case *ast.ObjectType:
|
case *ast.ObjectType:
|
||||||
fmt.Println("printing ObjectType", t)
|
buf.Write(p.printObjectType(t))
|
||||||
default:
|
default:
|
||||||
fmt.Printf(" unknown type: %T\n", n)
|
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 {
|
for i, k := range o.Keys {
|
||||||
buf.WriteString(k.Token.Text)
|
buf.WriteString(k.Token.Text)
|
||||||
if i != len(o.Keys)-1 || len(o.Keys) == 1 {
|
buf.WriteByte(blank)
|
||||||
buf.WriteString(" ")
|
|
||||||
}
|
|
||||||
|
|
||||||
// reach end of key
|
// reach end of key
|
||||||
if i == len(o.Keys)-1 {
|
if i == len(o.Keys)-1 {
|
||||||
buf.WriteString("=")
|
buf.WriteString("=")
|
||||||
buf.WriteString(" ")
|
buf.WriteByte(blank)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +64,26 @@ func (p *printer) printLiteral(l *ast.LiteralType) []byte {
|
|||||||
return []byte(l.Token.Text)
|
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 {
|
func (p *printer) printList(l *ast.ListType) []byte {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteString("[")
|
buf.WriteString("[")
|
||||||
@ -65,20 +91,44 @@ func (p *printer) printList(l *ast.ListType) []byte {
|
|||||||
for i, item := range l.List {
|
for i, item := range l.List {
|
||||||
if item.Pos().Line != l.Lbrack.Line {
|
if item.Pos().Line != l.Lbrack.Line {
|
||||||
// not same line
|
// not same line
|
||||||
buf.WriteString("\n")
|
buf.WriteByte(newline)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buf.WriteByte(tab)
|
||||||
buf.Write(p.printNode(item))
|
buf.Write(p.printNode(item))
|
||||||
|
|
||||||
if i != len(l.List)-1 {
|
if i != len(l.List)-1 {
|
||||||
buf.WriteString(",")
|
buf.WriteString(",")
|
||||||
buf.WriteString(" ")
|
buf.WriteByte(blank)
|
||||||
} else if item.Pos().Line != l.Lbrack.Line {
|
} else if item.Pos().Line != l.Lbrack.Line {
|
||||||
buf.WriteString(",")
|
buf.WriteString(",")
|
||||||
buf.WriteString("\n")
|
buf.WriteByte(newline)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.WriteString("]")
|
buf.WriteString("]")
|
||||||
return buf.Bytes()
|
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
|
package printer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
@ -15,24 +14,12 @@ type printer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *printer) output() []byte {
|
func (p *printer) output() []byte {
|
||||||
fmt.Println("STARTING OUTPUT")
|
|
||||||
return p.printNode(p.node)
|
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.
|
// A Config node controls the output of Fprint.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Mode Mode // default: 0
|
SpaceWidth int // if set, it will use spaces instead of tabs for alignment
|
||||||
Tabwidth int // default: 4
|
|
||||||
Indent int // default: 0 (all code is indented at least by this much)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) fprint(output io.Writer, node ast.Node) error {
|
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,
|
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 {
|
if _, err := output.Write(p.output()); err != nil {
|
||||||
return err
|
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
|
// Fprint "pretty-prints" an HCL node to output
|
||||||
// It calls Config.Fprint with default settings.
|
// It calls Config.Fprint with default settings.
|
||||||
func Fprint(output io.Writer, node ast.Node) error {
|
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
|
package printer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -9,7 +10,7 @@ import (
|
|||||||
|
|
||||||
var listHCL = `foo = ["fatih", "arslan"]`
|
var listHCL = `foo = ["fatih", "arslan"]`
|
||||||
var listHCL2 = `foo = [
|
var listHCL2 = `foo = [
|
||||||
"fatih",
|
"fatih",
|
||||||
"arslan",
|
"arslan",
|
||||||
]`
|
]`
|
||||||
|
|
||||||
@ -58,8 +59,8 @@ output "web_ip" {
|
|||||||
`
|
`
|
||||||
|
|
||||||
func TestPrint(t *testing.T) {
|
func TestPrint(t *testing.T) {
|
||||||
// node, err := parser.Parse([]byte(complexHcl))
|
node, err := parser.Parse([]byte(complexHcl))
|
||||||
node, err := parser.Parse([]byte(listHCL2))
|
// node, err := parser.Parse([]byte(listHCL2))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -67,4 +68,6 @@ func TestPrint(t *testing.T) {
|
|||||||
if err := Fprint(os.Stdout, node); err != nil {
|
if err := Fprint(os.Stdout, node); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Println("")
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user