1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2024-12-14 11:23:09 +02:00
lazygit/pkg/gui/style/text_style.go

158 lines
3.7 KiB
Go
Raw Normal View History

package style
import (
"github.com/gookit/color"
)
2021-07-31 07:34:45 +02:00
// A TextStyle contains a foreground color, background color, and
// decorations (bold/underline/reverse).
//
2021-08-01 04:54:17 +02:00
// Colors may each be either 16-bit or 24-bit RGB colors. When
2021-07-31 07:34:45 +02:00
// we need to produce a string with a TextStyle, if either foreground or
// background color is RGB, we'll promote the other color component to RGB as well.
// We could simplify this code by forcing everything to be RGB, but we're not
// sure how compatible or efficient that would be with various terminals.
// Lazygit will typically stick to 16-bit colors, but users may configure RGB colors.
//
// TextStyles are value objects, not entities, so for example if you want to
// add the bold decoration to a TextStyle, we'll create a new TextStyle with
// that decoration applied.
//
// Decorations are additive, so when we merge two TextStyles, if either is bold
// then the resulting style will also be bold.
//
// So that we aren't rederiving the underlying style each time we want to print
// a string, we derive it when a new TextStyle is created and store it in the
// `style` field.
2021-07-31 04:54:28 +02:00
type TextStyle struct {
fg *Color
bg *Color
decoration Decoration
2021-07-31 07:34:45 +02:00
2021-11-02 07:39:15 +02:00
// making this public so that we can use a type switch to get to the underlying
// value so we can cache styles. This is very much a hack.
Style Sprinter
}
2021-07-31 04:54:28 +02:00
type Sprinter interface {
Sprint(a ...interface{}) string
Sprintf(format string, a ...interface{}) string
}
2021-07-31 07:34:45 +02:00
func New() TextStyle {
s := TextStyle{}
2021-11-02 07:39:15 +02:00
s.Style = s.deriveStyle()
2021-07-31 07:34:45 +02:00
return s
}
2021-07-31 04:54:28 +02:00
func (b TextStyle) Sprint(a ...interface{}) string {
2021-11-02 07:39:15 +02:00
return b.Style.Sprint(a...)
}
2021-07-31 04:54:28 +02:00
func (b TextStyle) Sprintf(format string, a ...interface{}) string {
2021-11-02 07:39:15 +02:00
return b.Style.Sprintf(format, a...)
2021-07-31 04:54:28 +02:00
}
2021-07-31 09:15:38 +02:00
// note that our receiver here is not a pointer which means we're receiving a
// copy of the original TextStyle. This allows us to mutate and return that
// TextStyle receiver without actually modifying the original.
2021-07-31 04:54:28 +02:00
func (b TextStyle) SetBold() TextStyle {
b.decoration.SetBold()
2021-11-02 07:39:15 +02:00
b.Style = b.deriveStyle()
return b
}
2021-07-31 04:54:28 +02:00
func (b TextStyle) SetUnderline() TextStyle {
b.decoration.SetUnderline()
2021-11-02 07:39:15 +02:00
b.Style = b.deriveStyle()
return b
}
2021-07-31 04:54:28 +02:00
func (b TextStyle) SetReverse() TextStyle {
b.decoration.SetReverse()
2021-11-02 07:39:15 +02:00
b.Style = b.deriveStyle()
2021-07-31 04:54:28 +02:00
return b
}
2023-05-21 02:45:45 +02:00
func (b TextStyle) SetStrikethrough() TextStyle {
b.decoration.SetStrikethrough()
b.Style = b.deriveStyle()
return b
}
2021-07-31 07:34:45 +02:00
func (b TextStyle) SetBg(color Color) TextStyle {
b.bg = &color
2021-11-02 07:39:15 +02:00
b.Style = b.deriveStyle()
2021-07-31 07:34:45 +02:00
return b
}
func (b TextStyle) SetFg(color Color) TextStyle {
b.fg = &color
2021-11-02 07:39:15 +02:00
b.Style = b.deriveStyle()
2021-07-31 07:34:45 +02:00
return b
}
func (b TextStyle) MergeStyle(other TextStyle) TextStyle {
b.decoration = b.decoration.Merge(other.decoration)
if other.fg != nil {
b.fg = other.fg
}
if other.bg != nil {
b.bg = other.bg
}
2021-11-02 07:39:15 +02:00
b.Style = b.deriveStyle()
2021-07-31 07:34:45 +02:00
return b
}
2021-07-31 07:34:45 +02:00
func (b TextStyle) deriveStyle() Sprinter {
if b.fg == nil && b.bg == nil {
return color.Style(b.decoration.ToOpts())
2021-07-31 04:54:28 +02:00
}
2021-07-31 07:34:45 +02:00
isRgb := (b.fg != nil && b.fg.IsRGB()) || (b.bg != nil && b.bg.IsRGB())
2021-07-31 04:54:28 +02:00
if isRgb {
2021-07-31 07:34:45 +02:00
return b.deriveRGBStyle()
2021-07-31 04:54:28 +02:00
}
2021-07-31 07:34:45 +02:00
return b.deriveBasicStyle()
}
func (b TextStyle) deriveBasicStyle() color.Style {
2021-07-31 04:54:28 +02:00
style := make([]color.Color, 0, 5)
2021-07-31 07:34:45 +02:00
if b.fg != nil {
style = append(style, *b.fg.basic)
}
2021-07-31 07:34:45 +02:00
if b.bg != nil {
style = append(style, *b.bg.basic)
}
2021-07-31 07:34:45 +02:00
style = append(style, b.decoration.ToOpts()...)
2021-07-31 04:54:28 +02:00
return color.Style(style)
}
2021-07-31 07:34:45 +02:00
func (b TextStyle) deriveRGBStyle() *color.RGBStyle {
style := &color.RGBStyle{}
2021-07-31 07:34:45 +02:00
if b.fg != nil {
2021-07-31 20:48:40 +02:00
style.SetFg(*b.fg.ToRGB(false).rgb)
2021-07-31 04:54:28 +02:00
}
2021-07-31 07:34:45 +02:00
if b.bg != nil {
2021-07-31 20:48:40 +02:00
// We need to convert the bg firstly to a foreground color,
// For more info see
style.SetBg(*b.bg.ToRGB(true).rgb)
}
2021-07-31 04:54:28 +02:00
2021-07-31 07:34:45 +02:00
style.SetOpts(b.decoration.ToOpts())
return style
}