internal/lsp: move PrintVersionInfo to the debug package

Also add a new rendering mode, and clean up the plain text one.
Then use it to add an info page to to the server in debug mode.

Change-Id: Ifa66a75260965d0e46e874200203ebbc4490e424
Reviewed-on: https://go-review.googlesource.com/c/tools/+/179497
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/internal/lsp/cmd/info.go b/internal/lsp/cmd/info.go
index 2514405..9024464 100644
--- a/internal/lsp/cmd/info.go
+++ b/internal/lsp/cmd/info.go
@@ -13,8 +13,8 @@
 	"os"
 	"strings"
 
-	"golang.org/x/tools/internal/lsp"
 	"golang.org/x/tools/internal/lsp/browser"
+	"golang.org/x/tools/internal/lsp/debug"
 )
 
 // version implements the version command.
@@ -36,7 +36,7 @@
 // Run collects some basic information and then prepares an issue ready to
 // be reported.
 func (v *version) Run(ctx context.Context, args ...string) error {
-	lsp.PrintVersionInfo(os.Stdout, v.app.Verbose, false)
+	debug.PrintVersionInfo(os.Stdout, v.app.Verbose, debug.PlainText)
 	return nil
 }
 
@@ -70,7 +70,7 @@
 func (b *bug) Run(ctx context.Context, args ...string) error {
 	buf := &bytes.Buffer{}
 	fmt.Fprint(buf, goplsBugHeader)
-	lsp.PrintVersionInfo(buf, true, true)
+	debug.PrintVersionInfo(buf, true, debug.Markdown)
 	body := buf.String()
 	title := strings.Join(args, " ")
 	if !strings.HasPrefix(title, goplsBugPrefix) {
diff --git a/internal/lsp/info.1.11.go b/internal/lsp/debug/info.1.11.go
similarity index 78%
rename from internal/lsp/info.1.11.go
rename to internal/lsp/debug/info.1.11.go
index ac4128f..b29a157 100644
--- a/internal/lsp/info.1.11.go
+++ b/internal/lsp/debug/info.1.11.go
@@ -4,13 +4,13 @@
 
 // +build !go1.12
 
-package lsp
+package debug
 
 import (
 	"fmt"
 	"io"
 )
 
-func printBuildInfo(w io.Writer, verbose bool) {
+func printBuildInfo(w io.Writer, verbose bool, mode PrintMode) {
 	fmt.Fprintf(w, "no module information, gopls not built with go 1.11 or earlier\n")
 }
diff --git a/internal/lsp/info.go b/internal/lsp/debug/info.1.12.go
similarity index 74%
rename from internal/lsp/info.go
rename to internal/lsp/debug/info.1.12.go
index 476ebb8..70856f6 100644
--- a/internal/lsp/info.go
+++ b/internal/lsp/debug/info.1.12.go
@@ -4,7 +4,7 @@
 
 // +build go1.12
 
-package lsp
+package debug
 
 import (
 	"fmt"
@@ -12,13 +12,13 @@
 	"runtime/debug"
 )
 
-func printBuildInfo(w io.Writer, verbose bool) {
+func printBuildInfo(w io.Writer, verbose bool, mode PrintMode) {
 	if info, ok := debug.ReadBuildInfo(); ok {
 		fmt.Fprintf(w, "%v\n", info.Path)
-		printModuleInfo(w, &info.Main)
+		printModuleInfo(w, &info.Main, mode)
 		if verbose {
 			for _, dep := range info.Deps {
-				printModuleInfo(w, dep)
+				printModuleInfo(w, dep, mode)
 			}
 		}
 	} else {
@@ -26,7 +26,7 @@
 	}
 }
 
-func printModuleInfo(w io.Writer, m *debug.Module) {
+func printModuleInfo(w io.Writer, m *debug.Module, mode PrintMode) {
 	fmt.Fprintf(w, "    %s@%s", m.Path, m.Version)
 	if m.Sum != "" {
 		fmt.Fprintf(w, " %s", m.Sum)
diff --git a/internal/lsp/debug/info.go b/internal/lsp/debug/info.go
new file mode 100644
index 0000000..4173a91
--- /dev/null
+++ b/internal/lsp/debug/info.go
@@ -0,0 +1,58 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package debug
+
+import (
+	"fmt"
+	"io"
+	"os/exec"
+	"strings"
+)
+
+type PrintMode int
+
+const (
+	PlainText = PrintMode(iota)
+	Markdown
+	HTML
+)
+
+// This writes the version and environment information to a writer.
+func PrintVersionInfo(w io.Writer, verbose bool, mode PrintMode) {
+	if !verbose {
+		printBuildInfo(w, false, mode)
+		return
+	}
+	section(w, mode, "Build info", func() {
+		printBuildInfo(w, true, mode)
+	})
+	fmt.Fprint(w, "\n")
+	section(w, mode, "Go info", func() {
+		cmd := exec.Command("go", "version")
+		cmd.Stdout = w
+		cmd.Run()
+		fmt.Fprint(w, "\n")
+		cmd = exec.Command("go", "env")
+		cmd.Stdout = w
+		cmd.Run()
+	})
+}
+
+func section(w io.Writer, mode PrintMode, title string, body func()) {
+	switch mode {
+	case PlainText:
+		fmt.Fprintln(w, title)
+		fmt.Fprintln(w, strings.Repeat("-", len(title)))
+		body()
+	case Markdown:
+		fmt.Fprintf(w, "#### %s\n\n```\n", title)
+		body()
+		fmt.Fprintf(w, "```\n")
+	case HTML:
+		fmt.Fprintf(w, "<h3>%s</h3>\n<pre>\n", title)
+		body()
+		fmt.Fprint(w, "</pre>\n")
+	}
+}
diff --git a/internal/lsp/debug/serve.go b/internal/lsp/debug/serve.go
index bbe34e0..c5a1bbd 100644
--- a/internal/lsp/debug/serve.go
+++ b/internal/lsp/debug/serve.go
@@ -5,6 +5,7 @@
 package debug
 
 import (
+	"bytes"
 	"context"
 	"html/template"
 	"log"
@@ -16,6 +17,13 @@
 func init() {
 	http.HandleFunc("/", Render(mainTmpl, nil))
 	http.HandleFunc("/debug/", Render(debugTmpl, nil))
+	http.HandleFunc("/info", Render(infoTmpl, getInfo))
+}
+
+func getInfo(r *http.Request) interface{} {
+	buf := &bytes.Buffer{}
+	PrintVersionInfo(buf, true, HTML)
+	return template.HTML(buf.String())
 }
 
 // Serve starts and runs a debug server in the background.
@@ -64,9 +72,12 @@
 </style>
 </head>
 <body>
-{{template "title"}}
-<br>
-{{block "body" .Data}}
+<a href="/">Main</a>
+<a href="/info">Info</a>
+<a href="/debug/">Debug</a>
+<hr>
+<h1>{{template "title" .}}</h1>
+{{block "body" .}}
 Unknown page
 {{end}}
 </body>
@@ -76,7 +87,13 @@
 var mainTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
 {{define "title"}}GoPls server information{{end}}
 {{define "body"}}
-<A href="/debug/">Debug</A>
+{{end}}
+`))
+
+var infoTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
+{{define "title"}}GoPls version information{{end}}
+{{define "body"}}
+{{.}}
 {{end}}
 `))
 
diff --git a/internal/lsp/general.go b/internal/lsp/general.go
index 6091519..8ddbe59 100644
--- a/internal/lsp/general.go
+++ b/internal/lsp/general.go
@@ -12,6 +12,7 @@
 	"path"
 
 	"golang.org/x/tools/internal/jsonrpc2"
+	"golang.org/x/tools/internal/lsp/debug"
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/source"
 	"golang.org/x/tools/internal/span"
@@ -140,7 +141,7 @@
 		}
 	}
 	buf := &bytes.Buffer{}
-	PrintVersionInfo(buf, true, false)
+	debug.PrintVersionInfo(buf, true, debug.PlainText)
 	s.session.Logger().Infof(ctx, "%s", buf)
 	return nil
 }
diff --git a/internal/lsp/util.go b/internal/lsp/util.go
index b931078..427ff07 100644
--- a/internal/lsp/util.go
+++ b/internal/lsp/util.go
@@ -7,45 +7,12 @@
 import (
 	"context"
 	"fmt"
-	"io"
-	"os/exec"
 
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/source"
 	"golang.org/x/tools/internal/span"
 )
 
-// This writes the version and environment information to a writer.
-func PrintVersionInfo(w io.Writer, verbose bool, markdown bool) {
-	if !verbose {
-		printBuildInfo(w, false)
-		return
-	}
-	fmt.Fprint(w, "#### Build info\n\n")
-	if markdown {
-		fmt.Fprint(w, "```\n")
-	}
-	printBuildInfo(w, true)
-	fmt.Fprint(w, "\n")
-	if markdown {
-		fmt.Fprint(w, "```\n")
-	}
-	fmt.Fprint(w, "\n#### Go info\n\n")
-	if markdown {
-		fmt.Fprint(w, "```\n")
-	}
-	cmd := exec.Command("go", "version")
-	cmd.Stdout = w
-	cmd.Run()
-	fmt.Fprint(w, "\n")
-	cmd = exec.Command("go", "env")
-	cmd.Stdout = w
-	cmd.Run()
-	if markdown {
-		fmt.Fprint(w, "```\n")
-	}
-}
-
 func getSourceFile(ctx context.Context, v source.View, uri span.URI) (source.File, *protocol.ColumnMapper, error) {
 	f, err := v.GetFile(ctx, uri)
 	if err != nil {