func (p *printer) recordLine(linePtr *int) {
	p.linePtr = linePtr
}
recordLine records the output line number for the next non-whitespace
token in *linePtr. It is used to compute an accurate line number for a
formatted construct, independent of pending (not yet emitted) whitespace
or comments.
package printer
import (
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"
	"text/tabwriter"
	"unicode"
	"github.com/8byt/gox/ast"
	"github.com/8byt/gox/token"
)
const (
	maxNewlines = 2      
	debug       = false  
	infinity    = 1 << 30
)
type whiteSpace byte
const (
	ignore   = whiteSpace(0)
	blank    = whiteSpace(' ')
	vtab     = whiteSpace('\v')
	newline  = whiteSpace('\n')
	formfeed = whiteSpace('\f')
	indent   = whiteSpace('>')
	unindent = whiteSpace('<')
)
type pmode int
const (
	noExtraBlank     pmode = 1 << iota  
	noExtraLinebreak                    
)
type commentInfo struct {
	cindex         int                
	comment        *ast.CommentGroup  
	commentOffset  int                
	commentNewline bool               
}
type printer struct {
	Config
	fset *token.FileSet
	output      []byte        
	indent      int           
	level       int           
	mode        pmode         
	impliedSemi bool          
	lastTok     token.Token   
	prevOpen    token.Token   
	wsbuf       []whiteSpace  
	pos     token.Position  
	out     token.Position  
	last    token.Position  
	linePtr *int            
	comments        []*ast.CommentGroup  
	useNodeComments bool                 
	commentInfo
	nodeSizes map[ast.Node]int
	cachedPos  token.Pos
	cachedLine int  
}
func (p *printer) init(cfg *Config, fset *token.FileSet, nodeSizes map[ast.Node]int) {
	p.Config = *cfg
	p.fset = fset
	p.pos = token.Position{Line: 1, Column: 1}
	p.out = token.Position{Line: 1, Column: 1}
	p.wsbuf = make([]whiteSpace, 0, 16)  
	p.nodeSizes = nodeSizes
	p.cachedPos = -1
}
func (p *printer) internalError(msg ...interface{}) {
	if debug {
		fmt.Print(p.pos.String() + ": ")
		fmt.Println(msg...)
		panic("github.com/8byt/gox/printer")
	}
}
func (p *printer) commentsHaveNewline(list []*ast.Comment) bool {
	line := p.lineFor(list[0].Pos())
	for i, c := range list {
		if i > 0 && p.lineFor(list[i].Pos()) != line {
			return true
		}
		if t := c.Text; len(t) >= 2 && (t[1] == '/' || strings.Contains(t, "\n")) {
			return true
		}
	}
	_ = line
	return false
}
func (p *printer) nextComment() {
	for p.cindex < len(p.comments) {
		c := p.comments[p.cindex]
		p.cindex++
		if list := c.List; len(list) > 0 {
			p.comment = c
			p.commentOffset = p.posFor(list[0].Pos()).Offset
			p.commentNewline = p.commentsHaveNewline(list)
			return
		}
	}
	p.commentOffset = infinity
}
func (p *printer) commentBefore(next token.Position) bool {
	return p.commentOffset < next.Offset && (!p.impliedSemi || !p.commentNewline)
}
func (p *printer) commentSizeBefore(next token.Position) int {
	defer func(info commentInfo) {
		p.commentInfo = info
	}(p.commentInfo)
	size := 0
	for p.commentBefore(next) {
		for _, c := range p.comment.List {
			size += len(c.Text)
		}
		p.nextComment()
	}
	return size
}