Skip to content
This repository was archived by the owner on Jul 29, 2021. It is now read-only.

Commit 774717f

Browse files
committed
Add support for examples.
Fixes #2
1 parent deb306d commit 774717f

File tree

3 files changed

+141
-15
lines changed

3 files changed

+141
-15
lines changed

example.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"go/doc"
6+
"go/printer"
7+
"regexp"
8+
"sort"
9+
"strings"
10+
"unicode"
11+
"unicode/utf8"
12+
13+
"golang.org/x/tools/godoc"
14+
)
15+
16+
type example struct {
17+
Name string
18+
Doc string
19+
Code string
20+
Output string
21+
}
22+
23+
var exampleOutputRx = regexp.MustCompile(`(?i)//[[:space:]]*(unordered )?output:`)
24+
25+
func examplesFunc(info *godoc.PageInfo, name string) []*example {
26+
var egs []*example
27+
for _, eg := range info.Examples {
28+
if name != "*" && stripExampleSuffix(eg.Name) != name {
29+
continue
30+
}
31+
doc := eg.Doc
32+
out := eg.Output
33+
code, wholeFile := exampleCode(info, eg)
34+
if wholeFile {
35+
doc = ""
36+
out = ""
37+
}
38+
egs = append(egs, &example{
39+
Name: eg.Name,
40+
Doc: doc,
41+
Code: code,
42+
Output: out,
43+
})
44+
}
45+
sort.Slice(egs, func(i int, j int) bool {
46+
ni, si := splitExampleName(egs[i].Name)
47+
nj, sj := splitExampleName(egs[j].Name)
48+
if ni == nj {
49+
return si < sj
50+
}
51+
return ni < nj
52+
})
53+
return egs
54+
}
55+
56+
func exampleCode(info *godoc.PageInfo, eg *doc.Example) (code string, wholeFile bool) {
57+
// Print code
58+
var buf bytes.Buffer
59+
cnode := &printer.CommentedNode{Node: eg.Code, Comments: eg.Comments}
60+
config := &printer.Config{Mode: printer.UseSpaces, Tabwidth: *tabWidth}
61+
config.Fprint(&buf, info.FSet, cnode)
62+
code = strings.Trim(buf.String(), "\n")
63+
wholeFile = true
64+
65+
if n := len(code); n >= 2 && code[0] == '{' && code[n-1] == '}' {
66+
wholeFile = false
67+
// Remove surrounding braces.
68+
code = strings.Trim(code[1:n-1], "\n")
69+
// Remove output from code.
70+
if loc := exampleOutputRx.FindStringIndex(code); loc != nil {
71+
code = strings.TrimRightFunc(code[:loc[0]], unicode.IsSpace)
72+
}
73+
// Unindent code.
74+
lines := strings.Split(code, "\n")
75+
unindent(lines)
76+
code = strings.Join(lines, "\n")
77+
}
78+
79+
return code, wholeFile
80+
}
81+
82+
func splitExampleName(s string) (name, suffix string) {
83+
i := strings.LastIndex(s, "_")
84+
if 0 <= i && i < len(s)-1 && !startsWithUppercase(s[i+1:]) {
85+
name = s[:i]
86+
suffix = " (" + strings.Title(s[i+1:]) + ")"
87+
return
88+
}
89+
name = s
90+
return
91+
}
92+
93+
// stripExampleSuffix strips lowercase braz in Foo_braz or Foo_Bar_braz from name
94+
// while keeping uppercase Braz in Foo_Braz.
95+
func stripExampleSuffix(name string) string {
96+
if i := strings.LastIndex(name, "_"); i != -1 {
97+
if i < len(name)-1 && !startsWithUppercase(name[i+1:]) {
98+
name = name[:i]
99+
}
100+
}
101+
return name
102+
}
103+
104+
func startsWithUppercase(s string) bool {
105+
r, _ := utf8.DecodeRuneInString(s)
106+
return unicode.IsUpper(r)
107+
}

main.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,15 @@ var (
6161
fs = vfs.NameSpace{}
6262

6363
funcs = map[string]interface{}{
64-
"comment_md": commentMdFunc,
65-
"base": path.Base,
66-
"md": mdFunc,
67-
"pre": preFunc,
68-
"kebab": kebabFunc,
69-
"bitscape": bitscapeFunc, //Escape [] for bitbucket confusion
64+
"comment_md": commentMdFunc,
65+
"base": path.Base,
66+
"md": mdFunc,
67+
"pre": preFunc,
68+
"kebab": kebabFunc,
69+
"bitscape": bitscapeFunc, //Escape [] for bitbucket confusion
70+
"show_examples": func() bool { return *showExamples },
71+
"examples": examplesFunc,
72+
"output": outputFunc,
7073
}
7174
)
7275

@@ -86,6 +89,14 @@ func preFunc(text string) string {
8689
return "``` go\n" + text + "\n```"
8790
}
8891

92+
func outputFunc(output string) string {
93+
lines := strings.Split(output, "\n")
94+
for i, line := range lines {
95+
lines[i] = " " + line
96+
}
97+
return "\n" + strings.Join(lines, "\n")
98+
}
99+
89100
// Original Source https://github.com/golang/tools/blob/master/godoc/godoc.go#L562
90101
func srcLinkFunc(s string) string {
91102
s = path.Clean("/" + s)

template.go

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
package main
22

3-
var pkgTemplate = `{{with .PDoc}}
3+
var pkgTemplate = `{{define "examples_md"}}{{- range .}}
4+
#### <a name="example_{{.Name}}">Example{{example_suffix .Name}}</a>
5+
{{comment_md .Doc}}
6+
Code:
7+
{{pre .Code}}{{if .Output}}
8+
Output:
9+
{{output .Output}}
10+
{{end}}
11+
{{end}}{{end}}{{with .PDoc}}
412
{{if $.IsMain}}
513
> {{ base .ImportPath }}
614
{{comment_md .Doc}}
@@ -9,13 +17,13 @@ var pkgTemplate = `{{with .PDoc}}
917
` + "`" + `import "{{.ImportPath}}"` + "`" + `
1018
1119
* [Overview](#pkg-overview)
12-
* [Index](#pkg-index){{if $.Examples}}
20+
* [Index](#pkg-index){{if and $.Examples show_examples}}
1321
* [Examples](#pkg-examples){{- end}}{{if $.Dirs}}
1422
* [Subdirectories](#pkg-subdirectories){{- end}}
1523
1624
## <a name="pkg-overview">Overview</a>
1725
{{comment_md .Doc}}
18-
{{example_html $ ""}}
26+
{{template "examples_md" (examples $ "")}}
1927
2028
## <a name="pkg-index">Index</a>{{if .Consts}}
2129
* [Constants](#pkg-constants){{end}}{{if .Vars}}
@@ -25,8 +33,8 @@ var pkgTemplate = `{{with .PDoc}}
2533
* [{{node_html $ .Decl false | sanitize}}](#{{$name_html}}){{- end}}{{- range .Methods}}{{$name_html := html .Name}}
2634
* [{{node_html $ .Decl false | sanitize}}](#{{$tname_html}}.{{$name_html}}){{- end}}{{- end}}{{- if $.Notes}}{{- range $marker, $item := $.Notes}}
2735
* [{{noteTitle $marker | html}}s](#pkg-note-{{$marker}}){{end}}{{end}}
28-
{{if $.Examples}}
29-
#### <a name="pkg-examples">Examples</a>{{- range $.Examples}}
36+
{{if and $.Examples show_examples}}
37+
#### <a name="pkg-examples">Examples</a>{{- range examples $ "*" }}
3038
* [{{example_name .Name}}](#example_{{.Name}}){{- end}}{{- end}}
3139
{{with .Filenames}}
3240
#### <a name="pkg-files">Package files</a>
@@ -43,7 +51,7 @@ var pkgTemplate = `{{with .PDoc}}
4351
{{range .Funcs}}{{$name_html := html .Name}}## <a name="{{$name_html}}">func</a> [{{$name_html}}]({{posLink_url $ .Decl}})
4452
{{node $ .Decl | pre}}
4553
{{comment_md .Doc}}
46-
{{example_html $ .Name}}
54+
{{template "examples_md" (examples $ .Name)}}
4755
{{callgraph_html $ "" .Name}}{{end}}
4856
{{range .Types}}{{$tname := .Name}}{{$tname_html := html .Name}}## <a name="{{$tname_html}}">type</a> [{{$tname_html}}]({{posLink_url $ .Decl}})
4957
{{node $ .Decl | pre}}
@@ -53,20 +61,20 @@ var pkgTemplate = `{{with .PDoc}}
5361
{{node $ .Decl | pre }}
5462
{{comment_md .Doc}}{{end}}
5563
56-
{{example_html $ $tname}}
64+
{{template "examples_md" (examples $ $tname)}}
5765
{{implements_html $ $tname}}
5866
{{methodset_html $ $tname}}
5967
6068
{{range .Funcs}}{{$name_html := html .Name}}### <a name="{{$name_html}}">func</a> [{{$name_html}}]({{posLink_url $ .Decl}})
6169
{{node $ .Decl | pre}}
6270
{{comment_md .Doc}}
63-
{{example_html $ .Name}}{{end}}
71+
{{template "examples_md" (examples $ .Name)}}{{end}}
6472
{{callgraph_html $ "" .Name}}
6573
6674
{{range .Methods}}{{$name_html := html .Name}}### <a name="{{$tname_html}}.{{$name_html}}">func</a> ({{md .Recv}}) [{{$name_html}}]({{posLink_url $ .Decl}})
6775
{{node $ .Decl | pre}}
6876
{{comment_md .Doc}}
69-
{{$name := printf "%s_%s" $tname .Name}}{{example_html $ $name}}
77+
{{$name := printf "%s_%s" $tname .Name}}{{template "examples_md" (examples $ $name)}}
7078
{{callgraph_html $ .Recv .Name}}
7179
{{end}}{{end}}{{end}}
7280

0 commit comments

Comments
 (0)