protofmt/columns.go

207 lines
6.1 KiB
Go

package protofmt
import (
"bytes"
"fmt"
"io"
"strconv"
"github.com/emicklei/proto"
)
func columns(v proto.Visitee) []aligned {
return asColumnsPrintable(v).columns()
}
// columnsPrintable is for elements that can be printed in aligned columns.
type columnsPrintable interface {
columns() (cols []aligned)
}
type columnsPrinter struct {
cols []aligned
visitee proto.Visitee
}
func asColumnsPrintable(v proto.Visitee) *columnsPrinter {
p := new(columnsPrinter)
p.visitee = v
return p
}
// columns is part of columnsPrintable
func (p *columnsPrinter) columns() []aligned {
p.visitee.Accept(p)
return p.cols
}
func (p *columnsPrinter) VisitMessage(m *proto.Message) {}
func (p *columnsPrinter) VisitService(v *proto.Service) {}
func (p *columnsPrinter) VisitSyntax(s *proto.Syntax) {}
func (p *columnsPrinter) VisitPackage(pkg *proto.Package) {
p.cols = append(p.cols, notAligned("package "), notAligned(pkg.Name), alignedSemicolon)
if pkg.InlineComment != nil {
p.cols = append(p.cols, notAligned(" //"), notAligned(pkg.InlineComment.Message()))
}
}
func (p *columnsPrinter) VisitOption(o *proto.Option) {
if !o.IsEmbedded {
p.cols = append(p.cols, leftAligned("option "))
} else {
p.cols = append(p.cols, leftAligned(" ["))
}
p.cols = append(p.cols, keyValuePair(o, o.IsEmbedded)...)
if o.IsEmbedded {
p.cols = append(p.cols, leftAligned("]"))
}
if !o.IsEmbedded {
p.cols = append(p.cols, alignedSemicolon)
if o.InlineComment != nil {
p.cols = append(p.cols, notAligned(" //"), notAligned(o.InlineComment.Message()))
}
}
}
func (p *columnsPrinter) VisitImport(i *proto.Import) {
p.cols = append(p.cols, leftAligned("import"), alignedSpace)
if len(i.Kind) > 0 {
p.cols = append(p.cols, leftAligned(i.Kind), alignedSpace)
}
p.cols = append(p.cols, notAligned(fmt.Sprintf("%q", i.Filename)), alignedSemicolon)
if i.InlineComment != nil {
p.cols = append(p.cols, notAligned(" //"), notAligned(i.InlineComment.Message()))
}
}
// VisitNormalField
// [|repeated][|optional][space][name][equals][sequence][|option]
func (p *columnsPrinter) VisitNormalField(f *proto.NormalField) {
if f.Repeated {
p.cols = append(p.cols, leftAligned("repeated "))
} else if f.Optional {
p.cols = append(p.cols, leftAligned("optional "))
} else if f.Required {
p.cols = append(p.cols, leftAligned("required "))
} else {
p.cols = append(p.cols, alignedEmpty)
}
p.cols = append(p.cols, leftAligned(f.Type), alignedSpace, leftAligned(f.Name), alignedEquals, rightAligned(strconv.Itoa(f.Sequence)))
if len(f.Options) > 0 {
p.cols = append(p.cols, leftAligned(" ["))
for i, each := range f.Options {
if i > 0 {
p.cols = append(p.cols, alignedComma)
}
p.cols = append(p.cols, keyValuePair(each, true)...)
}
p.cols = append(p.cols, leftAligned("]"))
}
p.cols = append(p.cols, alignedSemicolon)
if f.InlineComment != nil {
p.cols = append(p.cols, alignedInlinePrefix(f.InlineComment), notAligned(f.InlineComment.Message()))
}
}
func (p *columnsPrinter) VisitEnumField(f *proto.EnumField) {
p.cols = append(p.cols, leftAligned(f.Name), alignedEquals, rightAligned(strconv.Itoa(f.Integer)))
if f.ValueOption != nil {
p.cols = append(p.cols, columns(f.ValueOption)...)
}
p.cols = append(p.cols, alignedSemicolon)
if f.InlineComment != nil {
p.cols = append(p.cols, alignedInlinePrefix(f.InlineComment), notAligned(f.InlineComment.Message()))
}
}
func (p *columnsPrinter) VisitEnum(e *proto.Enum) {}
func (p *columnsPrinter) VisitComment(e *proto.Comment) {}
func (p *columnsPrinter) VisitOneof(o *proto.Oneof) {}
func (p *columnsPrinter) VisitOneofField(o *proto.OneOfField) {
p.cols = append(p.cols,
leftAligned(o.Type),
alignedSpace,
leftAligned(o.Name),
alignedEquals,
rightAligned(strconv.Itoa(o.Sequence)))
if len(o.Options) > 0 {
p.cols = append(p.cols, leftAligned(" ["))
for i, each := range o.Options {
if i > 0 {
p.cols = append(p.cols, alignedComma)
}
p.cols = append(p.cols, keyValuePair(each, true)...)
}
p.cols = append(p.cols, leftAligned("]"))
}
p.cols = append(p.cols, alignedSemicolon)
if o.InlineComment != nil {
p.cols = append(p.cols, notAligned(" //"), notAligned(o.InlineComment.Message()))
}
}
func (p *columnsPrinter) VisitReserved(rs *proto.Reserved) {}
func (p *columnsPrinter) VisitRPC(r *proto.RPC) {
p.cols = append(p.cols,
leftAligned("rpc "),
leftAligned(r.Name),
leftAligned(" ("))
if r.StreamsRequest {
p.cols = append(p.cols, leftAligned("stream "))
} else {
p.cols = append(p.cols, alignedEmpty)
}
p.cols = append(p.cols,
leftAligned(r.RequestType),
leftAligned(") "),
leftAligned("returns"),
leftAligned(" ("))
if r.StreamsReturns {
p.cols = append(p.cols, leftAligned("stream "))
} else {
p.cols = append(p.cols, alignedEmpty)
}
p.cols = append(p.cols,
leftAligned(r.ReturnsType),
leftAligned(")"))
if len(r.Elements) > 0 {
buf := new(bytes.Buffer)
io.WriteString(buf, " {\n")
f := NewFormatter(buf, " ") // TODO get separator, now 2 spaces
f.level(1)
for _, each := range r.Elements {
each.Accept(f)
io.WriteString(buf, "\n")
}
f.indent(-1)
io.WriteString(buf, "}")
p.cols = append(p.cols, notAligned(buf.String()))
} else {
p.cols = append(p.cols, alignedSemicolon)
}
if r.InlineComment != nil {
p.cols = append(p.cols, notAligned(" //"), notAligned(r.InlineComment.Message()))
}
}
func (p *columnsPrinter) VisitMapField(f *proto.MapField) {
p.cols = append(p.cols,
alignedEmpty, // no repeated no optional
leftAligned(fmt.Sprintf("map <%s,%s>", f.KeyType, f.Type)),
alignedSpace,
leftAligned(f.Name),
alignedEquals,
rightAligned(strconv.Itoa(f.Sequence)))
if len(f.Options) > 0 {
p.cols = append(p.cols, leftAligned(" ["))
for i, each := range f.Options {
if i > 0 {
p.cols = append(p.cols, alignedComma)
}
p.cols = append(p.cols, keyValuePair(each, true)...)
}
p.cols = append(p.cols, leftAligned("]"))
}
p.cols = append(p.cols, alignedSemicolon)
if f.InlineComment != nil {
p.cols = append(p.cols, alignedInlinePrefix(f.InlineComment), notAligned(f.InlineComment.Message()))
}
}
func (p *columnsPrinter) VisitGroup(g *proto.Group) {}
func (p *columnsPrinter) VisitExtensions(e *proto.Extensions) {}