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 }