blob: d314ac7224b0bb8d68a0bb7662246d06fdb9de8d [file] [log] [blame]
chai2010fb59b332015-04-27 11:32:30 +08001// Copyright 2013 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Brad Fitzpatrickca3319f2013-07-17 17:17:12 +10005// TODO(bradfitz,adg): move to util
6
7package godoc
8
9import "io"
10
11var spaces = []byte(" ") // 32 spaces seems like a good number
12
13const (
14 indenting = iota
15 collecting
16)
17
18// A tconv is an io.Writer filter for converting leading tabs into spaces.
19type tconv struct {
20 output io.Writer
21 state int // indenting or collecting
22 indent int // valid if state == indenting
Brad Fitzpatrick5395cfe2013-07-18 13:14:09 +100023 p *Presentation
Brad Fitzpatrickca3319f2013-07-17 17:17:12 +100024}
25
26func (p *tconv) writeIndent() (err error) {
27 i := p.indent
28 for i >= len(spaces) {
29 i -= len(spaces)
30 if _, err = p.output.Write(spaces); err != nil {
31 return
32 }
33 }
34 // i < len(spaces)
35 if i > 0 {
36 _, err = p.output.Write(spaces[0:i])
37 }
38 return
39}
40
41func (p *tconv) Write(data []byte) (n int, err error) {
42 if len(data) == 0 {
43 return
44 }
45 pos := 0 // valid if p.state == collecting
46 var b byte
47 for n, b = range data {
48 switch p.state {
49 case indenting:
50 switch b {
51 case '\t':
Brad Fitzpatrick5395cfe2013-07-18 13:14:09 +100052 p.indent += p.p.TabWidth
Brad Fitzpatrickca3319f2013-07-17 17:17:12 +100053 case '\n':
54 p.indent = 0
55 if _, err = p.output.Write(data[n : n+1]); err != nil {
56 return
57 }
58 case ' ':
59 p.indent++
60 default:
61 p.state = collecting
62 pos = n
63 if err = p.writeIndent(); err != nil {
64 return
65 }
66 }
67 case collecting:
68 if b == '\n' {
69 p.state = indenting
70 p.indent = 0
71 if _, err = p.output.Write(data[pos : n+1]); err != nil {
72 return
73 }
74 }
75 }
76 }
77 n = len(data)
78 if pos < n && p.state == collecting {
79 _, err = p.output.Write(data[pos:])
80 }
81 return
82}