1234567module fmt89import os10import time1112pub const glyph_ok = '✦'13pub const glyph_fail = '✗'1415pub fn colour_enabled() bool {16 if os.getenv('NO_COLOR') != '' || os.getenv('KOH_NO_COLOR') != '' {17 return false18 }19 return os.is_atty(1) != 020}2122fn paint(text string, code string) string {23 if !colour_enabled() {24 return text25 }26 return '\x1b[${code}m${text}\x1b[0m'27}2829pub fn bold(text string) string {30 return paint(text, '1')31}3233pub fn reverse(text string) string {34 return paint(text, '7')35}3637pub fn amber(text string) string {38 return paint(text, '38;5;214')39}4041pub fn red(text string) string {42 return paint(text, '38;5;203')43}4445pub fn green(text string) string {46 return paint(text, '38;5;114')47}4849pub fn dim(text string) string {50 return paint(text, '38;5;245')51}52535455pub fn gold(text string) string {56 return paint(text, '38;5;179')57}5859pub fn muted(text string) string {60 return paint(text, '38;5;241')61}6263pub fn blue(text string) string {64 return paint(text, '38;5;110')65}666768pub fn strip_ansi(text string) string {69 mut out := ''70 mut skipping := false71 for c in text.runes() {72 if c == `\x1b` {73 skipping = true74 continue75 }76 if skipping {77 if (c >= `a` && c <= `z`) || (c >= `A` && c <= `Z`) {78 skipping = false79 }80 continue81 }82 out += c.str()83 }84 return out85}8687pub fn visible_width(text string) int {88 return strip_ansi(text).runes().len89}90919293pub fn fit(text string, width int) string {94 if visible_width(text) <= width {95 return text96 }97 mut out := []rune{}98 mut shown := 099 mut skipping := false100 for c in text.runes() {101 if c == `\x1b` {102 skipping = true103 }104 if skipping {105 out << c106 if (c >= `a` && c <= `z`) || (c >= `A` && c <= `Z`) {107 skipping = false108 }109 continue110 }111 if shown == width {112 break113 }114 out << c115 shown++116 }117 cut := out.string()118 return if cut.contains('\x1b') { cut + '\x1b[0m' } else { cut }119}120121pub fn stamp(unix_seconds i64) string {122 return time.unix(unix_seconds).local().format()123}124125pub fn date_of(unix_seconds i64) string {126 return time.unix(unix_seconds).local().ymmdd()127}128129pub fn hour_of(unix_seconds i64) string {130 return time.unix(unix_seconds).local().hhmm()131}132133pub fn clock_of(unix_seconds i64) string {134 return time.unix(unix_seconds).local().hhmmss()135}136137pub fn human_bytes(bytes i64) string {138 mut value := f64(bytes)139 mut unit := 'B'140 for suffix in ['KiB', 'MiB', 'GiB'] {141 if value < 1024 {142 break143 }144 value /= 1024145 unit = suffix146 }147 if unit == 'B' {148 return '${bytes} B'149 }150 return '${value:.1f} ${unit}'151}152153154pub fn plural(count int, noun string) string {155 if count == 1 {156 return '1 ${noun}'157 }158 return '${count} ${noun}s'159}