line.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. package door
  2. import (
  3. "log"
  4. "strings"
  5. "unicode"
  6. )
  7. /*
  8. door.Line - Display a line of text
  9. Example:
  10. var basicLine door.Line = {Text: "Welcome",
  11. DefaultColor: door.Color("BRIGHT YELLOW"),
  12. }
  13. d.Write(basicLine.Output() + door.Reset + door.CRNL)
  14. This outputs Welcome in Bright/Bold Yellow.
  15. Example Render:
  16. var renderAlphaDigit ColorRender = func(text string) string {
  17. var r door.Render{Text: text}
  18. var alpha string = door.ColorText("BOLD YELLOW")
  19. var digit string = door.ColorText("BOLD GREEN")
  20. var other string = door.Reset
  21. for _, letter := range text {
  22. if unicode.IsAlpha(letter) {
  23. r.Append(alpha, 1)
  24. } else {
  25. if unicode.IsDigit(letter) {
  26. r.Append(digit, 1)
  27. } else {
  28. r.Append(other, 1)
  29. }
  30. }
  31. }
  32. return r.Result
  33. }
  34. var renderLine door.Line = {Text: "Render - 12345",
  35. RenderF: renderAlphaDigit,
  36. }
  37. d.Write(renderLine.Output() + door.Reset + door.CRNL)
  38. This outputs "Render" in Yellow, "12345" in Green, and " - " in White.
  39. Example Update:
  40. var updateTime() string {
  41. var now time.Time = time.Now()
  42. var result string = now.Format("3:04:05 PM")
  43. return result
  44. }
  45. var timeLine door.Line = {Text: updateTime(),
  46. UpdateF: updateTime,
  47. }
  48. d.Write(timeLine.Output() + door.CRNL)
  49. time.Sleep(time.Second)
  50. // Check timeLine for update
  51. if timeLine.Update() {
  52. // Yes, there's an update to the time, output it.
  53. d.Write(timeLine.Output() + door.CRNL)
  54. }
  55. if timeLine.Update() {
  56. // This isn't called. There were no changes.
  57. d.Write(timeLine.Output() + door.CRNL)
  58. }
  59. This outputs the Current time in 12 hour format. It pauses for a second,
  60. and outputs the new time.
  61. */
  62. /*
  63. Line of text to display.
  64. */
  65. type Line struct {
  66. Text string // Text to be displayed
  67. DefaultColor string // Default Color to use
  68. RenderF ColorRender // Render function (displays string with colors)
  69. UpdateF Updater // Update function updates the text
  70. Width int // Line length
  71. }
  72. /*
  73. Line Update - This calls the UpdateF if present.
  74. Returns true if the line has been updated, and there's an Update function.
  75. */
  76. func (l *Line) Update() bool {
  77. if l.UpdateF == nil {
  78. return false
  79. }
  80. var NewText string = l.UpdateF()
  81. l.LineLength(&NewText)
  82. if NewText != l.Text {
  83. l.Text = NewText
  84. return true
  85. }
  86. return false
  87. }
  88. // If a line Width has been set, make sure we match it.
  89. func (l *Line) LineLength(text *string) {
  90. if l.Width == 0 {
  91. return
  92. }
  93. var length int = StringLen(*text)
  94. /*
  95. if Unicode {
  96. length = len([]rune(*text))
  97. } else {
  98. length = len([]byte(*text))
  99. }
  100. */
  101. if length > l.Width {
  102. log.Printf("ERROR: Line Width %d: Have %d\n", l.Width, length)
  103. } else {
  104. *text += strings.Repeat(" ", l.Width-length)
  105. }
  106. }
  107. /*
  108. Line Output - returns a string with ANSI Color codes.
  109. If there is no RenderF, we use the DefaultColor. Otherwise we pass the text
  110. to RenderF and return what it returns.
  111. */
  112. func (l *Line) Output() string {
  113. if l.UpdateF == nil {
  114. l.LineLength(&l.Text)
  115. }
  116. if l.RenderF == nil {
  117. return l.DefaultColor + l.Text
  118. } else {
  119. return l.RenderF(l.Text)
  120. }
  121. }
  122. /*
  123. door.Render - Helper for Line RenderF (Render Function)
  124. Example:
  125. // RenderStatus - KEY_COLOR[key] COLON_COLOR[:] VALUE_COLOR[value]
  126. func RenderStatus(text string) string {
  127. var r door.Render = Render{Line: text}
  128. var bool inValue = false
  129. var key string = door.ColorText("BLUE")
  130. var colon string = door.ColorText("BRIGHT WHITE")
  131. var value string = door.ColorText("MAGENTA")
  132. for _, letter := range text {
  133. if letter == ':' {
  134. r.Append(colon, 1)
  135. inValue = true
  136. } else {
  137. if inValue {
  138. r.Append(value, 1)
  139. } else {
  140. r.Append(key, 1)
  141. }
  142. }
  143. }
  144. return r.Result
  145. }
  146. */
  147. type Render struct {
  148. Line string // Original Text
  149. Result string // Output Result
  150. Pos int // Current Position
  151. LastColor string // LastColor code sent
  152. }
  153. /*
  154. Render.Append - Output len number of characters in the color.
  155. This uses Render.LastColor to tell if we've already sent that color before.
  156. */
  157. func (r *Render) Append(color string, len int) {
  158. if color != r.LastColor {
  159. r.LastColor = color
  160. r.Result += color
  161. }
  162. if Unicode {
  163. // Treat unicode as []rune.
  164. r.Result += string([]rune(r.Line)[r.Pos : r.Pos+len])
  165. } else {
  166. r.Result += r.Line[r.Pos : r.Pos+len]
  167. }
  168. r.Pos += len
  169. }
  170. // RenderBlueYellow - Uppercase is Bold Blue, everything else is Yellow.
  171. // This is an example of using the door.Render routines.
  172. func RenderBlueYellowOld(text string) string {
  173. var r Render = Render{Line: text}
  174. var blue string = ColorText("BOLD BLUE")
  175. var yellow string = ColorText("BOLD YELLOW")
  176. for _, letter := range text {
  177. if unicode.IsUpper(letter) {
  178. r.Append(blue, 1)
  179. } else {
  180. r.Append(yellow, 1)
  181. }
  182. }
  183. return r.Result
  184. }
  185. /*
  186. var RenderPool = sync.Pool{
  187. New: func() any {
  188. return new(strings.Builder)
  189. },
  190. }
  191. */
  192. // Render is the old way of doing things...
  193. // Using strings.Builder ...
  194. func RenderBlueYellow(text string) string {
  195. var output strings.Builder
  196. // var output = RenderPool.Get().(*strings.Builder)
  197. // output.Reset()
  198. var blue string = ColorText("BOLD BLUE")
  199. var yellow string = ColorText("BOLD YELLOW")
  200. var last *string
  201. for _, letter := range text {
  202. if unicode.IsUpper(letter) {
  203. if last != &blue {
  204. output.WriteString(blue)
  205. last = &blue
  206. }
  207. } else {
  208. if last != &yellow {
  209. output.WriteString(yellow)
  210. last = &yellow
  211. }
  212. }
  213. output.WriteRune(letter)
  214. }
  215. // var result = output.String()
  216. // RenderPool.Put(output)
  217. // return result
  218. return output.String()
  219. }