// setWindowTitle sets the title of the current shell window based on the current build state.
func setWindowTitle(state *core.BuildState) {
	if state == nil {
		SetWindowTitle("plz: finishing up")
	} else {
		SetWindowTitle(fmt.Sprintf("plz: %d / %d tasks, %3.1fs", state.NumDone(), state.NumActive(), time.Since(startTime).Seconds()))
	}
}
func printLines(state *core.BuildState, buildingTargets []buildingTarget, maxLines, cols int) {
	now := time.Now()
	printf("Building [%d/%d, %3.1fs]:\n", state.NumDone(), state.NumActive(), time.Since(startTime).Seconds())
	for i := 0; i < len(buildingTargets) && i < maxLines; i++ {
		buildingTargets[i].Lock()
		// Take a local copy of the structure, which isn't *that* big, so we don't need to retain the lock
		// while we do potentially blocking things like printing.
		target := buildingTargets[i].buildingTargetData
		buildingTargets[i].Unlock()
		label := target.Label.Parent()
		if target.Active {
			lprintf(cols, "${BOLD_WHITE}=> [%4.1fs] ${RESET}%s%s ${BOLD_WHITE}%s${ERASE_AFTER}\n",
				now.Sub(target.Started).Seconds(), target.Colour, label, target.Description)
		} else if time.Since(target.Finished).Seconds() < 0.5 {
			// Only display finished targets for half a second after they're done.
			duration := target.Finished.Sub(target.Started).Seconds()
			if target.Failed {
				lprintf(cols, "${BOLD_RED}=> [%4.1fs] ${RESET}%s%s ${BOLD_RED}Failed${ERASE_AFTER}\n",
					duration, target.Colour, label)
			} else if target.Cached {
				lprintf(cols, "${BOLD_WHITE}=> [%4.1fs] ${RESET}%s%s ${BOLD_GREY}%s${ERASE_AFTER}\n",
					duration, target.Colour, label, target.Description)
			} else {
				lprintf(cols, "${BOLD_WHITE}=> [%4.1fs] ${RESET}%s%s ${WHITE}%s${ERASE_AFTER}\n",
					duration, target.Colour, label, target.Description)
			}
		} else {
			printf("${BOLD_GREY}=|${ERASE_AFTER}\n")
		}
	}
	printf("${RESET}")
}
func updateTarget(state *core.BuildState, plainOutput bool, buildingTarget *buildingTarget, label core.BuildLabel,
	active bool, failed bool, cached bool, description string, err error, colour string) {
	updateTarget2(buildingTarget, label, active, failed, cached, description, err, colour)
	if plainOutput {
		if failed {
			log.Errorf("%s: %s", label.String(), description)
		} else {
			if !active {
				active := pluralise(state.NumActive(), "task", "tasks")
				log.Notice("[%d/%s] %s: %s [%3.1fs]", state.NumDone(), active, label.String(), description, time.Now().Sub(buildingTarget.Started).Seconds())
			} else {
				log.Info("%s: %s", label.String(), description)
			}
		}
	}
}