-
Notifications
You must be signed in to change notification settings - Fork 3
/
comment_wrap.go
174 lines (139 loc) · 4.1 KB
/
comment_wrap.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
package main
import (
"bytes"
"fmt"
"go/ast"
"go/printer"
"go/token"
"log"
"os"
"os/exec"
"strings"
"sync"
)
func wrapComments(args []string, maxCommentLength uint, write bool) error {
fset := token.NewFileSet()
files, err := parseInput(args, fset)
if err != nil {
return fmt.Errorf("could not parse input %v", err)
}
var wg sync.WaitGroup
for _, f := range files {
processComments(fset, f.Comments, int(maxCommentLength), write)
wg.Add(1)
go func(f *ast.File) {
defer wg.Done()
if write {
// See if there's anything to actually do
if len(f.Comments) == 0 {
return
}
// Write the changes out to the file
fileName := fset.File(f.Pos()).Name()
file, err := os.Create(fileName)
if err != nil {
log.Println(err)
return
}
defer file.Close()
if err := printer.Fprint(file, fset, f); err != nil {
log.Fatal(err)
return
}
cmd := exec.Command("gofmt", "-w", fileName)
var out bytes.Buffer
cmd.Stdout = &out
err = cmd.Run()
if err != nil {
log.Fatal(err)
}
}
}(f)
}
wg.Wait()
return nil
}
func processComments(fset *token.FileSet, comments []*ast.CommentGroup, maxCommentLength int, write bool) {
for _, cg := range comments {
cIdx := 0
// Ignore huge block comment groups
if len(cg.List) > 10 {
continue
}
for _, c := range cg.List {
if len(c.Text) > maxCommentLength {
file := fset.File(cg.Pos())
lineNumber := file.Position(cg.List[cIdx].Pos()).Line
// Block comments are ignored
if strings.HasPrefix(c.Text, "/*") || strings.HasSuffix(c.Text, "*/") {
if !write {
log.Printf("%v:%v ignoring block comment\n", file.Name(), lineNumber)
}
break
}
// Split on each word
words := strings.Split(c.Text, " ")
// This means we have one giant word longer than X characters. It's probably a diagram or something, so we'll leave it.
if len(words) == 1 {
continue
}
// Otherwise, chop off words in reverse and glob them into a new line
currentLength := len(c.Text)
var choppedWords []string
for i := len(words) - 1; i >= 0; i-- {
currentLength = currentLength - len(words[i])
currentLength-- // subtract another 1 because we split on a space
choppedWords = append(choppedWords, words[i])
// Chopping off this word fixed our problems
if currentLength < maxCommentLength {
cg.List[cIdx].Text = strings.Join(words[0:i], " ")
// See if this is in a comment group we can wrap below to
if cIdx < len(cg.List)-1 {
// we were going in reverse, so append these in the other order.
reverse(choppedWords)
// Split on the comment
splitComment := strings.Split(cg.List[cIdx+1].Text, "//")
// See whether or not this comment follows the "// comment" or "// comment" idiom
commentStr := "//"
usesSpace := strings.HasPrefix(cg.List[cIdx+1].Text, "// ")
if usesSpace {
commentStr += " "
}
cg.List[cIdx+1].Text = commentStr + strings.Join(choppedWords, " ") + splitComment[0]
// Tack the rest of the comment back on
if len(splitComment) > 1 {
for _, s := range splitComment {
cg.List[cIdx+1].Text += s
}
}
break
} else {
// Otherwise, we have no room to wrap. This is easy, just create a new comment
reverse(choppedWords)
// See whether or not the preceding comment follows the "// comment" or "//comment" idiom
commentStr := "//"
usesSpace := strings.HasPrefix(cg.List[cIdx].Text, "// ")
if usesSpace {
commentStr += " "
}
cg.List = append(cg.List, &ast.Comment{Slash: cg.End() + 1, Text: commentStr + strings.Join(choppedWords, " ") + "\n"})
break
}
}
}
if !write {
log.Printf("%v:%v can be reduced to\n", file.Name(), lineNumber)
log.Printf(" %v\n", cg.List[cIdx].Text)
log.Printf(" %v\n", cg.List[cIdx+1].Text)
}
}
cIdx++
}
}
}
func reverse(ss []string) {
last := len(ss) - 1
for i := 0; i < len(ss)/2; i++ {
ss[i], ss[last-i] = ss[last-i], ss[i]
}
}