internal/lsp: check content format instead of assuming markdown

Fixes golang/go#31078

Change-Id: I2227f64d839d65d7b46d43e1b90f5b1dc298bf6f
Reviewed-on: https://go-review.googlesource.com/c/tools/+/172601
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
diff --git a/internal/lsp/cmd/cmd.go b/internal/lsp/cmd/cmd.go
index 0262c03..ffb02c8 100644
--- a/internal/lsp/cmd/cmd.go
+++ b/internal/lsp/cmd/cmd.go
@@ -150,9 +150,12 @@
 		}
 		go jc.Run(ctx)
 	}
+
 	params := &protocol.InitializeParams{}
 	params.RootURI = string(span.FileURI(app.Config.Dir))
 	params.Capabilities.Workspace.Configuration = true
+	params.Capabilities.TextDocument.Hover.ContentFormat = []protocol.MarkupKind{protocol.PlainText}
+
 	client.prepare(app, server)
 	if _, err := server.Initialize(ctx, params); err != nil {
 		return nil, err
diff --git a/internal/lsp/cmd/definition.go b/internal/lsp/cmd/definition.go
index c906dc2..4e9b97e 100644
--- a/internal/lsp/cmd/definition.go
+++ b/internal/lsp/cmd/definition.go
@@ -100,13 +100,7 @@
 	if err != nil {
 		return fmt.Errorf("%v: %v", from, err)
 	}
-	//TODO: either work out how to request plain text, or
-	//use a less kludgy way of cleaning the markdown
-	description := hover.Contents.Value
-	if v := strings.TrimPrefix(description, "```go"); v != description {
-		description = strings.TrimSuffix(v, "```")
-	}
-	description = strings.TrimSpace(description)
+	description := strings.TrimSpace(hover.Contents.Value)
 	var result interface{}
 	switch d.query.Emulate {
 	case "":
diff --git a/internal/lsp/general.go b/internal/lsp/general.go
index 3991581..b97d46d 100644
--- a/internal/lsp/general.go
+++ b/internal/lsp/general.go
@@ -105,6 +105,12 @@
 	// Check if the client supports configuration messages.
 	s.configurationSupported = caps.Workspace.Configuration
 	s.dynamicConfigurationSupported = caps.Workspace.DidChangeConfiguration.DynamicRegistration
+
+	// Check which types of content format are supported by this client.
+	s.preferredContentFormat = protocol.PlainText
+	if len(caps.TextDocument.Hover.ContentFormat) > 0 {
+		s.preferredContentFormat = caps.TextDocument.Hover.ContentFormat[0]
+	}
 }
 
 func (s *Server) initialized(ctx context.Context, params *protocol.InitializedParams) error {
diff --git a/internal/lsp/hover.go b/internal/lsp/hover.go
index 8348251..8a8e218 100644
--- a/internal/lsp/hover.go
+++ b/internal/lsp/hover.go
@@ -35,7 +35,6 @@
 	if err != nil {
 		return nil, err
 	}
-	markdown := "```go\n" + content + "\n```"
 	identSpan, err := ident.Range.Span()
 	if err != nil {
 		return nil, err
@@ -45,10 +44,20 @@
 		return nil, err
 	}
 	return &protocol.Hover{
-		Contents: protocol.MarkupContent{
-			Kind:  protocol.Markdown,
-			Value: markdown,
-		},
-		Range: &rng,
+		Contents: markupContent(content, s.preferredContentFormat),
+		Range:    &rng,
 	}, nil
 }
+
+func markupContent(content string, kind protocol.MarkupKind) protocol.MarkupContent {
+	result := protocol.MarkupContent{
+		Kind: kind,
+	}
+	switch kind {
+	case protocol.PlainText:
+		result.Value = content
+	case protocol.Markdown:
+		result.Value = "```go\n" + content + "\n```"
+	}
+	return result
+}
diff --git a/internal/lsp/server.go b/internal/lsp/server.go
index 2d7947e..54bfd1a 100644
--- a/internal/lsp/server.go
+++ b/internal/lsp/server.go
@@ -77,6 +77,7 @@
 	insertTextFormat              protocol.InsertTextFormat
 	configurationSupported        bool
 	dynamicConfigurationSupported bool
+	preferredContentFormat        protocol.MarkupKind
 
 	textDocumentSyncKind protocol.TextDocumentSyncKind