]> Cypherpunks repositories - gostls13.git/commitdiff
use new tab indentation format in godoc, but convert
authorRobert Griesemer <gri@golang.org>
Thu, 17 Dec 2009 22:10:49 +0000 (14:10 -0800)
committerRobert Griesemer <gri@golang.org>
Thu, 17 Dec 2009 22:10:49 +0000 (14:10 -0800)
leading tabs into spaces to ensure a good outcome in
most browsers

R=rsc
https://golang.org/cl/165051

src/cmd/godoc/godoc.go

index 1e4eb1625b8fb25fdd3960a2e008248510eeb0a0..a381c3a5863280a14ec47adc5905c9e6df11c16a 100644 (file)
@@ -453,16 +453,84 @@ func (s *Styler) Token(tok token.Token) (text []byte, tag printer.HTMLTag) {
 }
 
 
+// ----------------------------------------------------------------------------
+// Tab conversion
+
+var spaces = strings.Bytes("                ") // 16 spaces seems like a good number
+
+const (
+       indenting = iota
+       collecting
+)
+
+// 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
+}
+
+
+func (p *tconv) writeIndent(n int) (err os.Error) {
+       i := n * *tabwidth
+       for i > len(spaces) {
+               i -= len(spaces)
+               if _, err = p.output.Write(spaces); err != nil {
+                       return
+               }
+       }
+       _, err = p.output.Write(spaces[0:i])
+       return
+}
+
+
+func (p *tconv) Write(data []byte) (n int, err os.Error) {
+       pos := 0 // valid if p.state == collecting
+       var b byte
+       for n, b = range data {
+               switch p.state {
+               case indenting:
+                       if b == '\t' {
+                               p.indent++
+                       } else {
+                               p.state = collecting
+                               pos = n
+                               if err = p.writeIndent(p.indent); 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 {
+                                       return
+                               }
+                       }
+               }
+       }
+       n = len(data)
+       if p.state == collecting {
+               _, err = p.output.Write(data[pos:])
+       }
+       return
+}
+
+
 // ----------------------------------------------------------------------------
 // Templates
 
 // Write an AST-node to w; optionally html-escaped.
 func writeNode(w io.Writer, node interface{}, html bool, styler printer.Styler) {
-       mode := printer.UseSpaces | printer.NoSemis
+       mode := printer.TabIndent | printer.UseSpaces | printer.NoSemis
        if html {
                mode |= printer.GenHTML
        }
-       (&printer.Config{mode, *tabwidth, styler}).Fprint(w, node)
+       // convert trailing tabs into spaces using a tconv filter
+       // to ensure a good outcome in most browsers (there may still
+       // be tabs in comments and strings, but converting those into
+       // the right number of spaces is much harder)
+       (&printer.Config{mode, *tabwidth, styler}).Fprint(&tconv{output: w}, node)
 }