internal/lsp: get debug pages limping along again

Changes to the cache data structure broke the templates displaying
information in the debug server. This CL makes small changes to
get the pages working again. it adds  a link to the command line
on the Info page.

More work is needed. For instance, only the memory page refreshes
automatically; options could be displayed; information
about diagnostics could be displayed, as could be information
about modules, and no doubt there's more.

I'm working on a test to typecheck the templates.

Fixes golang/go#41343

Change-Id: I98538a8673de1a9589d09660eab47ad04eb2cc14
Reviewed-on: https://go-review.googlesource.com/c/tools/+/270099
Run-TryBot: Peter Weinberger <pjw@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
Trust: Peter Weinberger <pjw@google.com>
diff --git a/internal/lsp/cache/view.go b/internal/lsp/cache/view.go
index 489504b..896e629 100644
--- a/internal/lsp/cache/view.go
+++ b/internal/lsp/cache/view.go
@@ -433,6 +433,10 @@
 	}
 }
 
+func (v *View) Session() *Session {
+	return v.session
+}
+
 func (v *View) BackgroundContext() context.Context {
 	v.mu.Lock()
 	defer v.mu.Unlock()
diff --git a/internal/lsp/debug/info.go b/internal/lsp/debug/info.go
index ef578c4..cd4ee58 100644
--- a/internal/lsp/debug/info.go
+++ b/internal/lsp/debug/info.go
@@ -99,6 +99,9 @@
 		fmt.Fprintf(w, "Debug address: %s\n", i.DebugAddress)
 	})
 	PrintVersionInfo(ctx, w, true, HTML)
+	section(w, HTML, "Command Line", func() {
+		fmt.Fprintf(w, "<a href=/debug/pprof/cmdline>cmdline</a>")
+	})
 }
 
 // PrintVersionInfo writes version information to w, using the output format
diff --git a/internal/lsp/debug/serve.go b/internal/lsp/debug/serve.go
index cd9ec97..aa4df63 100644
--- a/internal/lsp/debug/serve.go
+++ b/internal/lsp/debug/serve.go
@@ -231,6 +231,36 @@
 	}
 }
 
+// an http.ResponseWriter that filters writes
+type filterResponse struct {
+	w    http.ResponseWriter
+	edit func([]byte) []byte
+}
+
+func (c filterResponse) Header() http.Header {
+	return c.w.Header()
+}
+
+func (c filterResponse) Write(buf []byte) (int, error) {
+	ans := c.edit(buf)
+	return c.w.Write(ans)
+}
+
+func (c filterResponse) WriteHeader(n int) {
+	c.w.WriteHeader(n)
+}
+
+// replace annoying nuls by spaces
+func cmdline(w http.ResponseWriter, r *http.Request) {
+	fake := filterResponse{
+		w: w,
+		edit: func(buf []byte) []byte {
+			return bytes.ReplaceAll(buf, []byte{0}, []byte{' '})
+		},
+	}
+	pprof.Cmdline(fake, r)
+}
+
 func (i *Instance) getCache(r *http.Request) interface{} {
 	return i.State.Cache(path.Base(r.URL.Path))
 }
@@ -354,6 +384,7 @@
 // It also logs the port the server starts on, to allow for :0 auto assigned
 // ports.
 func (i *Instance) Serve(ctx context.Context) error {
+	log.SetFlags(log.Lshortfile)
 	if i.DebugAddress == "" {
 		return nil
 	}
@@ -373,7 +404,7 @@
 		mux.HandleFunc("/", render(mainTmpl, func(*http.Request) interface{} { return i }))
 		mux.HandleFunc("/debug/", render(debugTmpl, nil))
 		mux.HandleFunc("/debug/pprof/", pprof.Index)
-		mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
+		mux.HandleFunc("/debug/pprof/cmdline", cmdline)
 		mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
 		mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
 		mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
@@ -624,7 +655,7 @@
 {{define "serverlink"}}<a href="/server/{{.}}">Server {{.}}</a>{{end}}
 {{define "sessionlink"}}<a href="/session/{{.}}">Session {{.}}</a>{{end}}
 {{define "viewlink"}}<a href="/view/{{.}}">View {{.}}</a>{{end}}
-{{define "filelink"}}<a href="/file/{{.SessionID}}/{{.Identifier}}">{{.URI}}</a>{{end}}
+{{define "filelink"}}<a href="/file/{{.Session}}/{{.FileIdentity.Hash}}">{{.FileIdentity.URI}}</a>{{end}}
 `)).Funcs(template.FuncMap{
 	"fuint64":  fuint64,
 	"fuint32":  fuint32,
@@ -747,7 +778,7 @@
 <h2>Views</h2>
 <ul>{{range .Views}}<li>{{.Name}} is {{template "viewlink" .ID}} in {{.Folder}}</li>{{end}}</ul>
 <h2>Overlays</h2>
-<ul>{{range .Overlays}}<li>{{template "filelink" .Identity}}</li>{{end}}</ul>
+<ul>{{range .Overlays}}<li>{{template "filelink" .}}</li>{{end}}</ul>
 {{end}}
 `))
 
@@ -763,16 +794,16 @@
 `))
 
 var fileTmpl = template.Must(template.Must(baseTemplate.Clone()).Parse(`
-{{define "title"}}Overlay {{.Identity.Identifier}}{{end}}
+{{define "title"}}Overlay {{.FileIdentity.Hash}}{{end}}
 {{define "body"}}
-{{with .Identity}}
-	From: <b>{{template "sessionlink" .SessionID}}</b><br>
+{{with .}}
+	From: <b>{{template "sessionlink" .Session}}</b><br>
 	URI: <b>{{.URI}}</b><br>
-	Identifier: <b>{{.Identifier}}</b><br>
+	Identifier: <b>{{.FileIdentity.Hash}}</b><br>
 	Version: <b>{{.Version}}</b><br>
 	Kind: <b>{{.Kind}}</b><br>
 {{end}}
 <h3>Contents</h3>
-<pre>{{fcontent .Data}}</pre>
+<pre>{{fcontent .Read}}</pre>
 {{end}}
 `))