go.tools/godoc: server mode: add support for type and pointer analysis.

See analysis.go for overview of new features.
See README for known bugs and issues.

Much UI polish, testing and optimization work remains, but
this is a starting point.

Flag: we add a new flag -analysis=type,pointer, default "",
for adventurous users only at this stage.
Type analysis takes ~10s for stdlib + go.tools;
Pointer analysis (currently) takes several minutes.

Dependencies: we now include jquery.treeview.js and its GIF
images among the resources.  (bake.go now handles binary.)

LGTM=crawshaw, bgarcia
R=crawshaw, bgarcia
CC=bradfitz, golang-codereviews
https://golang.org/cl/60540044
diff --git a/godoc/server.go b/godoc/server.go
index 834d826..a4d613f 100644
--- a/godoc/server.go
+++ b/godoc/server.go
@@ -6,6 +6,7 @@
 
 import (
 	"bytes"
+	"encoding/json"
 	"expvar"
 	"fmt"
 	"go/ast"
@@ -13,6 +14,7 @@
 	"go/doc"
 	"go/token"
 	htmlpkg "html"
+	htmltemplate "html/template"
 	"io"
 	"io/ioutil"
 	"log"
@@ -25,6 +27,7 @@
 	"text/template"
 	"time"
 
+	"code.google.com/p/go.tools/godoc/analysis"
 	"code.google.com/p/go.tools/godoc/util"
 	"code.google.com/p/go.tools/godoc/vfs"
 )
@@ -256,6 +259,18 @@
 		tabtitle = "Commands"
 	}
 
+	// Emit JSON array for type information.
+	// TODO(adonovan): issue a "pending..." message if results not ready.
+	var callGraph []*analysis.PCGNodeJSON
+	var typeInfos []*analysis.TypeInfoJSON
+	callGraph, info.CallGraphIndex, typeInfos = h.c.Analysis.PackageInfo(relpath)
+	info.CallGraph = htmltemplate.JS(marshalJSON(callGraph))
+	info.AnalysisData = htmltemplate.JS(marshalJSON(typeInfos))
+	info.TypeInfoIndex = make(map[string]int)
+	for i, ti := range typeInfos {
+		info.TypeInfoIndex[ti.Name] = i
+	}
+
 	h.p.ServePage(w, Page{
 		Title:    title,
 		Tabtitle: tabtitle,
@@ -480,10 +495,25 @@
 		return
 	}
 
+	h := r.FormValue("h")
+	s := RangeSelection(r.FormValue("s"))
+
 	var buf bytes.Buffer
-	buf.WriteString("<pre>")
-	FormatText(&buf, src, 1, pathpkg.Ext(abspath) == ".go", r.FormValue("h"), RangeSelection(r.FormValue("s")))
-	buf.WriteString("</pre>")
+	if pathpkg.Ext(abspath) == ".go" {
+		// Find markup links for this file (e.g. "/src/pkg/fmt/print.go").
+		data, links := p.Corpus.Analysis.FileInfo(abspath)
+		buf.WriteString("<script type='text/javascript'>document.ANALYSIS_DATA = ")
+		buf.Write(marshalJSON(data))
+		buf.WriteString(";</script>\n")
+
+		buf.WriteString("<pre>")
+		formatGoSource(&buf, src, links, h, s)
+		buf.WriteString("</pre>")
+	} else {
+		buf.WriteString("<pre>")
+		FormatText(&buf, src, 1, false, h, s)
+		buf.WriteString("</pre>")
+	}
 	fmt.Fprintf(&buf, `<p><a href="/%s?m=text">View as plain text</a></p>`, htmlpkg.EscapeString(relpath))
 
 	p.ServePage(w, Page{
@@ -493,6 +523,33 @@
 	})
 }
 
+// formatGoSource HTML-escapes Go source text and writes it to w,
+// decorating it with the specified analysis links.
+//
+func formatGoSource(buf *bytes.Buffer, text []byte, links []analysis.Link, pattern string, selection Selection) {
+	var i int
+	var link analysis.Link // shared state of the two funcs below
+	segmentIter := func() (seg Segment) {
+		if i < len(links) {
+			link = links[i]
+			i++
+			seg = Segment{link.Start(), link.End()}
+		}
+		return
+	}
+	linkWriter := func(w io.Writer, offs int, start bool) {
+		link.Write(w, offs, start)
+	}
+
+	comments := tokenSelection(text, token.COMMENT)
+	var highlights Selection
+	if pattern != "" {
+		highlights = regexpSelection(text, pattern)
+	}
+
+	FormatSelections(buf, text, linkWriter, segmentIter, selectionTag, comments, highlights, selection)
+}
+
 func (p *Presentation) serveDirectory(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
 	if redirect(w, r) {
 		return
@@ -635,3 +692,18 @@
 	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
 	w.Write(text)
 }
+
+func marshalJSON(x interface{}) []byte {
+	var data []byte
+	var err error
+	const indentJSON = false // for easier debugging
+	if indentJSON {
+		data, err = json.MarshalIndent(x, "", "    ")
+	} else {
+		data, err = json.Marshal(x)
+	}
+	if err != nil {
+		panic(fmt.Sprintf("json.Marshal failed: %s", err))
+	}
+	return data
+}