mirror of
https://github.com/golang/go
synced 2024-11-24 09:30:07 -07:00
go/doc/comment: parse and print code
[This CL is part of a sequence implementing the proposal #51082. The design doc is at https://go.dev/s/godocfmt-design.] Implement indented code blocks. For #51082. Change-Id: I0eacbf56e101424a875386cb6f26174b239561f5 Reviewed-on: https://go-review.googlesource.com/c/go/+/397285 Run-TryBot: Russ Cox <rsc@golang.org> Reviewed-by: Jonathan Amsterdam <jba@google.com> Reviewed-by: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
parent
6eceabf119
commit
3f5d099663
@ -51,6 +51,11 @@ func (p *htmlPrinter) block(out *bytes.Buffer, x Block) {
|
||||
out.WriteString("</h")
|
||||
out.WriteString(h)
|
||||
out.WriteString(">\n")
|
||||
|
||||
case *Code:
|
||||
out.WriteString("<pre>")
|
||||
p.escape(out, x.Text)
|
||||
out.WriteString("</pre>\n")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,6 +54,18 @@ func (p *mdPrinter) block(out *bytes.Buffer, x Block) {
|
||||
out.WriteString("}")
|
||||
}
|
||||
out.WriteString("\n")
|
||||
|
||||
case *Code:
|
||||
md := x.Text
|
||||
for md != "" {
|
||||
var line string
|
||||
line, md, _ = strings.Cut(md, "\n")
|
||||
if line != "" {
|
||||
out.WriteString("\t")
|
||||
out.WriteString(line)
|
||||
}
|
||||
out.WriteString("\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -309,6 +309,9 @@ func (p *Parser) Parse(text string) *Doc {
|
||||
case line == "":
|
||||
// emit nothing
|
||||
|
||||
case isIndented(line):
|
||||
b, lines = d.code(lines)
|
||||
|
||||
case (len(lines) == 1 || lines[1] == "") && !didHeading && isOldHeading(line, all, len(all)-n):
|
||||
b = d.oldHeading(line)
|
||||
didHeading = true
|
||||
@ -473,17 +476,51 @@ func (d *parseDoc) heading(line string) Block {
|
||||
return &Heading{Text: []Text{Plain(strings.TrimSpace(line[1:]))}}
|
||||
}
|
||||
|
||||
// code returns a code block built from the indented text
|
||||
// at the start of lines, along with the remainder of the lines.
|
||||
// If there is no indented text at the start, or if the indented
|
||||
// text consists only of empty lines, code returns a nil Block.
|
||||
func (d *parseDoc) code(lines []string) (b Block, rest []string) {
|
||||
lines, rest = indented(lines)
|
||||
body := unindent(lines)
|
||||
if len(body) == 0 {
|
||||
return nil, rest
|
||||
}
|
||||
body = append(body, "") // to get final \n from Join
|
||||
return &Code{Text: strings.Join(body, "\n")}, rest
|
||||
}
|
||||
|
||||
// isIndented reports whether the line is indented,
|
||||
// meaning it starts with a space or tab.
|
||||
func isIndented(line string) bool {
|
||||
return line != "" && (line[0] == ' ' || line[0] == '\t')
|
||||
}
|
||||
|
||||
// indented splits lines into an initial indented section
|
||||
// and the remaining lines, returning the two halves.
|
||||
func indented(lines []string) (indented, rest []string) {
|
||||
// Blank lines mid-run are OK, but not at the end.
|
||||
i := 0
|
||||
for i < len(lines) && (isIndented(lines[i]) || lines[i] == "") {
|
||||
i++
|
||||
}
|
||||
for i > 0 && lines[i-1] == "" {
|
||||
i--
|
||||
}
|
||||
return lines[:i], lines[i:]
|
||||
}
|
||||
|
||||
// paragraph returns a paragraph block built from the
|
||||
// unindented text at the start of lines, along with the remainder of the lines.
|
||||
// If there is no unindented text at the start of lines,
|
||||
// then paragraph returns a nil Block.
|
||||
func (d *parseDoc) paragraph(lines []string) (b Block, rest []string) {
|
||||
// TODO: Paragraph should be interrupted by any indented line,
|
||||
// Paragraph is interrupted by any indented line,
|
||||
// which is either a list or a code block,
|
||||
// and of course by a blank line.
|
||||
// It should not be interrupted by a # line - headings must stand alone.
|
||||
// It is not interrupted by a # line - headings must stand alone.
|
||||
i := 0
|
||||
for i < len(lines) && lines[i] != "" {
|
||||
for i < len(lines) && lines[i] != "" && !isIndented(lines[i]) {
|
||||
i++
|
||||
}
|
||||
lines, rest = lines[:i], lines[i:]
|
||||
|
@ -213,6 +213,18 @@ func (p *commentPrinter) block(out *bytes.Buffer, x Block) {
|
||||
out.WriteString("# ")
|
||||
p.text(out, "", x.Text)
|
||||
out.WriteString("\n")
|
||||
|
||||
case *Code:
|
||||
md := x.Text
|
||||
for md != "" {
|
||||
var line string
|
||||
line, md, _ = strings.Cut(md, "\n")
|
||||
if line != "" {
|
||||
out.WriteString("\t")
|
||||
out.WriteString(line)
|
||||
}
|
||||
out.WriteString("\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
94
src/go/doc/comment/testdata/code.txt
vendored
Normal file
94
src/go/doc/comment/testdata/code.txt
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
-- input --
|
||||
Text.
|
||||
A tab-indented
|
||||
(no, not eight-space indented)
|
||||
code block and haiku.
|
||||
More text.
|
||||
One space
|
||||
is
|
||||
enough
|
||||
to
|
||||
start
|
||||
a
|
||||
block.
|
||||
More text.
|
||||
|
||||
Blocks
|
||||
can
|
||||
|
||||
have
|
||||
blank
|
||||
lines.
|
||||
-- gofmt --
|
||||
Text.
|
||||
|
||||
A tab-indented
|
||||
(no, not eight-space indented)
|
||||
code block and haiku.
|
||||
|
||||
More text.
|
||||
|
||||
One space
|
||||
is
|
||||
enough
|
||||
to
|
||||
start
|
||||
a
|
||||
block.
|
||||
|
||||
More text.
|
||||
|
||||
Blocks
|
||||
can
|
||||
|
||||
have
|
||||
blank
|
||||
lines.
|
||||
-- markdown --
|
||||
Text.
|
||||
|
||||
A tab-indented
|
||||
(no, not eight-space indented)
|
||||
code block and haiku.
|
||||
|
||||
More text.
|
||||
|
||||
One space
|
||||
is
|
||||
enough
|
||||
to
|
||||
start
|
||||
a
|
||||
block.
|
||||
|
||||
More text.
|
||||
|
||||
Blocks
|
||||
can
|
||||
|
||||
have
|
||||
blank
|
||||
lines.
|
||||
-- html --
|
||||
<p>Text.
|
||||
<pre>A tab-indented
|
||||
(no, not eight-space indented)
|
||||
code block and haiku.
|
||||
</pre>
|
||||
<p>More text.
|
||||
<pre>One space
|
||||
is
|
||||
enough
|
||||
to
|
||||
start
|
||||
a
|
||||
block.
|
||||
</pre>
|
||||
<p>More text.
|
||||
<pre> Blocks
|
||||
can
|
||||
|
||||
have
|
||||
blank
|
||||
lines.
|
||||
</pre>
|
31
src/go/doc/comment/testdata/code2.txt
vendored
Normal file
31
src/go/doc/comment/testdata/code2.txt
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
-- input --
|
||||
Text.
|
||||
|
||||
A tab-indented
|
||||
(no, not eight-space indented)
|
||||
code block and haiku.
|
||||
|
||||
More text.
|
||||
-- gofmt --
|
||||
Text.
|
||||
|
||||
A tab-indented
|
||||
(no, not eight-space indented)
|
||||
code block and haiku.
|
||||
|
||||
More text.
|
||||
-- markdown --
|
||||
Text.
|
||||
|
||||
A tab-indented
|
||||
(no, not eight-space indented)
|
||||
code block and haiku.
|
||||
|
||||
More text.
|
||||
-- html --
|
||||
<p>Text.
|
||||
<pre>A tab-indented
|
||||
(no, not eight-space indented)
|
||||
code block and haiku.
|
||||
</pre>
|
||||
<p>More text.
|
33
src/go/doc/comment/testdata/code3.txt
vendored
Normal file
33
src/go/doc/comment/testdata/code3.txt
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
-- input --
|
||||
Text.
|
||||
|
||||
$
|
||||
A tab-indented
|
||||
(surrounded by more blank lines)
|
||||
code block and haiku.
|
||||
$
|
||||
|
||||
More text.
|
||||
-- gofmt --
|
||||
Text.
|
||||
|
||||
A tab-indented
|
||||
(surrounded by more blank lines)
|
||||
code block and haiku.
|
||||
|
||||
More text.
|
||||
-- markdown --
|
||||
Text.
|
||||
|
||||
A tab-indented
|
||||
(surrounded by more blank lines)
|
||||
code block and haiku.
|
||||
|
||||
More text.
|
||||
-- html --
|
||||
<p>Text.
|
||||
<pre>A tab-indented
|
||||
(surrounded by more blank lines)
|
||||
code block and haiku.
|
||||
</pre>
|
||||
<p>More text.
|
12
src/go/doc/comment/testdata/text9.txt
vendored
Normal file
12
src/go/doc/comment/testdata/text9.txt
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{"TextPrefix":"|", "TextCodePrefix": "@"}
|
||||
-- input --
|
||||
Hello, world
|
||||
Code block here.
|
||||
-- gofmt --
|
||||
Hello, world
|
||||
|
||||
Code block here.
|
||||
-- text --
|
||||
|Hello, world
|
||||
|
|
||||
@Code block here.
|
@ -15,18 +15,23 @@ import (
|
||||
// A textPrinter holds the state needed for printing a Doc as plain text.
|
||||
type textPrinter struct {
|
||||
*Printer
|
||||
long strings.Builder
|
||||
prefix string
|
||||
width int
|
||||
long strings.Builder
|
||||
prefix string
|
||||
codePrefix string
|
||||
width int
|
||||
}
|
||||
|
||||
// Text returns a textual formatting of the Doc.
|
||||
// See the [Printer] documentation for ways to customize the text output.
|
||||
func (p *Printer) Text(d *Doc) []byte {
|
||||
tp := &textPrinter{
|
||||
Printer: p,
|
||||
prefix: p.TextPrefix,
|
||||
width: p.TextWidth,
|
||||
Printer: p,
|
||||
prefix: p.TextPrefix,
|
||||
codePrefix: p.TextCodePrefix,
|
||||
width: p.TextWidth,
|
||||
}
|
||||
if tp.codePrefix == "" {
|
||||
tp.codePrefix = p.TextPrefix + "\t"
|
||||
}
|
||||
if tp.width == 0 {
|
||||
tp.width = 80 - utf8.RuneCountInString(tp.prefix)
|
||||
@ -35,6 +40,7 @@ func (p *Printer) Text(d *Doc) []byte {
|
||||
var out bytes.Buffer
|
||||
for i, x := range d.Content {
|
||||
if i > 0 && blankBefore(x) {
|
||||
out.WriteString(tp.prefix)
|
||||
writeNL(&out)
|
||||
}
|
||||
tp.block(&out, x)
|
||||
@ -86,6 +92,18 @@ func (p *textPrinter) block(out *bytes.Buffer, x Block) {
|
||||
out.WriteString(p.prefix)
|
||||
out.WriteString("# ")
|
||||
p.text(out, x.Text)
|
||||
|
||||
case *Code:
|
||||
text := x.Text
|
||||
for text != "" {
|
||||
var line string
|
||||
line, text, _ = strings.Cut(text, "\n")
|
||||
if line != "" {
|
||||
out.WriteString(p.codePrefix)
|
||||
out.WriteString(line)
|
||||
}
|
||||
writeNL(out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user