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:
Russ Cox 2021-02-23 16:50:24 -05:00
Родитель d72b0a78e3
Коммит 28d7606f40
2 изменённых файлов: 30 добавлений и 26 удалений

Просмотреть файл

@ -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
}