internal/godoc/dochtml/internal/render: don't smart quote in <pre> blocks

Fixes golang/go#51807.

Change-Id: I8ab6c9362ef79a286c0480d14a4905f8fe4c0c84
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/394034
Trust: Jamal Carvalho <jamal@golang.org>
Reviewed-by: Jamal Carvalho <jamal@golang.org>
Reviewed-by: Jamal Carvalho <jamalcarvalho@google.com>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
diff --git a/internal/godoc/dochtml/internal/render/linkify.go b/internal/godoc/dochtml/internal/render/linkify.go
index c03d560..9e33743 100644
--- a/internal/godoc/dochtml/internal/render/linkify.go
+++ b/internal/godoc/dochtml/internal/render/linkify.go
@@ -93,7 +93,7 @@
 			if inLinks {
 				r.links = append(r.links, parseLinks(blk.lines)...)
 			} else {
-				el.Body = r.linesToHTML(blk.lines)
+				el.Body = r.linesToHTML(blk.lines, false)
 				els = append(els, el)
 			}
 		case *preformat:
@@ -101,7 +101,7 @@
 				r.links = append(r.links, parseLinks(blk.lines)...)
 			} else {
 				el.IsPreformat = true
-				el.Body = r.linesToHTML(blk.lines)
+				el.Body = r.linesToHTML(blk.lines, true)
 				els = append(els, el)
 			}
 		case *heading:
@@ -159,11 +159,11 @@
 	}
 }
 
-func (r *Renderer) linesToHTML(lines []string) safehtml.HTML {
+func (r *Renderer) linesToHTML(lines []string, pre bool) safehtml.HTML {
 	newline := safehtml.HTMLEscaped("\n")
 	htmls := make([]safehtml.HTML, 0, 2*len(lines))
 	for _, l := range lines {
-		htmls = append(htmls, r.formatLineHTML(l))
+		htmls = append(htmls, r.formatLineHTML(l, pre))
 		htmls = append(htmls, newline)
 	}
 	return safehtml.HTMLConcat(htmls...)
@@ -264,7 +264,8 @@
 
 // formatLineHTML formats the line as HTML-annotated text.
 // URLs and Go identifiers are linked to corresponding declarations.
-func (r *Renderer) formatLineHTML(line string) safehtml.HTML {
+// If pre is true no conversion of `` or '' to “ and ” is performed.
+func (r *Renderer) formatLineHTML(line string, pre bool) safehtml.HTML {
 	var htmls []safehtml.HTML
 	var numQuotes int
 
@@ -272,7 +273,9 @@
 		htmls = append(htmls, ExecuteToHTML(LinkTemplate, Link{Href: href, Text: text}))
 	}
 
-	line = convertQuotes(line)
+	if !pre {
+		line = convertQuotes(line)
+	}
 	for len(line) > 0 {
 		m0, m1 := len(line), len(line)
 		if m := matchRx.FindStringIndex(line); m != nil {
@@ -425,7 +428,7 @@
 			tokType = commentType
 			htmlLines[line] = append(htmlLines[line],
 				template.MustParseAndExecuteToHTML(`<span class="comment">`),
-				r.formatLineHTML(lit),
+				r.formatLineHTML(lit, false),
 				template.MustParseAndExecuteToHTML(`</span>`))
 			lastOffset += len(lit)
 		case token.IDENT:
diff --git a/internal/godoc/dochtml/internal/render/linkify_test.go b/internal/godoc/dochtml/internal/render/linkify_test.go
index c62d9ea..0d6b8ad 100644
--- a/internal/godoc/dochtml/internal/render/linkify_test.go
+++ b/internal/godoc/dochtml/internal/render/linkify_test.go
@@ -151,6 +151,12 @@
 			doc:  "For more detail, run ``go help test'' and ``go help testflag''",
 			want: `<p>For more detail, run “go help test” and “go help testflag”` + "\n" + "</p>",
 		},
+		{
+			name: "single quotes in pre block",
+			doc: `Join
+			    [].join() // returns ''`,
+			want: `<p>Join` + "\n" + `</p><pre>[].join() // returns &#39;&#39;` + "\n" + `</pre>`,
+		},
 	} {
 		t.Run(test.name, func(t *testing.T) {
 			extractLinks := test.extractLinks