github.com/markusbkk/elvish@v0.0.0-20231204143114-91dc52438621/pkg/ui/style.go (about)

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