src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

format.go (4137B)


      1 package entry
      2 
      3 import (
      4 	"fmt"
      5 
      6 	"sort"
      7 	"strconv"
      8 	"strings"
      9 
     10 	"code.dwrz.net/src/pkg/color"
     11 	"code.dwrz.net/src/pkg/dqs/category"
     12 	"code.dwrz.net/src/pkg/dqs/stats"
     13 	"code.dwrz.net/src/pkg/dqs/user"
     14 )
     15 
     16 const (
     17 	width  = 44
     18 	top    = "┌────────────────────────────────────────────┐\n"
     19 	hr     = "├────────────────────────────────────────────┤\n"
     20 	bottom = "└────────────────────────────────────────────┘\n"
     21 )
     22 
     23 func centerPad(s string, width int) string {
     24 	return fmt.Sprintf(
     25 		"%[1]*s", -width, fmt.Sprintf("%[1]*s", (width+len(s))/2, s),
     26 	)
     27 }
     28 
     29 // FormatPrint formats an entry for display to the user.
     30 func (e *Entry) FormatPrint(u *user.User) string {
     31 	// Assemble the data for display.
     32 	var (
     33 		highQuality []category.Category
     34 		lowQuality  []category.Category
     35 	)
     36 
     37 	// Separate high quality and low quality categories.
     38 	for _, c := range e.Categories {
     39 		if c.HighQuality {
     40 			highQuality = append(highQuality, c)
     41 			continue
     42 		}
     43 		lowQuality = append(lowQuality, c)
     44 	}
     45 
     46 	// Sort alphabetically for consistent appearance.
     47 	sort.Slice(highQuality, func(i, j int) bool {
     48 		return highQuality[i].Name < highQuality[j].Name
     49 	})
     50 	sort.Slice(lowQuality, func(i, j int) bool {
     51 		return lowQuality[i].Name < lowQuality[j].Name
     52 	})
     53 
     54 	// Prepare a string for display to the user.
     55 	var str strings.Builder
     56 
     57 	// Format the date.
     58 	str.WriteString(top)
     59 	str.WriteString(fmt.Sprintf(
     60 		"│%s%s%s│\n",
     61 		color.BrightBlack,
     62 		centerPad(e.Date.Format(dateDisplayFormat), width),
     63 		color.Reset,
     64 	))
     65 	str.WriteString(hr)
     66 
     67 	// Format high-quality categories.
     68 	str.WriteString(fmt.Sprintf("│%-44s│\n", "High Quality"))
     69 	str.WriteString(hr)
     70 	for _, c := range highQuality {
     71 		str.WriteString(c.FormatPrint())
     72 		str.WriteString("\n")
     73 	}
     74 
     75 	// Format low-quality categories.
     76 	str.WriteString(hr)
     77 	str.WriteString(fmt.Sprintf("│%-44s│\n", "Low Quality"))
     78 	str.WriteString(hr)
     79 	for _, c := range lowQuality {
     80 		str.WriteString(c.FormatPrint())
     81 		str.WriteString("\n")
     82 	}
     83 	str.WriteString(hr)
     84 
     85 	// Format the total.
     86 	var totalColor color.Color
     87 	total := e.Score()
     88 	switch {
     89 	case total >= 15:
     90 		totalColor = color.BrightGreen
     91 	case total >= 0:
     92 		totalColor = color.BrightYellow
     93 	default:
     94 		totalColor = color.BrightRed
     95 
     96 	}
     97 
     98 	max := e.Diet.MaxScore()
     99 	formattedTotal := strconv.FormatFloat(total, 'f', -1, 64)
    100 	digits := len(fmt.Sprintf("%s / %d", formattedTotal, max))
    101 	space := width - digits
    102 	format := fmt.Sprintf("%%-%ds%%s%%s%%s / %%d │\n", space)
    103 	str.WriteString(fmt.Sprintf(
    104 		format,
    105 		"│Total / Max: ", totalColor, formattedTotal, color.Reset, max,
    106 	))
    107 	str.WriteString(hr)
    108 
    109 	// Format the weight, delta, and body fat.
    110 	digits = len(fmt.Sprintf(
    111 		"%.2f / %.2f", e.UnitWeight(u.Units), u.UnitTargetWeight(),
    112 	))
    113 	space = width - digits
    114 	format = fmt.Sprintf("%%-%ds%%.2f / %%.2f │\n", space)
    115 	str.WriteString(fmt.Sprintf(
    116 		format,
    117 		"│Weight / Target:",
    118 		e.UnitWeight(u.Units),
    119 		u.UnitTargetWeight(),
    120 	))
    121 
    122 	diff := e.UnitWeight(u.Units) - u.UnitTargetWeight()
    123 	digits = len(fmt.Sprintf("%+.2f", diff))
    124 	space = width - digits
    125 	format = fmt.Sprintf("%%-%ds%%+.2f │\n", space)
    126 	str.WriteString(fmt.Sprintf(format, "│Weight Δ:", diff))
    127 
    128 	bfw := e.UnitBodyFatWeight(u.Units)
    129 	digits = len(fmt.Sprintf(
    130 		"%.2f%% (%.2f %s)",
    131 		e.BodyFat, bfw, u.Units.Weight(),
    132 	))
    133 	space = width - digits
    134 	format = fmt.Sprintf("%%-%ds%%.2f%%%% (%%.2f %%s) │\n", space)
    135 	str.WriteString(fmt.Sprintf(
    136 		format,
    137 		"│Body Fat:",
    138 		e.BodyFat, bfw, u.Units.Weight(),
    139 	))
    140 
    141 	bmi := stats.BMI(u.Height, e.Weight)
    142 	digits = len(fmt.Sprintf("%.2f", bmi))
    143 	space = width - digits
    144 	format = fmt.Sprintf("%%-%ds%%.2f │\n", space)
    145 	str.WriteString(fmt.Sprintf(format, "│BMI:", bmi))
    146 
    147 	str.WriteString(bottom)
    148 
    149 	// If a note is set, format it.
    150 	if e.Note != "" {
    151 		str.WriteString(fmt.Sprintf(
    152 			"\n%s%s%s\n", color.Italic, e.Note, color.Reset,
    153 		))
    154 	}
    155 
    156 	return str.String()
    157 }