hackdoc: render TOC inline

Change-Id: Ib91e4d3b73354e7e19095ea62eed70a23ef96512
diff --git a/devtools/hackdoc/markdown.go b/devtools/hackdoc/markdown.go
index cfd594d..5004642 100644
--- a/devtools/hackdoc/markdown.go
+++ b/devtools/hackdoc/markdown.go
@@ -28,11 +28,18 @@
 	parser := blackfriday.New(blackfriday.WithRenderer(r), blackfriday.WithExtensions(blackfriday.CommonExtensions))
 	ast := parser.Parse(input)
 
+	// Render table of contents (raw HTML) into bytes.
+	var tocB bytes.Buffer
+	tocB.Write([]byte(`<div class="toc">`))
+	r.RenderHeader(&tocB, ast)
+	tocB.Write([]byte(`</div>`))
+	toc := tocB.Bytes()
+
 	var buf bytes.Buffer
-	buf.Write([]byte(`<div class="toc"><h1>Page Contents</h1>`))
-	r.RenderHeader(&buf, ast)
-	buf.Write([]byte(`</div><div class="content">`))
+	buf.Write([]byte(`<div class="content">`))
+	// Render Markdown with some custom behaviour.
 	ast.Walk(func(node *blackfriday.Node, entering bool) blackfriday.WalkStatus {
+		// Fix intra-hackdoc links to contain ?ref=
 		if ref != "" && entering && node.Type == blackfriday.Link || node.Type == blackfriday.Image {
 			dest := string(node.Destination)
 			u, err := url.Parse(dest)
@@ -41,9 +48,14 @@
 				q["ref"] = []string{ref}
 				u.RawQuery = q.Encode()
 				node.Destination = []byte(u.String())
-				glog.Infof("link fix %q -> %q", dest, u.String())
+				glog.V(10).Infof("link fix %q -> %q", dest, u.String())
 			}
 		}
+		// Replace [TOC] anchor with a rendered TOC.
+		if entering && node.Type == blackfriday.Text && string(node.Literal) == "[TOC]" {
+			buf.Write(toc)
+			return blackfriday.GoToNext
+		}
 		return r.RenderNode(&buf, node, entering)
 	})
 	buf.Write([]byte(`</div>`))