1 | // 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 | |
5 | // TODO(bradfitz,adg): move to util |
6 | |
7 | package godoc |
8 | |
9 | import "io" |
10 | |
11 | var spaces = []byte(" ") // 32 spaces seems like a good number |
12 | |
13 | const ( |
14 | indenting = iota |
15 | collecting |
16 | ) |
17 | |
18 | // A tconv is an io.Writer filter for converting leading tabs into spaces. |
19 | type tconv struct { |
20 | output io.Writer |
21 | state int // indenting or collecting |
22 | indent int // valid if state == indenting |
23 | p *Presentation |
24 | } |
25 | |
26 | func (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 | |
41 | func (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': |
52 | p.indent += p.p.TabWidth |
53 | 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 | } |
83 |
Members