1
2
3
4
5
6
7 package modfile
8
9 import (
10 "bytes"
11 "fmt"
12 "strings"
13 )
14
15
16 func Format(f *FileSyntax) []byte {
17 pr := &printer{}
18 pr.file(f)
19
20
21 b := pr.Bytes()
22 for len(b) > 0 && b[len(b)-1] == '\n' && (len(b) == 1 || b[len(b)-2] == '\n') {
23 b = b[:len(b)-1]
24 }
25 return b
26 }
27
28
29 type printer struct {
30 bytes.Buffer
31 comment []Comment
32 margin int
33 }
34
35
36 func (p *printer) printf(format string, args ...interface{}) {
37 fmt.Fprintf(p, format, args...)
38 }
39
40
41 func (p *printer) indent() int {
42 b := p.Bytes()
43 n := 0
44 for n < len(b) && b[len(b)-1-n] != '\n' {
45 n++
46 }
47 return n
48 }
49
50
51 func (p *printer) newline() {
52 if len(p.comment) > 0 {
53 p.printf(" ")
54 for i, com := range p.comment {
55 if i > 0 {
56 p.trim()
57 p.printf("\n")
58 for i := 0; i < p.margin; i++ {
59 p.printf("\t")
60 }
61 }
62 p.printf("%s", strings.TrimSpace(com.Token))
63 }
64 p.comment = p.comment[:0]
65 }
66
67 p.trim()
68 if b := p.Bytes(); len(b) == 0 || (len(b) >= 2 && b[len(b)-1] == '\n' && b[len(b)-2] == '\n') {
69
70 } else {
71 p.printf("\n")
72 }
73 for i := 0; i < p.margin; i++ {
74 p.printf("\t")
75 }
76 }
77
78
79 func (p *printer) trim() {
80
81 b := p.Bytes()
82 n := len(b)
83 for n > 0 && (b[n-1] == '\t' || b[n-1] == ' ') {
84 n--
85 }
86 p.Truncate(n)
87 }
88
89
90 func (p *printer) file(f *FileSyntax) {
91 for _, com := range f.Before {
92 p.printf("%s", strings.TrimSpace(com.Token))
93 p.newline()
94 }
95
96 for i, stmt := range f.Stmt {
97 switch x := stmt.(type) {
98 case *CommentBlock:
99
100 p.expr(x)
101
102 default:
103 p.expr(x)
104 p.newline()
105 }
106
107 for _, com := range stmt.Comment().After {
108 p.printf("%s", strings.TrimSpace(com.Token))
109 p.newline()
110 }
111
112 if i+1 < len(f.Stmt) {
113 p.newline()
114 }
115 }
116 }
117
118 func (p *printer) expr(x Expr) {
119
120 if before := x.Comment().Before; len(before) > 0 {
121
122
123 p.trim()
124 if p.indent() > 0 {
125
126 p.printf("\n")
127 }
128
129 for i := 0; i < p.margin; i++ {
130 p.printf("\t")
131 }
132 for _, com := range before {
133 p.printf("%s", strings.TrimSpace(com.Token))
134 p.newline()
135 }
136 }
137
138 switch x := x.(type) {
139 default:
140 panic(fmt.Errorf("printer: unexpected type %T", x))
141
142 case *CommentBlock:
143
144
145 case *LParen:
146 p.printf("(")
147 case *RParen:
148 p.printf(")")
149
150 case *Line:
151 p.tokens(x.Token)
152
153 case *LineBlock:
154 p.tokens(x.Token)
155 p.printf(" ")
156 p.expr(&x.LParen)
157 p.margin++
158 for _, l := range x.Line {
159 p.newline()
160 p.expr(l)
161 }
162 p.margin--
163 p.newline()
164 p.expr(&x.RParen)
165 }
166
167
168
169 p.comment = append(p.comment, x.Comment().Suffix...)
170 }
171
172 func (p *printer) tokens(tokens []string) {
173 sep := ""
174 for _, t := range tokens {
175 if t == "," || t == ")" || t == "]" || t == "}" {
176 sep = ""
177 }
178 p.printf("%s%s", sep, t)
179 sep = " "
180 if t == "(" || t == "[" || t == "{" {
181 sep = ""
182 }
183 }
184 }
185
View as plain text