1
0
mirror of https://github.com/golang/go synced 2024-11-23 00:50:05 -07:00

go/doc: convert to unicode quotes for ToText and Synopsis

We refactor the conversion of quotes to their unicode equivalent
to a separate function so that it can be called from ToText and Synopsis.

And we introduce a temp buffer to write the escaped HTML and convert
the unicode quotes back to html escaped entities. This simplifies the logic
and gets rid of the need to track the index of the escaped text.

Fixes #27759

Change-Id: I71cf47ddcd4c6794ccdf2898ac25539388b393c1
Reviewed-on: https://go-review.googlesource.com/c/150377
Run-TryBot: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Agniva De Sarker 2018-11-20 11:13:03 +05:30 committed by Robert Griesemer
parent 689fae2d78
commit 81a5c9c306
4 changed files with 49 additions and 19 deletions

View File

@ -7,6 +7,7 @@
package doc
import (
"bytes"
"io"
"strings"
"text/template" // for HTMLEscape
@ -14,32 +15,38 @@ import (
"unicode/utf8"
)
const (
ldquo = "&ldquo;"
rdquo = "&rdquo;"
ulquo = "“"
urquo = "”"
)
var (
ldquo = []byte("&ldquo;")
rdquo = []byte("&rdquo;")
htmlQuoteReplacer = strings.NewReplacer(ulquo, ldquo, urquo, rdquo)
unicodeQuoteReplacer = strings.NewReplacer("``", ulquo, "''", urquo)
)
// Escape comment text for HTML. If nice is set,
// also turn `` into &ldquo; and '' into &rdquo;.
func commentEscape(w io.Writer, text string, nice bool) {
last := 0
if nice {
for i := 0; i < len(text)-1; i++ {
ch := text[i]
if ch == text[i+1] && (ch == '`' || ch == '\'') {
template.HTMLEscape(w, []byte(text[last:i]))
last = i + 2
switch ch {
case '`':
w.Write(ldquo)
case '\'':
w.Write(rdquo)
}
i++ // loop will add one more
}
}
// In the first pass, we convert `` and '' into their unicode equivalents.
// This prevents them from being escaped in HTMLEscape.
text = convertQuotes(text)
var buf bytes.Buffer
template.HTMLEscape(&buf, []byte(text))
// Now we convert the unicode quotes to their HTML escaped entities to maintain old behavior.
// We need to use a temp buffer to read the string back and do the conversion,
// otherwise HTMLEscape will escape & to &amp;
htmlQuoteReplacer.WriteString(w, buf.String())
return
}
template.HTMLEscape(w, []byte(text[last:]))
template.HTMLEscape(w, []byte(text))
}
func convertQuotes(text string) string {
return unicodeQuoteReplacer.Replace(text)
}
const (
@ -248,7 +255,7 @@ func heading(line string) string {
}
// allow "." when followed by non-space
for b := line;; {
for b := line; ; {
i := strings.IndexRune(b, '.')
if i < 0 {
break
@ -429,12 +436,14 @@ func ToText(w io.Writer, text string, indent, preIndent string, width int) {
case opPara:
// l.write will add leading newline if required
for _, line := range b.lines {
line = convertQuotes(line)
l.write(line)
}
l.flush()
case opHead:
w.Write(nl)
for _, line := range b.lines {
line = convertQuotes(line)
l.write(line + "\n")
}
l.flush()
@ -445,6 +454,7 @@ func ToText(w io.Writer, text string, indent, preIndent string, width int) {
w.Write([]byte("\n"))
} else {
w.Write([]byte(preIndent))
line = convertQuotes(line)
w.Write([]byte(line))
}
}

View File

@ -7,6 +7,7 @@ package doc
import (
"bytes"
"reflect"
"strings"
"testing"
)
@ -212,3 +213,20 @@ func TestPairedParensPrefixLen(t *testing.T) {
}
}
}
func TestCommentEscape(t *testing.T) {
commentTests := []struct {
in, out string
}{
{"typically invoked as ``go tool asm'',", "typically invoked as " + ldquo + "go tool asm" + rdquo + ","},
{"For more detail, run ``go help test'' and ``go help testflag''", "For more detail, run " + ldquo + "go help test" + rdquo + " and " + ldquo + "go help testflag" + rdquo},
}
for i, tt := range commentTests {
var buf strings.Builder
commentEscape(&buf, tt.in, true)
out := buf.String()
if out != tt.out {
t.Errorf("#%d: mismatch\nhave: %q\nwant: %q", i, out, tt.out)
}
}
}

View File

@ -72,6 +72,7 @@ func Synopsis(s string) string {
return ""
}
}
s = convertQuotes(s)
return s
}

View File

@ -35,6 +35,7 @@ var tests = []struct {
{"All Rights reserved. Package foo does bar.", 20, ""},
{"All rights reserved. Package foo does bar.", 20, ""},
{"Authors: foo@bar.com. Package foo does bar.", 21, ""},
{"typically invoked as ``go tool asm'',", 37, "typically invoked as " + ulquo + "go tool asm" + urquo + ","},
}
func TestSynopsis(t *testing.T) {