299 lines
7.0 KiB
Go
299 lines
7.0 KiB
Go
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
|
|
// Use of this source code is governed by the GPL 3.0
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"iter"
|
|
"os"
|
|
"strings"
|
|
sync "sync"
|
|
|
|
"go.wit.com/log"
|
|
)
|
|
|
|
// like 'goimport', but for .proto files
|
|
|
|
var allTheLines *LinesScanner
|
|
|
|
func protoReformat(filename string) error {
|
|
// read in the .proto file
|
|
data, err := os.ReadFile(filename)
|
|
if err != nil {
|
|
log.Info("file read failed", filename, err)
|
|
return err
|
|
}
|
|
|
|
var inMessage bool
|
|
var newfile string
|
|
var fmtmsg *FormatMsg
|
|
fmtmsg = new(FormatMsg)
|
|
|
|
var bigName int64
|
|
var bigType int64
|
|
|
|
var allLinesIter iter.Seq[string]
|
|
allLinesIter = makeLineIter(data)
|
|
// gets the max vartype and varname
|
|
for line := range allLinesIter {
|
|
if strings.HasPrefix(line, "message ") {
|
|
inMessage = true
|
|
continue
|
|
}
|
|
|
|
// find the end of the message
|
|
if strings.HasPrefix(line, "}") {
|
|
inMessage = false
|
|
formatMessage2(fmtmsg)
|
|
if bigName < fmtmsg.MaxVarname {
|
|
bigName = fmtmsg.MaxVarname
|
|
}
|
|
if bigType < fmtmsg.MaxVartype {
|
|
bigType = fmtmsg.MaxVartype
|
|
}
|
|
fmtmsg = new(FormatMsg)
|
|
continue
|
|
}
|
|
|
|
// don't format or change anything when not in a "message {" section
|
|
if !inMessage {
|
|
continue
|
|
}
|
|
fmtmsg.Lines = append(fmtmsg.Lines, line)
|
|
}
|
|
|
|
fmtmsg = new(FormatMsg)
|
|
fmtmsg.MaxVarname = bigName
|
|
fmtmsg.MaxVartype = bigType
|
|
|
|
// write out the messages
|
|
allTheLines = newLinesScanner(strings.Split(string(data), "\n"))
|
|
for allTheLines.Scan() {
|
|
line := allTheLines.Next()
|
|
if strings.HasPrefix(line, "oneof ") {
|
|
if inMessage {
|
|
// message inception. search for the architect. don't forget your totem
|
|
newmsg := new(FormatMsg)
|
|
newmsg.MaxVarname = bigName
|
|
newmsg.MaxVartype = bigType
|
|
newmsg.Lines = append(newmsg.Lines, line)
|
|
getInceptionMsg(newmsg)
|
|
newmsg.Enums = append(newmsg.Oneofs, newmsg)
|
|
continue
|
|
}
|
|
}
|
|
|
|
if strings.HasPrefix(line, "enum ") {
|
|
if inMessage {
|
|
// message inception. search for the architect. don't forget your totem
|
|
newmsg := new(FormatMsg)
|
|
newmsg.MaxVarname = bigName
|
|
newmsg.MaxVartype = bigType
|
|
newmsg.Lines = append(newmsg.Lines, line)
|
|
getInceptionMsg(newmsg)
|
|
newmsg.Enums = append(newmsg.Enums, newmsg)
|
|
continue
|
|
}
|
|
}
|
|
|
|
if strings.HasPrefix(line, "message ") {
|
|
if inMessage {
|
|
// message inception. search for the architect. don't forget your totem
|
|
newmsg := new(FormatMsg)
|
|
newmsg.MaxVarname = bigName
|
|
newmsg.MaxVartype = bigType
|
|
newmsg.Lines = append(newmsg.Lines, line)
|
|
getInceptionMsg(newmsg)
|
|
newmsg.InceptionMsgs = append(newmsg.InceptionMsgs, newmsg)
|
|
continue
|
|
|
|
}
|
|
inMessage = true
|
|
parts := strings.Fields(line)
|
|
if len(parts) > 3 {
|
|
// hack to actually indent comments on the message line itself. you're welcome
|
|
start := parts[0] + " " + parts[1] + " " + parts[2]
|
|
end := strings.Join(parts[3:], " ")
|
|
offset := int(bigName) + int(bigType) + 16 - len(start)
|
|
pad := fmt.Sprintf("%d", offset)
|
|
hmm := "%s %" + pad + "s %s"
|
|
line = fmt.Sprintf(hmm, start, " ", end)
|
|
}
|
|
newfile += fmt.Sprintln(line)
|
|
continue
|
|
}
|
|
|
|
// find the end of the message
|
|
if strings.HasPrefix(line, "}") {
|
|
inMessage = false
|
|
// format and write the last message to the file
|
|
for _, newline := range formatMessage2(fmtmsg) {
|
|
newfile += fmt.Sprintln(newline)
|
|
}
|
|
newfile += fmt.Sprintln(line)
|
|
fmtmsg = new(FormatMsg)
|
|
fmtmsg.MaxVarname = bigName
|
|
fmtmsg.MaxVartype = bigType
|
|
continue
|
|
}
|
|
|
|
// don't format or change anything when not in a "message {" section
|
|
if !inMessage {
|
|
newfile += fmt.Sprintln(line)
|
|
continue
|
|
}
|
|
|
|
fmtmsg.Lines = append(fmtmsg.Lines, line)
|
|
}
|
|
|
|
pf, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
|
|
if err != nil {
|
|
log.Info("file open error. permissions?", filename, err)
|
|
return err
|
|
}
|
|
newfile = strings.TrimSpace(newfile)
|
|
fmt.Fprintln(pf, newfile)
|
|
pf.Close()
|
|
|
|
// for i, s := range slices.Backward(pf.ToSort) {
|
|
return nil
|
|
}
|
|
|
|
// returns vartype, varname, id, end
|
|
func tokenMsgVar(line string) (string, string, string, string) {
|
|
parts := strings.Split(line, ";")
|
|
front := parts[0]
|
|
end := strings.Join(parts[1:], ";")
|
|
|
|
var id string
|
|
var varname string
|
|
var vartype string
|
|
|
|
parts = strings.Fields(front)
|
|
parts, id = slicesPop(parts)
|
|
parts, _ = slicesPop(parts) // this is the "=" sign
|
|
parts, varname = slicesPop(parts)
|
|
vartype = strings.Join(parts, " ")
|
|
|
|
return vartype, varname, id, end
|
|
}
|
|
|
|
func slicesPop(parts []string) ([]string, string) {
|
|
if len(parts) == 0 {
|
|
return nil, ""
|
|
}
|
|
if len(parts) == 1 {
|
|
return nil, parts[0]
|
|
}
|
|
x := len(parts)
|
|
end := parts[x-1]
|
|
return parts[0 : x-1], end
|
|
}
|
|
|
|
// 'for x := range' syntax using the smartly done golang 1.24 'iter'
|
|
func makeLineIter(data []byte) iter.Seq[string] {
|
|
items := strings.Split(string(data), "\n")
|
|
// log.Println("Made All() Iter.Seq[] with length", len(items))
|
|
return func(yield func(string) bool) {
|
|
for _, v := range items {
|
|
if !yield(v) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func getInceptionMsg(curmsg *FormatMsg) {
|
|
for allTheLines.Scan() {
|
|
line := allTheLines.Next()
|
|
if strings.HasPrefix(line, "}") {
|
|
curmsg.Lines = append(curmsg.Lines, line)
|
|
return
|
|
}
|
|
curmsg.Lines = append(curmsg.Lines, line)
|
|
}
|
|
}
|
|
|
|
func formatMessage2(curmsg *FormatMsg) []string {
|
|
var newmsg []string
|
|
|
|
// find the max length of varname and vartype
|
|
for _, line := range curmsg.Lines {
|
|
parts := strings.Split(line, ";")
|
|
if len(parts) < 2 {
|
|
// line is blank or just a comment
|
|
continue
|
|
}
|
|
|
|
vartype, varname, _, _ := tokenMsgVar(line)
|
|
if len(vartype) > int(curmsg.MaxVartype) {
|
|
curmsg.MaxVartype = int64(len(vartype))
|
|
}
|
|
if len(varname) > int(curmsg.MaxVarname) {
|
|
curmsg.MaxVarname = int64(len(varname))
|
|
}
|
|
}
|
|
|
|
for _, line := range curmsg.Lines {
|
|
line = strings.TrimSpace(line)
|
|
if line == "" {
|
|
newmsg = append(newmsg, line)
|
|
continue
|
|
}
|
|
if strings.HasPrefix(line, "//") {
|
|
pad := fmt.Sprintf("%d", curmsg.MaxVartype+curmsg.MaxVarname+21)
|
|
hmm := "%" + pad + "s %s"
|
|
line = fmt.Sprintf(hmm, " ", line) // todo: compute 50
|
|
newmsg = append(newmsg, line)
|
|
continue
|
|
}
|
|
mt := fmt.Sprintf("%d", curmsg.MaxVartype)
|
|
mv := fmt.Sprintf("%d", curmsg.MaxVarname)
|
|
|
|
hmm := " %-" + mt + "s %-" + mv + "s = %-3s %s"
|
|
|
|
vartype, varname, id, end := tokenMsgVar(line)
|
|
end = strings.TrimSpace(end)
|
|
id = id + ";"
|
|
|
|
newline := fmt.Sprintf(hmm, vartype, varname, id, end)
|
|
newline = strings.TrimRight(newline, " ")
|
|
newmsg = append(newmsg, newline)
|
|
}
|
|
return newmsg
|
|
}
|
|
|
|
// DEFINE THE Lines ITERATOR.
|
|
// itializes a new iterator.
|
|
func newLinesScanner(things []string) *LinesScanner {
|
|
return &LinesScanner{things: things}
|
|
}
|
|
|
|
type LinesScanner struct {
|
|
sync.Mutex
|
|
|
|
things []string
|
|
index int
|
|
}
|
|
|
|
func (it *LinesScanner) Scan() bool {
|
|
if it.index >= len(it.things) {
|
|
return false
|
|
}
|
|
it.Lock()
|
|
it.index++
|
|
it.Unlock()
|
|
return true
|
|
}
|
|
|
|
// Next() returns the next thing in the array
|
|
func (it *LinesScanner) Next() string {
|
|
if it.index-1 == len(it.things) {
|
|
fmt.Println("Next() error in LinesScanner", it.index)
|
|
}
|
|
return strings.TrimSpace(it.things[it.index-1])
|
|
}
|
|
|
|
// END DEFINE THE ITERATOR
|