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