// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package printer

import (
	
	
	
)

func ( *printer) () {
	if len(.goBuild)+len(.plusBuild) == 0 {
		return
	}

	// Find latest possible placement of //go:build and // +build comments.
	// That's just after the last blank line before we find a non-comment.
	// (We'll add another blank line after our comment block.)
	// When we start dropping // +build comments, we can skip over /* */ comments too.
	// Note that we are processing tabwriter input, so every comment
	// begins and ends with a tabwriter.Escape byte.
	// And some newlines have turned into \f bytes.
	 := 0
	for  := 0; ; {
		// Skip leading space at beginning of line.
		 := true
		for  < len(.output) && (.output[] == ' ' || .output[] == '\t') {
			++
		}
		// Skip over // comment if any.
		if +3 < len(.output) && .output[] == tabwriter.Escape && .output[+1] == '/' && .output[+2] == '/' {
			 = false
			for  < len(.output) && !isNL(.output[]) {
				++
			}
		}
		// Skip over \n at end of line.
		if  >= len(.output) || !isNL(.output[]) {
			break
		}
		++

		if  {
			 = 
		}
	}

	// If there is a //go:build comment before the place we identified,
	// use that point instead. (Earlier in the file is always fine.)
	if len(.goBuild) > 0 && .goBuild[0] <  {
		 = .goBuild[0]
	} else if len(.plusBuild) > 0 && .plusBuild[0] <  {
		 = .plusBuild[0]
	}

	var  constraint.Expr
	switch len(.goBuild) {
	case 0:
		// Synthesize //go:build expression from // +build lines.
		for ,  := range .plusBuild {
			,  := constraint.Parse(.commentTextAt())
			if  != nil {
				 = nil
				break
			}
			if  == nil {
				 = 
			} else {
				 = &constraint.AndExpr{X: , Y: }
			}
		}
	case 1:
		// Parse //go:build expression.
		, _ = constraint.Parse(.commentTextAt(.goBuild[0]))
	}

	var  []byte
	if  == nil {
		// Don't have a valid //go:build expression to treat as truth.
		// Bring all the lines together but leave them alone.
		// Note that these are already tabwriter-escaped.
		for ,  := range .goBuild {
			 = append(, .lineAt()...)
		}
		for ,  := range .plusBuild {
			 = append(, .lineAt()...)
		}
	} else {
		 = append(, tabwriter.Escape)
		 = append(, "//go:build "...)
		 = append(, .String()...)
		 = append(, tabwriter.Escape, '\n')
		if len(.plusBuild) > 0 {
			,  := constraint.PlusBuildLines()
			if  != nil {
				 = []string{"// +build error: " + .Error()}
			}
			for ,  := range  {
				 = append(, tabwriter.Escape)
				 = append(, ...)
				 = append(, tabwriter.Escape, '\n')
			}
		}
	}
	 = append(, '\n')

	// Build sorted list of lines to delete from remainder of output.
	 := append(.goBuild, .plusBuild...)
	slices.Sort()

	// Collect output after insertion point, with lines deleted, into after.
	var  []byte
	 := 
	for ,  := range  {
		if  <  {
			continue
		}
		 = appendLines(, .output[:])
		 =  + len(.lineAt())
	}
	 = appendLines(, .output[:])
	if  := len();  >= 2 && isNL([-1]) && isNL([-2]) {
		 = [:-1]
	}

	.output = .output[:]
	.output = append(.output, ...)
	.output = append(.output, ...)
}

// appendLines is like append(x, y...)
// but it avoids creating doubled blank lines,
// which would not be gofmt-standard output.
// It assumes that only whole blocks of lines are being appended,
// not line fragments.
func appendLines(,  []byte) []byte {
	if len() > 0 && isNL([0]) && // y starts in blank line
		(len() == 0 || len() >= 2 && isNL([len()-1]) && isNL([len()-2])) { // x is empty or ends in blank line
		 = [1:] // delete y's leading blank line
	}
	return append(, ...)
}

func ( *printer) ( int) []byte {
	 := 
	for  < len(.output) && !isNL(.output[]) {
		++
	}
	if  < len(.output) {
		++
	}
	return .output[:]
}

func ( *printer) ( int) string {
	if  < len(.output) && .output[] == tabwriter.Escape {
		++
	}
	 := 
	for  < len(.output) && .output[] != tabwriter.Escape && !isNL(.output[]) {
		++
	}
	return string(.output[:])
}

func isNL( byte) bool {
	return  == '\n' ||  == '\f'
}