chai2010 | fb59b33 | 2015-04-27 11:32:30 +0800 | [diff] [blame] | 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 | |
Brad Fitzpatrick | ca3319f | 2013-07-17 17:17:12 +1000 | [diff] [blame] | 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 |
Brad Fitzpatrick | 5395cfe | 2013-07-18 13:14:09 +1000 | [diff] [blame] | 23 | p *Presentation |
Brad Fitzpatrick | ca3319f | 2013-07-17 17:17:12 +1000 | [diff] [blame] | 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': |
Brad Fitzpatrick | 5395cfe | 2013-07-18 13:14:09 +1000 | [diff] [blame] | 52 | p.indent += p.p.TabWidth |
Brad Fitzpatrick | ca3319f | 2013-07-17 17:17:12 +1000 | [diff] [blame] | 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 | } |