-
Notifications
You must be signed in to change notification settings - Fork 0
/
doc.go
182 lines (157 loc) · 5.6 KB
/
doc.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
175
176
177
178
179
180
181
182
package main
import (
"github.com/toteki/wiz"
"log"
"regexp"
"strings"
)
func main() {
// Only run this file after acquiring a raw godoc output html.
// One way to do this is by:
/*
read -p "Enter package url to document: " PACKAGE
godoc -url "http://localhost:6060/pkg/$PACKAGE/" > raw_doc.html
*/
// This script takes raw godoc output HTML, which contains references to
// external CSS and JS, as well as links to localhost:6060, where godoc
// would be running, and proceeds to embed the external files and clean
// any hyperlinks that wouldn't work without once the godoc server stopped.
// The CSS and JS are stored in this repository to remove external dependency.
// They were retrieved November 2020 and will not be updated unless necessary.
args := wiz.Args() // Retrieve command line arguments (expects 2)
// The command line argument is the name of the raw html doc to clean.
// This is doc_raw.html when using as intended.
wiz.Green("Reading file " + args[0])
raw_file, err := wiz.ReadFile(args[0])
if err != nil {
log.Fatal(err)
}
// HTML script tags
s0 := []byte("<script>\n")
s1 := []byte("\n</script>")
// Read godocs.js and prepend+append script tags
wiz.Green("Reading file godocs.js")
godocs, err := wiz.ReadFile("godocs.js")
if err != nil {
log.Fatal(err)
}
godocs = append(s0, godocs...)
godocs = append(godocs, s1...)
// Read jquery.js and prepend+append script tags
wiz.Green("Reading file jquery.js")
jquery, err := wiz.ReadFile("jquery.js")
if err != nil {
log.Fatal(err)
}
jquery = append(s0, jquery...)
jquery = append(jquery, s1...)
// HTML style tags
c0 := []byte("<style>\n")
c1 := []byte("\n</style>")
// Read style.css and prepend+append style tags
wiz.Green("Reading file style.css")
style, err := wiz.ReadFile("style.css")
if err != nil {
log.Fatal(err)
}
style = append(c0, style...)
style = append(style, c1...)
// Separate file out into lines
line := regexp.MustCompile(".*") // A regex which matches anything
lines := line.FindAll(raw_file, -1) // All matching lines in the file
// Eliminate the footer of the HTML document
lines = eliminateRange(lines, "<div id=\"footer\">", "</div>")
// Eliminate unnecessary godoc message
lines = replace(lines, "using GOPATH mode", []byte{})
// Embed local jquery.js file
lines = replace(lines, "<script src=\"/lib/godoc/jquery.js\" defer></script>", jquery)
// Embed local godocs.js file
lines = replace(lines, "<script src=\"/lib/godoc/godocs.js\" defer></script>", godocs)
// Embed local style.css file
lines = replace(lines, "<link type=\"text/css\" rel=\"stylesheet\" href=\"/lib/godoc/style.css\">", style)
// Re-combine the file line by line after manipulation
out := []byte{}
for _, l := range lines {
out = append(out, l...)
out = append(out, []byte("\n")...)
}
wiz.Green("Finished line manipulation")
// Next, should transform any hyperlinks in the file to plain text.
//
// For example,
// <a href="/src/github.com/toteki/wiz/ASCII.go?s=653:688#L14">ASCII</a>
// becomes
// ASCII
//
// Only eliminates hrefs that start with / (which leaves intact the ones
// which only jump the user to a section of the document).
// Mark these references to outside the document by
// replacing their first tag with <a doomed href>
refspotter := regexp.MustCompile("<a href=\"[^#][^\"]*\">")
out = refspotter.ReplaceAllLiteral(out, []byte("<a doomed href>"))
wiz.Purple("Spotting all broken hyperlinks")
// Kill <a doomed href> tags while
// preserving what's between them.
refkiller := regexp.MustCompile("<a doomed href>[^<]*</a>")
out = refkiller.ReplaceAllFunc(out, striplink)
wiz.Purple("Killing all broken hyperlinks")
// Determine the filename out the output - we will use everything after the
// last slash, e.g. "github.com/pkg/errors.html" => "errors.html"
// Matches zero or more non-slash before end of string
namer := regexp.MustCompile("[^/]+$")
name := string(namer.Find([]byte(args[1]))) // use on second command line arg
// Writing the cleaned output file to output directory
err = wiz.WriteFile("output/"+name, out)
if err != nil {
log.Fatal(err)
}
wiz.Green("Wrote file " + name + " to output directory")
}
// Given an input string which begins and ends with <a doomed href> and </a>,
// remove those tags. This is used after those tags are inserted in place
// of hyperlinks this script wishes to remove.
func striplink(in []byte) []byte {
s := string(in)
s = strings.TrimPrefix(s, "<a doomed href>")
s = strings.TrimSuffix(s, "</a>")
return []byte(s)
}
// Replaces a given line in a [][]byte representing the lines in a file, with
// a given byte slice. (In this case, a whole file.)
func replace(lines [][]byte, line string, file []byte) [][]byte {
out := [][]byte{}
for _, l := range lines {
if string(l) == line {
wiz.Purple("Replacing line: ", line)
out = append(out, file) //add the file
} else {
out = append(out, l) //add the existing line
}
}
return out
}
// Removes all lines between two specified lines of text in a [][]byte
// representing the lines in a file. Eliminates the specified lines too.
func eliminateRange(lines [][]byte, line1, line2 string) [][]byte {
active := false
output := [][]byte{}
for _, l := range lines {
if !active {
//If not currently eliminating between two lines
if string(l) == line1 {
active = true //Start eliminating if encountered line1
}
}
//If not eliminating, add lines to output
if !active {
output = append(output, l)
}
if active {
//If currently eliminating between two lines
if string(l) == line2 {
active = false //Stop eliminating if encountered line2
}
}
}
return output
}