style.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. package ui
  2. import (
  3. "fmt"
  4. "strings"
  5. )
  6. // Style specifies how something (mostly a string) shall be displayed.
  7. type Style struct {
  8. Foreground Color
  9. Background Color
  10. Bold bool
  11. Dim bool
  12. Italic bool
  13. Underlined bool
  14. Blink bool
  15. Inverse bool
  16. }
  17. // SGRValues returns an array of the individual SGR values for the style.
  18. func (s Style) SGRValues() []string {
  19. var sgr []string
  20. addIf := func(b bool, code string) {
  21. if b {
  22. sgr = append(sgr, code)
  23. }
  24. }
  25. addIf(s.Bold, "1")
  26. addIf(s.Dim, "2")
  27. addIf(s.Italic, "3")
  28. addIf(s.Underlined, "4")
  29. addIf(s.Blink, "5")
  30. addIf(s.Inverse, "7")
  31. if s.Foreground != nil {
  32. sgr = append(sgr, s.Foreground.fgSGR())
  33. }
  34. if s.Background != nil {
  35. sgr = append(sgr, s.Background.bgSGR())
  36. }
  37. return sgr
  38. }
  39. // SGR returns, for the Style, a string that can be included in an ANSI X3.64 SGR sequence.
  40. func (s Style) SGR() string {
  41. return strings.Join(s.SGRValues(), ";")
  42. }
  43. // MergeFromOptions merges all recognized values from a map to the current
  44. // Style.
  45. func (s *Style) MergeFromOptions(options map[string]any) error {
  46. assignColor := func(val any, colorField *Color) string {
  47. if val == "default" {
  48. *colorField = nil
  49. return ""
  50. } else if s, ok := val.(string); ok {
  51. color := parseColor(s)
  52. if color != nil {
  53. *colorField = color
  54. return ""
  55. }
  56. }
  57. return "valid color string"
  58. }
  59. assignBool := func(val any, attrField *bool) string {
  60. if b, ok := val.(bool); ok {
  61. *attrField = b
  62. } else {
  63. return "bool value"
  64. }
  65. return ""
  66. }
  67. for k, v := range options {
  68. var need string
  69. switch k {
  70. case "fg-color":
  71. need = assignColor(v, &s.Foreground)
  72. case "bg-color":
  73. need = assignColor(v, &s.Background)
  74. case "bold":
  75. need = assignBool(v, &s.Bold)
  76. case "dim":
  77. need = assignBool(v, &s.Dim)
  78. case "italic":
  79. need = assignBool(v, &s.Italic)
  80. case "underlined":
  81. need = assignBool(v, &s.Underlined)
  82. case "blink":
  83. need = assignBool(v, &s.Blink)
  84. case "inverse":
  85. need = assignBool(v, &s.Inverse)
  86. default:
  87. return fmt.Errorf("unrecognized option '%s'", k)
  88. }
  89. if need != "" {
  90. return fmt.Errorf("value for option '%s' must be a %s", k, need)
  91. }
  92. }
  93. return nil
  94. }