util.go 2.3 KB

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