| Abhay Kumar | a61c522 | 2025-11-10 07:32:50 +0000 | [diff] [blame^] | 1 | package pb |
| 2 | |
| 3 | import ( |
| 4 | "bytes" |
| 5 | "fmt" |
| 6 | "github.com/mattn/go-runewidth" |
| 7 | "math" |
| 8 | "regexp" |
| 9 | //"unicode/utf8" |
| 10 | ) |
| 11 | |
| 12 | const ( |
| 13 | _KiB = 1024 |
| 14 | _MiB = 1048576 |
| 15 | _GiB = 1073741824 |
| 16 | _TiB = 1099511627776 |
| 17 | |
| 18 | _kB = 1e3 |
| 19 | _MB = 1e6 |
| 20 | _GB = 1e9 |
| 21 | _TB = 1e12 |
| 22 | ) |
| 23 | |
| 24 | var ctrlFinder = regexp.MustCompile("\x1b\x5b[0-9;]+\x6d") |
| 25 | |
| 26 | func CellCount(s string) int { |
| 27 | n := runewidth.StringWidth(s) |
| 28 | for _, sm := range ctrlFinder.FindAllString(s, -1) { |
| 29 | n -= runewidth.StringWidth(sm) |
| 30 | } |
| 31 | return n |
| 32 | } |
| 33 | |
| 34 | func StripString(s string, w int) string { |
| 35 | l := CellCount(s) |
| 36 | if l <= w { |
| 37 | return s |
| 38 | } |
| 39 | var buf = bytes.NewBuffer(make([]byte, 0, len(s))) |
| 40 | StripStringToBuffer(s, w, buf) |
| 41 | return buf.String() |
| 42 | } |
| 43 | |
| 44 | func StripStringToBuffer(s string, w int, buf *bytes.Buffer) { |
| 45 | var seqs = ctrlFinder.FindAllStringIndex(s, -1) |
| 46 | var maxWidthReached bool |
| 47 | mainloop: |
| 48 | for i, r := range s { |
| 49 | for _, seq := range seqs { |
| 50 | if i >= seq[0] && i < seq[1] { |
| 51 | buf.WriteRune(r) |
| 52 | continue mainloop |
| 53 | } |
| 54 | } |
| 55 | if rw := CellCount(string(r)); rw <= w && !maxWidthReached { |
| 56 | w -= rw |
| 57 | buf.WriteRune(r) |
| 58 | } else { |
| 59 | maxWidthReached = true |
| 60 | } |
| 61 | } |
| 62 | for w > 0 { |
| 63 | buf.WriteByte(' ') |
| 64 | w-- |
| 65 | } |
| 66 | return |
| 67 | } |
| 68 | |
| 69 | func round(val float64) (newVal float64) { |
| 70 | roundOn := 0.5 |
| 71 | places := 0 |
| 72 | var round float64 |
| 73 | pow := math.Pow(10, float64(places)) |
| 74 | digit := pow * val |
| 75 | _, div := math.Modf(digit) |
| 76 | if div >= roundOn { |
| 77 | round = math.Ceil(digit) |
| 78 | } else { |
| 79 | round = math.Floor(digit) |
| 80 | } |
| 81 | newVal = round / pow |
| 82 | return |
| 83 | } |
| 84 | |
| 85 | // Convert bytes to human readable string. Like a 2 MiB, 64.2 KiB, or 2 MB, 64.2 kB |
| 86 | // if useSIPrefix is set to true |
| 87 | func formatBytes(i int64, useSIPrefix bool) (result string) { |
| 88 | if !useSIPrefix { |
| 89 | switch { |
| 90 | case i >= _TiB: |
| 91 | result = fmt.Sprintf("%.02f TiB", float64(i)/_TiB) |
| 92 | case i >= _GiB: |
| 93 | result = fmt.Sprintf("%.02f GiB", float64(i)/_GiB) |
| 94 | case i >= _MiB: |
| 95 | result = fmt.Sprintf("%.02f MiB", float64(i)/_MiB) |
| 96 | case i >= _KiB: |
| 97 | result = fmt.Sprintf("%.02f KiB", float64(i)/_KiB) |
| 98 | default: |
| 99 | result = fmt.Sprintf("%d B", i) |
| 100 | } |
| 101 | } else { |
| 102 | switch { |
| 103 | case i >= _TB: |
| 104 | result = fmt.Sprintf("%.02f TB", float64(i)/_TB) |
| 105 | case i >= _GB: |
| 106 | result = fmt.Sprintf("%.02f GB", float64(i)/_GB) |
| 107 | case i >= _MB: |
| 108 | result = fmt.Sprintf("%.02f MB", float64(i)/_MB) |
| 109 | case i >= _kB: |
| 110 | result = fmt.Sprintf("%.02f kB", float64(i)/_kB) |
| 111 | default: |
| 112 | result = fmt.Sprintf("%d B", i) |
| 113 | } |
| 114 | } |
| 115 | return |
| 116 | } |