234 lines
5.3 KiB
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)
|
||
|
}
|