console.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. package console
  2. import (
  3. "bytes"
  4. "fmt"
  5. "strings"
  6. "time"
  7. "unicode/utf8"
  8. )
  9. type Table struct {
  10. Bordered bool
  11. Values [][]interface{}
  12. }
  13. func (table *Table) AddRow(vs ...interface{}) {
  14. table.Values = append(table.Values, vs)
  15. }
  16. func (table *Table) WithBordered() *Table {
  17. table.Bordered = true
  18. return table
  19. }
  20. func printBorder(w *bytes.Buffer, ws []int) {
  21. for _, l := range ws {
  22. w.WriteString("+")
  23. w.WriteString(strings.Repeat("-", l+2))
  24. }
  25. w.WriteString("+\n")
  26. }
  27. func calcCharsetWidth(s string) int {
  28. bl := len(s)
  29. ul := utf8.RuneCountInString(s)
  30. if bl == ul {
  31. return bl
  32. } else {
  33. var wc int
  34. //计算中文词语数量,并且替换为2个长度显示
  35. for wc = ((bl - ul) / 3); wc < ul; wc++ {
  36. if wc*3-wc == bl-ul {
  37. break
  38. }
  39. }
  40. wv := wc*2 + (ul - wc)
  41. return wv
  42. }
  43. }
  44. func (table *Table) toString(v interface{}) string {
  45. switch t := v.(type) {
  46. case float32, float64:
  47. return fmt.Sprintf("%.2f", t)
  48. case time.Time:
  49. return t.Format("2006-01-02 15:04:05")
  50. default:
  51. return fmt.Sprint(v)
  52. }
  53. }
  54. func (table *Table) Marshal() ([]byte, error) {
  55. columns := make([][]string, 0)
  56. var widths []int
  57. var width int
  58. var maxLength int
  59. calcWidth := calcCharsetWidth
  60. for _, value := range table.Values {
  61. if len(value) > maxLength {
  62. maxLength = len(value)
  63. }
  64. }
  65. widths = make([]int, maxLength)
  66. for _, vs := range table.Values {
  67. vl := len(vs)
  68. column := make([]string, vl)
  69. for i, val := range vs {
  70. str := table.toString(val)
  71. if vl > 1 {
  72. width = calcWidth(str)
  73. if width > widths[i] {
  74. widths[i] = width
  75. }
  76. }
  77. column[i] = str
  78. }
  79. columns = append(columns, column)
  80. }
  81. buffer := &bytes.Buffer{}
  82. if table.Bordered {
  83. printBorder(buffer, widths)
  84. }
  85. for index, column := range columns {
  86. cl := len(column)
  87. for i, w := range widths {
  88. if table.Bordered {
  89. buffer.WriteString("|")
  90. }
  91. var str string
  92. if cl > i {
  93. str = column[i]
  94. }
  95. if table.Bordered {
  96. buffer.WriteString(" ")
  97. }
  98. buffer.WriteString(str)
  99. cl := calcWidth(str)
  100. if widths[i] >= cl {
  101. buffer.WriteString(strings.Repeat(" ", w-cl))
  102. }
  103. buffer.WriteString(" ")
  104. //key value options
  105. if len(widths) == 2 && i == 0 && len(column) == 2 && !table.Bordered {
  106. buffer.WriteString("\t")
  107. }
  108. }
  109. if table.Bordered {
  110. buffer.WriteString("|\n")
  111. } else {
  112. buffer.WriteString("\n")
  113. }
  114. if table.Bordered && index == 0 {
  115. printBorder(buffer, widths)
  116. }
  117. }
  118. if table.Bordered {
  119. printBorder(buffer, widths)
  120. }
  121. return buffer.Bytes(), nil
  122. }
  123. func NewTable() *Table {
  124. return &Table{
  125. Bordered: false,
  126. Values: make([][]interface{}, 0),
  127. }
  128. }