helper.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. // Copyright 2017 Zack Guo <zack.y.guo@gmail.com>. All rights reserved.
  2. // Use of this source code is governed by a MIT license that can
  3. // be found in the LICENSE file.
  4. package termui
  5. import (
  6. "regexp"
  7. "strings"
  8. tm "github.com/nsf/termbox-go"
  9. )
  10. import rw "github.com/mattn/go-runewidth"
  11. /* ---------------Port from termbox-go --------------------- */
  12. // Attribute is printable cell's color and style.
  13. type Attribute uint16
  14. // 8 basic clolrs
  15. const (
  16. ColorDefault Attribute = iota
  17. ColorBlack
  18. ColorRed
  19. ColorGreen
  20. ColorYellow
  21. ColorBlue
  22. ColorMagenta
  23. ColorCyan
  24. ColorWhite
  25. )
  26. //Have a constant that defines number of colors
  27. const NumberofColors = 8
  28. // Text style
  29. const (
  30. AttrBold Attribute = 1 << (iota + 9)
  31. AttrUnderline
  32. AttrReverse
  33. )
  34. var (
  35. dot = "…"
  36. dotw = rw.StringWidth(dot)
  37. )
  38. /* ----------------------- End ----------------------------- */
  39. func toTmAttr(x Attribute) tm.Attribute {
  40. return tm.Attribute(x)
  41. }
  42. func str2runes(s string) []rune {
  43. return []rune(s)
  44. }
  45. // Here for backwards-compatibility.
  46. func trimStr2Runes(s string, w int) []rune {
  47. return TrimStr2Runes(s, w)
  48. }
  49. // TrimStr2Runes trims string to w[-1 rune], appends …, and returns the runes
  50. // of that string if string is grather then n. If string is small then w,
  51. // return the runes.
  52. func TrimStr2Runes(s string, w int) []rune {
  53. if w <= 0 {
  54. return []rune{}
  55. }
  56. sw := rw.StringWidth(s)
  57. if sw > w {
  58. return []rune(rw.Truncate(s, w, dot))
  59. }
  60. return str2runes(s)
  61. }
  62. // TrimStrIfAppropriate trim string to "s[:-1] + …"
  63. // if string > width otherwise return string
  64. func TrimStrIfAppropriate(s string, w int) string {
  65. if w <= 0 {
  66. return ""
  67. }
  68. sw := rw.StringWidth(s)
  69. if sw > w {
  70. return rw.Truncate(s, w, dot)
  71. }
  72. return s
  73. }
  74. func strWidth(s string) int {
  75. return rw.StringWidth(s)
  76. }
  77. func charWidth(ch rune) int {
  78. return rw.RuneWidth(ch)
  79. }
  80. var whiteSpaceRegex = regexp.MustCompile(`\s`)
  81. // StringToAttribute converts text to a termui attribute. You may specify more
  82. // then one attribute like that: "BLACK, BOLD, ...". All whitespaces
  83. // are ignored.
  84. func StringToAttribute(text string) Attribute {
  85. text = whiteSpaceRegex.ReplaceAllString(strings.ToLower(text), "")
  86. attributes := strings.Split(text, ",")
  87. result := Attribute(0)
  88. for _, theAttribute := range attributes {
  89. var match Attribute
  90. switch theAttribute {
  91. case "reset", "default":
  92. match = ColorDefault
  93. case "black":
  94. match = ColorBlack
  95. case "red":
  96. match = ColorRed
  97. case "green":
  98. match = ColorGreen
  99. case "yellow":
  100. match = ColorYellow
  101. case "blue":
  102. match = ColorBlue
  103. case "magenta":
  104. match = ColorMagenta
  105. case "cyan":
  106. match = ColorCyan
  107. case "white":
  108. match = ColorWhite
  109. case "bold":
  110. match = AttrBold
  111. case "underline":
  112. match = AttrUnderline
  113. case "reverse":
  114. match = AttrReverse
  115. }
  116. result |= match
  117. }
  118. return result
  119. }
  120. // TextCells returns a coloured text cells []Cell
  121. func TextCells(s string, fg, bg Attribute) []Cell {
  122. cs := make([]Cell, 0, len(s))
  123. // sequence := MarkdownTextRendererFactory{}.TextRenderer(s).Render(fg, bg)
  124. // runes := []rune(sequence.NormalizedText)
  125. runes := str2runes(s)
  126. for n := range runes {
  127. // point, _ := sequence.PointAt(n, 0, 0)
  128. // cs = append(cs, Cell{point.Ch, point.Fg, point.Bg})
  129. cs = append(cs, Cell{runes[n], fg, bg})
  130. }
  131. return cs
  132. }
  133. // Width returns the actual screen space the cell takes (usually 1 or 2).
  134. func (c Cell) Width() int {
  135. return charWidth(c.Ch)
  136. }
  137. // Copy return a copy of c
  138. func (c Cell) Copy() Cell {
  139. return c
  140. }
  141. // TrimTxCells trims the overflowed text cells sequence.
  142. func TrimTxCells(cs []Cell, w int) []Cell {
  143. if len(cs) <= w {
  144. return cs
  145. }
  146. return cs[:w]
  147. }
  148. // DTrimTxCls trims the overflowed text cells sequence and append dots at the end.
  149. func DTrimTxCls(cs []Cell, w int) []Cell {
  150. l := len(cs)
  151. if l <= 0 {
  152. return []Cell{}
  153. }
  154. rt := make([]Cell, 0, w)
  155. csw := 0
  156. for i := 0; i < l && csw <= w; i++ {
  157. c := cs[i]
  158. cw := c.Width()
  159. if cw+csw < w {
  160. rt = append(rt, c)
  161. csw += cw
  162. } else {
  163. rt = append(rt, Cell{'…', c.Fg, c.Bg})
  164. break
  165. }
  166. }
  167. return rt
  168. }
  169. func CellsToStr(cs []Cell) string {
  170. str := ""
  171. for _, c := range cs {
  172. str += string(c.Ch)
  173. }
  174. return str
  175. }