github.com/v2fly/tools@v0.100.0/godoc/tab.go (about)

     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  }