internal/godoc: introduce TabSpacer
Mainly just isolate it from Presentation, but give it a nice API too. Change-Id: I9650bf650a15bfd814fe4da58de6fa133a858d90 Reviewed-on: https://go-review.googlesource.com/c/website/+/296374 Trust: Russ Cox <rsc@golang.org> Run-TryBot: Russ Cox <rsc@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
This commit is contained in:
Родитель
d72b0a78e3
Коммит
28d7606f40
|
@ -605,7 +605,7 @@ func (p *Presentation) writeNode(w io.Writer, pageInfo *PageInfo, fset *token.Fi
|
|||
}
|
||||
|
||||
mode := printer.TabIndent | printer.UseSpaces
|
||||
err := (&printer.Config{Mode: mode, Tabwidth: p.TabWidth}).Fprint(&tconv{p: p, output: out}, fset, x)
|
||||
err := (&printer.Config{Mode: mode, Tabwidth: p.TabWidth}).Fprint(TabSpacer(out, p.TabWidth), fset, x)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
//go:build go1.16
|
||||
// +build go1.16
|
||||
|
||||
// TODO(bradfitz,adg): move to util
|
||||
|
||||
package godoc
|
||||
|
||||
import "io"
|
||||
|
@ -18,68 +16,74 @@ const (
|
|||
collecting
|
||||
)
|
||||
|
||||
// TabSpacer returns a writer that passes writes through to w,
|
||||
// expanding tabs to one or more spaces ending at a width-spaces-aligned boundary.
|
||||
func TabSpacer(w io.Writer, width int) io.Writer {
|
||||
return &tconv{output: w, tabWidth: width}
|
||||
}
|
||||
|
||||
// A tconv is an io.Writer filter for converting leading tabs into spaces.
|
||||
type tconv struct {
|
||||
output io.Writer
|
||||
state int // indenting or collecting
|
||||
indent int // valid if state == indenting
|
||||
p *Presentation
|
||||
tabWidth int
|
||||
}
|
||||
|
||||
func (p *tconv) writeIndent() (err error) {
|
||||
i := p.indent
|
||||
func (t *tconv) writeIndent() (err error) {
|
||||
i := t.indent
|
||||
for i >= len(spaces) {
|
||||
i -= len(spaces)
|
||||
if _, err = p.output.Write(spaces); err != nil {
|
||||
if _, err = t.output.Write(spaces); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
// i < len(spaces)
|
||||
if i > 0 {
|
||||
_, err = p.output.Write(spaces[0:i])
|
||||
_, err = t.output.Write(spaces[0:i])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (p *tconv) Write(data []byte) (n int, err error) {
|
||||
func (t *tconv) Write(data []byte) (n int, err error) {
|
||||
if len(data) == 0 {
|
||||
return
|
||||
}
|
||||
pos := 0 // valid if p.state == collecting
|
||||
var b byte
|
||||
for n, b = range data {
|
||||
switch p.state {
|
||||
switch t.state {
|
||||
case indenting:
|
||||
switch b {
|
||||
case '\t':
|
||||
p.indent += p.p.TabWidth
|
||||
t.indent += t.tabWidth
|
||||
case '\n':
|
||||
p.indent = 0
|
||||
if _, err = p.output.Write(data[n : n+1]); err != nil {
|
||||
t.indent = 0
|
||||
if _, err = t.output.Write(data[n : n+1]); err != nil {
|
||||
return
|
||||
}
|
||||
case ' ':
|
||||
p.indent++
|
||||
t.indent++
|
||||
default:
|
||||
p.state = collecting
|
||||
t.state = collecting
|
||||
pos = n
|
||||
if err = p.writeIndent(); err != nil {
|
||||
if err = t.writeIndent(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
case collecting:
|
||||
if b == '\n' {
|
||||
p.state = indenting
|
||||
p.indent = 0
|
||||
if _, err = p.output.Write(data[pos : n+1]); err != nil {
|
||||
t.state = indenting
|
||||
t.indent = 0
|
||||
if _, err = t.output.Write(data[pos : n+1]); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
n = len(data)
|
||||
if pos < n && p.state == collecting {
|
||||
_, err = p.output.Write(data[pos:])
|
||||
if pos < n && t.state == collecting {
|
||||
_, err = t.output.Write(data[pos:])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче