<commit_before>// Copyright (c) 2016, <NAME> <<EMAIL>>
// See LICENSE for licensing information

package sh

import (
	"bytes"
	"fmt"
	"io"
	"strings"
)

// PrintConfig controls how the printing of an AST node will behave.
type PrintConfig struct {
	Spaces int // 0 (default) for tabs, >0 for number of spaces
}

// Fprint "pretty-prints" the given AST node to the given writer.
func (c PrintConfig) Fprint(w io.Writer, node Node) error {
	p := printer{w: w, c: c}
	switch x := node.(type) {
	case *File:
		p.comments = x.Comments
		p.stmts(x.Stmts)
		p.commentsUpTo(0)
	case *Stmt:
		p.stmt(x)
	default:
		return fmt.Errorf("unsupported root node: %T", node)
	}
	p.newline()
	return p.err
}

// Fprint "pretty-prints" the given AST node to the given writer. It
// calls PrintConfig.Fprint with its default settings.
func Fprint(w io.Writer, node Node) error {
	c := PrintConfig{}
	return c.Fprint(w, node)
}

type printer struct {
	w   io.Writer
	c   PrintConfig
	err error

	wantSpace   bool
	wantSpaces  int
	wantNewline bool

	// curLine is the line that is currently being printed (counted
	// in original lines).
	curLine int
	// lastLevel is the last level of indentation that was used.
	lastLevel int
	// level is the current level of indentation.
	level int
	// levelIncs records which indentation level increments actually
	// took place, to revert them once their section ends.
	levelIncs []bool

	// comments is the list of pending comments to write.
	comments []*Comment

	// pendingHdocs is the list of pending heredocs to write.
	pendingHdocs []*Redirect

	nestedBinary bool
}

const (
	spaces = "                                "
	tabs   = "\t\t\t\t\t\t\t\t"
)

func (p *printer) space() {
	_, p.err = io.WriteString(p.w, " ")
	p.wantSpace = false
}

func (p *printer) spaces(n int) {
	for n > 0 {
		if n < len(spaces) {
			_, p.err = io.WriteString(p.w, spaces[:n])
			break
		}
		_, p.err = io.WriteString(p.w, spaces)
		n -= len(spaces)
	}
	p.wantSpace = false
}

func (p *printer) tabs(n int) {
	for n > 0 {
		if n < len(tabs) {
			_, p.err = io.WriteString(p.w, tabs[:n])
			break
		}
		_, p.err = io.WriteString(p.w, tabs)
		n -= len(tabs)
	}
	p.wantSpace = false
}

func (p *printer) spacesNewl(s string) {
	_, p.err = io.WriteString(p.w, s)
	p.wantSpace = false<commit_msg>print: use bytes for spaces/tabs<commit_after>// Copyright (c) 2016, <NAME> <<EMAIL>>
// See LICENSE for licensing information

package sh

import (
	"bytes"
	"fmt"
	"io"
	"strings"
)

// PrintConfig controls how the printing of an AST node will behave.
type PrintConfig struct {
	Spaces int // 0 (default) for tabs, >0 for number of spaces
}

// Fprint "pretty-prints" the given AST node to the given writer.
func (c PrintConfig) Fprint(w io.Writer, node Node) error {
	p := printer{w: w, c: c}
	switch x := node.(type) {
	case *File:
		p.comments = x.Comments
		p.stmts(x.Stmts)
		p.commentsUpTo(0)
	case *Stmt:
		p.stmt(x)
	default:
		return fmt.Errorf("unsupported root node: %T", node)
	}
	p.newline()
	return p.err
}

// Fprint "pretty-prints" the given AST node to the given writer. It
// calls PrintConfig.Fprint with its default settings.
func Fprint(w io.Writer, node Node) error {
	c := PrintConfig{}
	return c.Fprint(w, node)
}

type printer struct {
	w   io.Writer
	c   PrintConfig
	err error

	wantSpace   bool
	wantSpaces  int
	wantNewline bool

	// curLine is the line that is currently being printed (counted
	// in original lines).
	curLine int
	// lastLevel is the last level of indentation that was used.
	lastLevel int
	// level is the current level of indentation.
	level int
	// levelIncs records which indentation level increments actually
	// took place, to revert them once their section ends.
	levelIncs []bool

	// comments is the list of pending comments to write.
	comments []*Comment

	// pendingHdocs is the list of pending heredocs to write.
	pendingHdocs []*Redirect

	nestedBinary bool
}

var (
	spaces = []byte("                                ")
	tabs   = []byte("\t\t\t\t\t\t\t\t")
)

func (p *printer) space() {
	_, p.err = p.w.Write(spaces[:1])
	p.wantSpace = false
}

func (p *printer) spaces(n int) {
	for n > 0 {
		if n < len(spaces) {
			_, p.err = p.w.Write(spaces[:n])
			break
		}
		_, p.err = p.w.Write(spaces)
		n -= len(spaces)
	}
	p.wantSpace = false
}

func (p *printer) tabs(n int) {
	for n > 0 {
		if n < len(tabs) {
			_, p.err = p.w.Write(tabs[:n])
			break
		}
		_, p.err = p.w.Write(tabs)
		n -= len(tabs)
	}
	p.wantSpace = false
}

func (p *printer) spacesNewl(s string) {
	_, p.err = io.WriteString(p.w, s)
	p.wantSpace = false
{'fraction_non_alphanumeric': 0.12609075043630016, 'fraction_numerical': 0.0041448516579406635, 'mean_word_length': 2.9525862068965516, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '544116', 'n_tokens_mistral': 1764, 'n_tokens_neox': 1660, 'n_words': 550}