protofmt/formatter.go

234 lines
5.3 KiB
Go

package protofmt
import (
"fmt"
"io"
"github.com/emicklei/proto"
)
// Formatter visits a Proto and writes formatted source.
type Formatter struct {
w io.Writer
indentSeparator string
indentLevel int
lastStmt string
lastLevel int
}
// NewFormatter returns a new Formatter. Only the indentation separator is configurable.
func NewFormatter(writer io.Writer, indentSeparator string) *Formatter {
return &Formatter{w: writer, indentSeparator: indentSeparator}
}
// Format visits all proto elements and writes formatted source.
func (f *Formatter) Format(p *proto.Proto) {
for _, each := range p.Elements {
each.Accept(f)
}
}
// VisitComment formats a Comment and writes enclosing newlines.
func (f *Formatter) VisitComment(c *proto.Comment) {
f.printComment(c)
f.nl()
}
// VisitEnum formats a Enum.
func (f *Formatter) VisitEnum(e *proto.Enum) {
f.begin("enum", e)
if _, ok := e.Parent.(*proto.Message); !ok && (e.Comment == nil || len(e.Comment.Lines) == 0) {
f.nl()
}
fmt.Fprintf(f.w, "enum %s {", e.Name)
if len(e.Elements) > 0 {
f.nl()
f.level(1)
f.printAsGroups(e.Elements)
f.indent(-1)
}
io.WriteString(f.w, "}\n")
f.end("enum")
}
// VisitEnumField formats a EnumField.
func (f *Formatter) VisitEnumField(e *proto.EnumField) {
f.printAsGroups([]proto.Visitee{e})
}
// VisitImport formats a Import.
func (f *Formatter) VisitImport(i *proto.Import) {
f.beginNoDoc("import", i)
f.printAsGroups([]proto.Visitee{i})
f.end("import")
}
// VisitMessage formats a Message.
func (f *Formatter) VisitMessage(m *proto.Message) {
f.begin("message", m)
if _, ok := m.Parent.(*proto.Message); !ok && (m.Comment == nil || len(m.Comment.Lines) == 0) {
f.nl()
}
if m.IsExtend {
fmt.Fprintf(f.w, "extend ")
} else {
fmt.Fprintf(f.w, "message ")
}
fmt.Fprintf(f.w, "%s {", m.Name)
if len(m.Elements) > 0 {
f.nl()
f.level(1)
f.printAsGroups(m.Elements)
f.indent(-1)
}
io.WriteString(f.w, "}\n")
f.end("message")
}
// VisitOption formats a Option.
func (f *Formatter) VisitOption(o *proto.Option) {
f.begin("option", o)
fmt.Fprintf(f.w, "option %s = ", o.Name)
f.formatLiteral(&o.Constant)
fmt.Fprintf(f.w, ";\n")
if o.InlineComment != nil {
fmt.Fprintf(f.w, " //%s", o.InlineComment.Message())
}
f.end("option")
}
func (f *Formatter) formatLiteral(l *proto.Literal) {
if len(l.OrderedMap) == 0 && len(l.Array) == 0 {
fmt.Fprintf(f.w, "%s", l.SourceRepresentation())
return
}
fmt.Fprintf(f.w, "{\n")
for _, other := range l.OrderedMap {
f.indent(1)
fmt.Fprintf(f.w, "%s", other.Name)
if other.PrintsColon {
fmt.Fprintf(f.w, ": ")
}
f.formatLiteral(other.Literal)
f.level(-1)
f.nl()
}
f.indent(0)
fmt.Fprintf(f.w, "}")
}
// VisitPackage formats a Package.
func (f *Formatter) VisitPackage(p *proto.Package) {
f.begin("package", p)
f.printAsGroups([]proto.Visitee{p})
f.end("package")
}
// VisitService formats a Service.
func (f *Formatter) VisitService(s *proto.Service) {
f.begin("service", s)
fmt.Fprintf(f.w, "service %s {", s.Name)
if len(s.Elements) > 0 {
f.nl()
f.level(1)
f.printAsGroups(s.Elements)
f.indent(-1)
}
io.WriteString(f.w, "}\n\n")
f.end("service")
}
// VisitSyntax formats a Syntax.
func (f *Formatter) VisitSyntax(s *proto.Syntax) {
f.begin("syntax", s)
fmt.Fprintf(f.w, "syntax = %q", s.Value)
f.endWithComment(s.InlineComment)
f.end("syntax")
}
// VisitOneof formats a Oneof.
func (f *Formatter) VisitOneof(o *proto.Oneof) {
f.begin("oneof", o)
fmt.Fprintf(f.w, "oneof %s {", o.Name)
if len(o.Elements) > 0 {
f.nl()
f.level(1)
f.printAsGroups(o.Elements)
f.indent(-1)
}
io.WriteString(f.w, "}\n")
f.end("oneof")
}
// VisitOneofField formats a OneofField.
func (f *Formatter) VisitOneofField(o *proto.OneOfField) {
f.printAsGroups([]proto.Visitee{o})
}
// VisitReserved formats a Reserved.
func (f *Formatter) VisitReserved(r *proto.Reserved) {
f.begin("reserved", r)
io.WriteString(f.w, "reserved ")
if len(r.Ranges) > 0 {
for i, each := range r.Ranges {
if i > 0 {
io.WriteString(f.w, ", ")
}
fmt.Fprintf(f.w, "%s", each.SourceRepresentation())
}
} else {
for i, each := range r.FieldNames {
if i > 0 {
io.WriteString(f.w, ", ")
}
fmt.Fprintf(f.w, "%q", each)
}
}
f.endWithComment(r.InlineComment)
}
// VisitRPC formats a RPC.
func (f *Formatter) VisitRPC(r *proto.RPC) {
f.printAsGroups([]proto.Visitee{r})
}
// VisitMapField formats a MapField.
func (f *Formatter) VisitMapField(m *proto.MapField) {
f.printAsGroups([]proto.Visitee{m})
}
// VisitNormalField formats a NormalField.
func (f *Formatter) VisitNormalField(f1 *proto.NormalField) {
f.printAsGroups([]proto.Visitee{f1})
}
// VisitGroup formats a proto2 Group.
func (f *Formatter) VisitGroup(g *proto.Group) {
f.begin("group", g)
if g.Optional {
io.WriteString(f.w, "optional ")
}
fmt.Fprintf(f.w, "group %s = %d {", g.Name, g.Sequence)
if len(g.Elements) > 0 {
f.nl()
f.level(1)
f.printAsGroups(g.Elements)
f.indent(-1)
}
io.WriteString(f.w, "}\n")
f.end("group")
}
// VisitExtensions formats a proto2 Extensions.
func (f *Formatter) VisitExtensions(e *proto.Extensions) {
f.begin("extensions", e)
io.WriteString(f.w, "extensions ")
for i, each := range e.Ranges {
if i > 0 {
io.WriteString(f.w, ", ")
}
fmt.Fprintf(f.w, "%s", each.SourceRepresentation())
}
f.endWithComment(e.InlineComment)
}