| // Copyright 2026 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 main |
| |
| import ( |
| "bytes" |
| "fmt" |
| "strings" |
| ) |
| |
| // labelWidth leaves one space after the longest label. Increase this if labels |
| // change and the tables get out of alignment. |
| const labelWidth = 47 |
| |
| // section writes a section heading and the tasks that move the figures in it. |
| // A tag long enough to push the heading past the line budget goes on its own |
| // line rather than trailing off the screen. |
| func section(w *bytes.Buffer, title, tasks string) { |
| head := "## " + title |
| if tag := taskTag(tasks); tag != "" { |
| if len(head)+len(tag)+1 <= 88 { |
| head += " " + tag |
| } else { |
| head += "\n " + strings.TrimSpace(tag) |
| } |
| } |
| fmt.Fprintf(w, "\n\n%s\n\n", head) |
| } |
| |
| // note writes a block of explanatory prose, followed by a blank line. |
| func note(w *bytes.Buffer, text string) { |
| fmt.Fprintf(w, "%s\n\n", text) |
| } |
| |
| // frac writes a figure heading for 100%. |
| func frac(w *bytes.Buffer, label string, r result, tasks string) { |
| pct := " --" |
| if r.d > 0 { |
| pct = fmt.Sprintf("%3.0f%%", 100*float64(r.n)/float64(r.d)) |
| } |
| line(w, fmt.Sprintf("%-*s %5d / %-5d %s%s", labelWidth, label, r.n, r.d, pct, taskTag(tasks))) |
| } |
| |
| // count writes a figure heading for zero. |
| func count(w *bytes.Buffer, label string, n int, tasks string) { |
| line(w, fmt.Sprintf("%-*s %5d %-9s%s", labelWidth, label, n, "-> 0", taskTag(tasks))) |
| } |
| |
| // kv writes a bare number: context rather than a figure with a target. |
| func kv(w *bytes.Buffer, label string, n int) { |
| line(w, fmt.Sprintf("%-*s %5d", labelWidth, label, n)) |
| } |
| |
| // sub writes a bare number indented under the figure it breaks down. |
| func sub(w *bytes.Buffer, label string, n int) { |
| line(w, fmt.Sprintf(" %-*s %5d", labelWidth-4, label, n)) |
| } |
| |
| // countIndented writes a count heading for zero, indented under the figure it |
| // breaks down. Used for per-field and per-file detail rows. |
| func countIndented(w *bytes.Buffer, label string, n int, tasks string) { |
| line(w, fmt.Sprintf(" %-*s %5d %-9s%s", labelWidth-4, label, n, "-> 0", taskTag(tasks))) |
| } |
| |
| // emptyList writes a placeholder when a list has no rows, so that a heading |
| // with nothing under it reads as an empty list rather than a truncated one. |
| func emptyList(w *bytes.Buffer, n int) { |
| if n == 0 { |
| line(w, " (none)") |
| } |
| } |
| |
| const lineWrap = 78 |
| |
| // wrap writes lead followed by a list of words, breaking before the line |
| // wrapping budget and aligning continuations under the first word. The lead |
| // labels the list, so that an inventory nested under a table row says what it |
| // is rather than leaving the reader to infer it from position. |
| func wrap(w *bytes.Buffer, indent, lead string, words []string) { |
| first, rest := indent+lead, indent+strings.Repeat(" ", len(lead)) |
| cur := first |
| for _, s := range words { |
| if len(cur) > len(rest) && len(cur)+1+len(s) > lineWrap { |
| line(w, cur) |
| cur = rest |
| } |
| if len(cur) > len(rest) { |
| cur += " " |
| } |
| cur += s |
| } |
| if len(cur) > len(rest) { |
| line(w, cur) |
| } |
| } |
| |
| func line(w *bytes.Buffer, s string) { |
| fmt.Fprintf(w, "%s\n", strings.TrimRight(s, " ")) |
| } |
| |
| func taskTag(tasks string) string { |
| if tasks == "" || tasks == "-" { |
| return "" |
| } |
| return " [" + tasks + "]" |
| } |