Commit e281576b authored by Robert Griesemer's avatar Robert Griesemer

go/doc: switch ToHTML from []byte to string argument

- this removes extra conversions from strings to bytes and vice versa
  for each comment
- minor cleanups

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5434096
parent 158ca3c4
...@@ -456,7 +456,7 @@ func comment_htmlFunc(comment string) string { ...@@ -456,7 +456,7 @@ func comment_htmlFunc(comment string) string {
var buf bytes.Buffer var buf bytes.Buffer
// TODO(gri) Provide list of words (e.g. function parameters) // TODO(gri) Provide list of words (e.g. function parameters)
// to be emphasized by ToHTML. // to be emphasized by ToHTML.
doc.ToHTML(&buf, []byte(comment), nil) // does html-escaping doc.ToHTML(&buf, comment, nil) // does html-escaping
return buf.String() return buf.String()
} }
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
package doc package doc
import ( import (
"bytes"
"go/ast" "go/ast"
"io" "io"
"regexp" "regexp"
...@@ -85,39 +84,6 @@ func CommentText(comment *ast.CommentGroup) string { ...@@ -85,39 +84,6 @@ func CommentText(comment *ast.CommentGroup) string {
return strings.Join(lines, "\n") return strings.Join(lines, "\n")
} }
// Split bytes into lines.
func split(text []byte) [][]byte {
// count lines
n := 0
last := 0
for i, c := range text {
if c == '\n' {
last = i + 1
n++
}
}
if last < len(text) {
n++
}
// split
out := make([][]byte, n)
last = 0
n = 0
for i, c := range text {
if c == '\n' {
out[n] = text[last : i+1]
last = i + 1
n++
}
}
if last < len(text) {
out[n] = text[last:]
}
return out
}
var ( var (
ldquo = []byte("&ldquo;") ldquo = []byte("&ldquo;")
rdquo = []byte("&rdquo;") rdquo = []byte("&rdquo;")
...@@ -125,13 +91,13 @@ var ( ...@@ -125,13 +91,13 @@ var (
// Escape comment text for HTML. If nice is set, // Escape comment text for HTML. If nice is set,
// also turn `` into &ldquo; and '' into &rdquo;. // also turn `` into &ldquo; and '' into &rdquo;.
func commentEscape(w io.Writer, s []byte, nice bool) { func commentEscape(w io.Writer, text string, nice bool) {
last := 0 last := 0
if nice { if nice {
for i := 0; i < len(s)-1; i++ { for i := 0; i < len(text)-1; i++ {
ch := s[i] ch := text[i]
if ch == s[i+1] && (ch == '`' || ch == '\'') { if ch == text[i+1] && (ch == '`' || ch == '\'') {
template.HTMLEscape(w, s[last:i]) template.HTMLEscape(w, []byte(text[last:i]))
last = i + 2 last = i + 2
switch ch { switch ch {
case '`': case '`':
...@@ -143,7 +109,7 @@ func commentEscape(w io.Writer, s []byte, nice bool) { ...@@ -143,7 +109,7 @@ func commentEscape(w io.Writer, s []byte, nice bool) {
} }
} }
} }
template.HTMLEscape(w, s[last:]) template.HTMLEscape(w, []byte(text[last:]))
} }
const ( const (
...@@ -183,9 +149,9 @@ var ( ...@@ -183,9 +149,9 @@ var (
// and the word is converted into a link. If nice is set, the remaining text's // and the word is converted into a link. If nice is set, the remaining text's
// appearance is improved where it makes sense (e.g., `` is turned into &ldquo; // appearance is improved where it makes sense (e.g., `` is turned into &ldquo;
// and '' into &rdquo;). // and '' into &rdquo;).
func emphasize(w io.Writer, line []byte, words map[string]string, nice bool) { func emphasize(w io.Writer, line string, words map[string]string, nice bool) {
for { for {
m := matchRx.FindSubmatchIndex(line) m := matchRx.FindStringSubmatchIndex(line)
if m == nil { if m == nil {
break break
} }
...@@ -233,7 +199,7 @@ func emphasize(w io.Writer, line []byte, words map[string]string, nice bool) { ...@@ -233,7 +199,7 @@ func emphasize(w io.Writer, line []byte, words map[string]string, nice bool) {
commentEscape(w, line, nice) commentEscape(w, line, nice)
} }
func indentLen(s []byte) int { func indentLen(s string) int {
i := 0 i := 0
for i < len(s) && (s[i] == ' ' || s[i] == '\t') { for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
i++ i++
...@@ -241,9 +207,11 @@ func indentLen(s []byte) int { ...@@ -241,9 +207,11 @@ func indentLen(s []byte) int {
return i return i
} }
func isBlank(s []byte) bool { return len(s) == 0 || (len(s) == 1 && s[0] == '\n') } func isBlank(s string) bool {
return len(s) == 0 || (len(s) == 1 && s[0] == '\n')
}
func commonPrefix(a, b []byte) []byte { func commonPrefix(a, b string) string {
i := 0 i := 0
for i < len(a) && i < len(b) && a[i] == b[i] { for i < len(a) && i < len(b) && a[i] == b[i] {
i++ i++
...@@ -251,7 +219,7 @@ func commonPrefix(a, b []byte) []byte { ...@@ -251,7 +219,7 @@ func commonPrefix(a, b []byte) []byte {
return a[0:i] return a[0:i]
} }
func unindent(block [][]byte) { func unindent(block []string) {
if len(block) == 0 { if len(block) == 0 {
return return
} }
...@@ -274,23 +242,23 @@ func unindent(block [][]byte) { ...@@ -274,23 +242,23 @@ func unindent(block [][]byte) {
} }
// heading returns the (possibly trimmed) line if it passes as a valid section // heading returns the (possibly trimmed) line if it passes as a valid section
// heading; otherwise it returns nil. // heading; otherwise it returns the empty string.
func heading(line []byte) []byte { func heading(line string) string {
line = bytes.TrimSpace(line) line = strings.TrimSpace(line)
if len(line) == 0 { if len(line) == 0 {
return nil return ""
} }
// a heading must start with an uppercase letter // a heading must start with an uppercase letter
r, _ := utf8.DecodeRune(line) r, _ := utf8.DecodeRuneInString(line)
if !unicode.IsLetter(r) || !unicode.IsUpper(r) { if !unicode.IsLetter(r) || !unicode.IsUpper(r) {
return nil return ""
} }
// it must end in a letter, digit or ':' // it must end in a letter, digit or ':'
r, _ = utf8.DecodeLastRune(line) r, _ = utf8.DecodeLastRuneInString(line)
if !unicode.IsLetter(r) && !unicode.IsDigit(r) && r != ':' { if !unicode.IsLetter(r) && !unicode.IsDigit(r) && r != ':' {
return nil return ""
} }
// strip trailing ':', if any // strip trailing ':', if any
...@@ -299,18 +267,18 @@ func heading(line []byte) []byte { ...@@ -299,18 +267,18 @@ func heading(line []byte) []byte {
} }
// exclude lines with illegal characters // exclude lines with illegal characters
if bytes.IndexAny(line, ",.;:!?+*/=()[]{}_^°&§~%#@<\">\\") >= 0 { if strings.IndexAny(line, ",.;:!?+*/=()[]{}_^°&§~%#@<\">\\") >= 0 {
return nil return ""
} }
// allow "'" for possessive "'s" only // allow "'" for possessive "'s" only
for b := line; ; { for b := line; ; {
i := bytes.IndexRune(b, '\'') i := strings.IndexRune(b, '\'')
if i < 0 { if i < 0 {
break break
} }
if i+1 >= len(b) || b[i+1] != 's' || (i+2 < len(b) && b[i+2] != ' ') { if i+1 >= len(b) || b[i+1] != 's' || (i+2 < len(b) && b[i+2] != ' ') {
return nil // not followed by "s " return "" // not followed by "s "
} }
b = b[i+2:] b = b[i+2:]
} }
...@@ -335,7 +303,7 @@ func heading(line []byte) []byte { ...@@ -335,7 +303,7 @@ func heading(line []byte) []byte {
// Go identifiers that appear in the words map are italicized; if the corresponding // Go identifiers that appear in the words map are italicized; if the corresponding
// map value is not the empty string, it is considered a URL and the word is converted // map value is not the empty string, it is considered a URL and the word is converted
// into a link. // into a link.
func ToHTML(w io.Writer, s []byte, words map[string]string) { func ToHTML(w io.Writer, text string, words map[string]string) {
inpara := false inpara := false
lastWasBlank := false lastWasBlank := false
lastWasHeading := false lastWasHeading := false
...@@ -353,7 +321,7 @@ func ToHTML(w io.Writer, s []byte, words map[string]string) { ...@@ -353,7 +321,7 @@ func ToHTML(w io.Writer, s []byte, words map[string]string) {
} }
} }
lines := split(s) lines := strings.SplitAfter(text, "\n")
unindent(lines) unindent(lines)
for i := 0; i < len(lines); { for i := 0; i < len(lines); {
line := lines[i] line := lines[i]
...@@ -397,10 +365,10 @@ func ToHTML(w io.Writer, s []byte, words map[string]string) { ...@@ -397,10 +365,10 @@ func ToHTML(w io.Writer, s []byte, words map[string]string) {
// current line is non-blank, sourounded by blank lines // current line is non-blank, sourounded by blank lines
// and the next non-blank line is not indented: this // and the next non-blank line is not indented: this
// might be a heading. // might be a heading.
if head := heading(line); head != nil { if head := heading(line); head != "" {
close() close()
w.Write(html_h) w.Write(html_h)
template.HTMLEscape(w, head) commentEscape(w, head, true) // nice text formatting
w.Write(html_endh) w.Write(html_endh)
i += 2 i += 2
lastWasHeading = true lastWasHeading = true
......
...@@ -32,7 +32,7 @@ var headingTests = []struct { ...@@ -32,7 +32,7 @@ var headingTests = []struct {
func TestIsHeading(t *testing.T) { func TestIsHeading(t *testing.T) {
for _, tt := range headingTests { for _, tt := range headingTests {
if h := heading([]byte(tt.line)); (h != nil) != tt.ok { if h := heading(tt.line); (len(h) > 0) != tt.ok {
t.Errorf("isHeading(%q) = %v, want %v", tt.line, h, tt.ok) t.Errorf("isHeading(%q) = %v, want %v", tt.line, h, tt.ok)
} }
} }
......
...@@ -43,7 +43,7 @@ func isGoFile(fi os.FileInfo) bool { ...@@ -43,7 +43,7 @@ func isGoFile(fi os.FileInfo) bool {
func appendHeadings(list []string, comment string) []string { func appendHeadings(list []string, comment string) []string {
var buf bytes.Buffer var buf bytes.Buffer
doc.ToHTML(&buf, []byte(comment), nil) doc.ToHTML(&buf, comment, nil)
for s := buf.String(); ; { for s := buf.String(); ; {
i := strings.Index(s, html_h) i := strings.Index(s, html_h)
if i < 0 { if i < 0 {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment