1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-02-13 13:59:06 +02:00

simplify code a bit

This commit is contained in:
Jesse Duffield 2021-07-31 12:54:28 +10:00
parent 79848087bc
commit 117c0bd4f7
15 changed files with 301 additions and 372 deletions

View File

@ -98,35 +98,35 @@ func (l *PatchLine) render(selected bool, included bool) string {
return coloredString(style.FgCyan, match[1], selected, included) + coloredString(theme.DefaultTextColor, match[2], selected, false) return coloredString(style.FgCyan, match[1], selected, included) + coloredString(theme.DefaultTextColor, match[2], selected, false)
} }
colorAttr := theme.DefaultTextColor textStyle := theme.DefaultTextColor
switch l.Kind { switch l.Kind {
case PATCH_HEADER: case PATCH_HEADER:
colorAttr = colorAttr.SetBold(true) textStyle = textStyle.SetBold()
case ADDITION: case ADDITION:
colorAttr = colorAttr.SetColor(style.FgGreen) textStyle = style.FgGreen
case DELETION: case DELETION:
colorAttr = colorAttr.SetColor(style.FgRed) textStyle = style.FgRed
case COMMIT_SHA: case COMMIT_SHA:
colorAttr = colorAttr.SetColor(style.FgYellow) textStyle = style.FgYellow
} }
return coloredString(colorAttr, content, selected, included) return coloredString(textStyle, content, selected, included)
} }
func coloredString(colorAttr style.TextStyle, str string, selected bool, included bool) string { func coloredString(textStyle style.TextStyle, str string, selected bool, included bool) string {
if selected { if selected {
colorAttr = colorAttr.SetColor(theme.SelectedRangeBgColor) textStyle = textStyle.MergeStyle(theme.SelectedRangeBgColor)
} }
if len(str) < 2 { if len(str) < 2 {
return colorAttr.Sprint(str) return textStyle.Sprint(str)
} }
res := colorAttr.Sprint(str[:1]) res := textStyle.Sprint(str[:1])
if included { if included {
return res + colorAttr.SetColor(style.BgGreen).Sprint(str[1:]) return res + textStyle.MergeStyle(style.BgGreen).Sprint(str[1:])
} }
return res + colorAttr.Sprint(str[1:]) return res + textStyle.Sprint(str[1:])
} }
func parsePatch(patch string) ([]int, []int, []*PatchLine) { func parsePatch(patch string) ([]int, []int, []*PatchLine) {

View File

@ -28,13 +28,13 @@ func (gui *Gui) GetOnRunCommand() func(entry oscommands.CmdLogEntry) {
currentSpan = entry.GetSpan() currentSpan = entry.GetSpan()
} }
clrAttr := theme.DefaultTextColor textStyle := theme.DefaultTextColor
if !entry.GetCommandLine() { if !entry.GetCommandLine() {
clrAttr = clrAttr.SetColor(style.FgMagenta) textStyle = style.FgMagenta
} }
gui.CmdLog = append(gui.CmdLog, entry.GetCmdStr()) gui.CmdLog = append(gui.CmdLog, entry.GetCmdStr())
indentedCmdStr := " " + strings.Replace(entry.GetCmdStr(), "\n", "\n ", -1) indentedCmdStr := " " + strings.Replace(entry.GetCmdStr(), "\n", "\n ", -1)
fmt.Fprint(gui.Views.Extras, "\n"+clrAttr.Sprint(indentedCmdStr)) fmt.Fprint(gui.Views.Extras, "\n"+textStyle.Sprint(indentedCmdStr))
} }
} }

View File

@ -15,8 +15,8 @@ func (gui *Gui) informationStr() string {
} }
if gui.g.Mouse { if gui.g.Mouse {
donate := style.FgMagenta.SetUnderline(true).Sprint(gui.Tr.Donate) donate := style.FgMagenta.SetUnderline().Sprint(gui.Tr.Donate)
askQuestion := style.FgYellow.SetUnderline(true).Sprint(gui.Tr.AskQuestion) askQuestion := style.FgYellow.SetUnderline().Sprint(gui.Tr.AskQuestion)
return fmt.Sprintf("%s %s %s", donate, askQuestion, gui.Config.GetVersion()) return fmt.Sprintf("%s %s %s", donate, askQuestion, gui.Config.GetVersion())
} else { } else {
return gui.Config.GetVersion() return gui.Config.GetVersion()

View File

@ -15,18 +15,18 @@ func ColoredConflictFile(content string, state *State, hasFocus bool) string {
conflict, remainingConflicts := shiftConflict(state.conflicts) conflict, remainingConflicts := shiftConflict(state.conflicts)
var outputBuffer bytes.Buffer var outputBuffer bytes.Buffer
for i, line := range utils.SplitLines(content) { for i, line := range utils.SplitLines(content) {
colour := theme.DefaultTextColor textStyle := theme.DefaultTextColor
if i == conflict.start || i == conflict.middle || i == conflict.end { if i == conflict.start || i == conflict.middle || i == conflict.end {
colour.SetColor(style.FgRed) textStyle = style.FgRed
} }
if hasFocus && state.conflictIndex < len(state.conflicts) && *state.conflicts[state.conflictIndex] == *conflict && shouldHighlightLine(i, conflict, state.conflictTop) { if hasFocus && state.conflictIndex < len(state.conflicts) && *state.conflicts[state.conflictIndex] == *conflict && shouldHighlightLine(i, conflict, state.conflictTop) {
colour = theme.SelectedRangeBgColor.SetBold(true) textStyle = theme.SelectedRangeBgColor.SetBold()
} }
if i == conflict.end && len(remainingConflicts) > 0 { if i == conflict.end && len(remainingConflicts) > 0 {
conflict, remainingConflicts = shiftConflict(remainingConflicts) conflict, remainingConflicts = shiftConflict(remainingConflicts)
} }
outputBuffer.WriteString(colour.Sprint(line) + "\n") outputBuffer.WriteString(textStyle.Sprint(line) + "\n")
} }
return outputBuffer.String() return outputBuffer.String()
} }

View File

@ -27,7 +27,7 @@ func (gui *Gui) modeStatuses() []modeStatus {
{ {
isActive: gui.GitCommand.PatchManager.Active, isActive: gui.GitCommand.PatchManager.Active,
description: func() string { description: func() string {
return style.FgYellow.SetBold(true).Sprintf( return style.FgYellow.SetBold().Sprintf(
"%s %s", "%s %s",
gui.Tr.LcBuildingPatch, gui.Tr.LcBuildingPatch,
style.AttrUnderline.Sprint(gui.Tr.ResetInParentheses), style.AttrUnderline.Sprint(gui.Tr.ResetInParentheses),
@ -38,7 +38,7 @@ func (gui *Gui) modeStatuses() []modeStatus {
{ {
isActive: gui.State.Modes.Filtering.Active, isActive: gui.State.Modes.Filtering.Active,
description: func() string { description: func() string {
return style.FgRed.SetBold(true).Sprintf( return style.FgRed.SetBold().Sprintf(
"%s '%s' %s", "%s '%s' %s",
gui.Tr.LcFilteringBy, gui.Tr.LcFilteringBy,
gui.State.Modes.Filtering.GetPath(), gui.State.Modes.Filtering.GetPath(),

View File

@ -10,6 +10,8 @@ import (
"github.com/kyokomi/emoji/v2" "github.com/kyokomi/emoji/v2"
) )
var cherryPickedCommitTextStyle = style.FgCyan.MergeStyle(style.BgBlue)
func GetCommitListDisplayStrings(commits []*models.Commit, fullDescription bool, cherryPickedCommitShaMap map[string]bool, diffName string, parseEmoji bool) [][]string { func GetCommitListDisplayStrings(commits []*models.Commit, fullDescription bool, cherryPickedCommitShaMap map[string]bool, diffName string, parseEmoji bool) [][]string {
lines := make([][]string, len(commits)) lines := make([][]string, len(commits))
@ -49,7 +51,7 @@ func getFullDescriptionDisplayStringsForCommit(c *models.Commit, cherryPickedCom
// for some reason, setting the background to blue pads out the other commits // for some reason, setting the background to blue pads out the other commits
// horizontally. For the sake of accessibility I'm considering this a feature, // horizontally. For the sake of accessibility I'm considering this a feature,
// not a bug // not a bug
shaColor = style.FgCyan.SetColor(style.BgBlue) shaColor = cherryPickedCommitTextStyle
} }
tagString := "" tagString := ""
@ -57,7 +59,7 @@ func getFullDescriptionDisplayStringsForCommit(c *models.Commit, cherryPickedCom
if c.Action != "" { if c.Action != "" {
secondColumnString = actionColorMap(c.Action).Sprint(c.Action) secondColumnString = actionColorMap(c.Action).Sprint(c.Action)
} else if c.ExtraInfo != "" { } else if c.ExtraInfo != "" {
tagString = theme.DiffTerminalColor.SetBold(true).Sprint(c.ExtraInfo) + " " tagString = theme.DiffTerminalColor.SetBold().Sprint(c.ExtraInfo) + " "
} }
truncatedAuthor := utils.TruncateWithEllipsis(c.Author, 17) truncatedAuthor := utils.TruncateWithEllipsis(c.Author, 17)
@ -96,7 +98,7 @@ func getDisplayStringsForCommit(c *models.Commit, cherryPickedCommitShaMap map[s
// for some reason, setting the background to blue pads out the other commits // for some reason, setting the background to blue pads out the other commits
// horizontally. For the sake of accessibility I'm considering this a feature, // horizontally. For the sake of accessibility I'm considering this a feature,
// not a bug // not a bug
shaColor = style.FgCyan.SetColor(style.BgBlue) shaColor = cherryPickedCommitTextStyle
} }
actionString := "" actionString := ""
@ -104,7 +106,7 @@ func getDisplayStringsForCommit(c *models.Commit, cherryPickedCommitShaMap map[s
if c.Action != "" { if c.Action != "" {
actionString = actionColorMap(c.Action).Sprint(utils.WithPadding(c.Action, 7)) + " " actionString = actionColorMap(c.Action).Sprint(utils.WithPadding(c.Action, 7)) + " "
} else if len(c.Tags) > 0 { } else if len(c.Tags) > 0 {
tagString = theme.DiffTerminalColor.SetBold(true).Sprint(strings.Join(c.Tags, " ")) + " " tagString = theme.DiffTerminalColor.SetBold().Sprint(strings.Join(c.Tags, " ")) + " "
} }
name := c.Name name := c.Name

View File

@ -29,7 +29,7 @@ func GetReflogCommitListDisplayStrings(commits []*models.Commit, fullDescription
func coloredReflogSha(c *models.Commit, cherryPickedCommitShaMap map[string]bool) string { func coloredReflogSha(c *models.Commit, cherryPickedCommitShaMap map[string]bool) string {
shaColor := style.FgBlue shaColor := style.FgBlue
if cherryPickedCommitShaMap[c.Sha] { if cherryPickedCommitShaMap[c.Sha] {
shaColor = style.FgCyan.SetColor(style.BgBlue) shaColor = cherryPickedCommitTextStyle
} }
return shaColor.Sprint(c.ShortSha()) return shaColor.Sprint(c.ShortSha())

View File

@ -1,147 +1,98 @@
package style package style
import ( import (
"fmt"
"github.com/gookit/color" "github.com/gookit/color"
) )
type BasicTextStyle struct { type TextStyle struct {
fg color.Color fg *Color
bg color.Color bg *Color
opts []color.Color decoration Decoration
style color.Style
} }
func (b BasicTextStyle) Sprint(a ...interface{}) string { type Sprinter interface {
return b.style.Sprint(a...) Sprint(a ...interface{}) string
Sprintf(format string, a ...interface{}) string
} }
func (b BasicTextStyle) Sprintf(format string, a ...interface{}) string { func (b TextStyle) Sprint(a ...interface{}) string {
return b.style.Sprintf(format, a...) return b.deriveStyle().Sprint(a...)
} }
func (b BasicTextStyle) deriveStyle() BasicTextStyle { func (b TextStyle) Sprintf(format string, a ...interface{}) string {
// b.style[:0] makes sure to use the same slice memory return b.deriveStyle().Sprintf(format, a...)
if b.fg == 0 { }
// Fg is most of the time defined so we reverse the check
b.style = b.style[:0]
} else {
b.style = append(b.style[:0], b.fg)
}
if b.bg != 0 { func (b TextStyle) SetBold() TextStyle {
b.style = append(b.style, b.bg) b.decoration.SetBold()
}
b.style = append(b.style, b.opts...)
return b return b
} }
func (b BasicTextStyle) setOpt(opt color.Color, v bool, deriveIfChanged bool) BasicTextStyle { func (b TextStyle) SetUnderline() TextStyle {
if v { b.decoration.SetUnderline()
// Add value
for _, listOpt := range b.opts {
if listOpt == opt {
// Option already added
return b
}
}
b.opts = append(b.opts, opt)
} else {
// Remove value
for idx, listOpt := range b.opts {
if listOpt == opt {
b.opts = append(b.opts[:idx], b.opts[idx+1:]...)
if deriveIfChanged {
return b.deriveStyle()
}
return b
}
}
}
if deriveIfChanged {
return b.deriveStyle()
}
return b return b
} }
func (b BasicTextStyle) SetBold(v bool) TextStyle { func (b TextStyle) SetReverse() TextStyle {
return b.setOpt(color.OpBold, v, true) b.decoration.SetReverse()
return b
} }
func (b BasicTextStyle) SetReverse(v bool) TextStyle { func (b TextStyle) deriveStyle() Sprinter {
return b.setOpt(color.OpReverse, v, true) // TODO: consider caching
return deriveStyle(b.fg, b.bg, b.decoration)
} }
func (b BasicTextStyle) SetUnderline(v bool) TextStyle { func deriveStyle(fg *Color, bg *Color, decoration Decoration) Sprinter {
return b.setOpt(color.OpUnderscore, v, true) if fg == nil && bg == nil {
} return color.Style(decoration.ToOpts())
func (b BasicTextStyle) SetRGBColor(red, green, blue uint8, background bool) TextStyle {
return b.convertToRGB().SetRGBColor(red, green, blue, background)
}
func (b BasicTextStyle) convertToRGB() RGBTextStyle {
res := RGBTextStyle{
fg: b.fg.RGB(),
fgSet: b.fg != 0,
opts: b.opts,
} }
if b.bg != 0 { isRgb := (fg != nil && fg.IsRGB()) || (bg != nil && bg.IsRGB())
// Need to convert bg to fg otherwise .RGB wont work if isRgb {
// for more info see https://github.com/gookit/color/issues/39 s := &color.RGBStyle{}
rgbBg := (b.bg - 10).RGB() if fg != nil {
rgbBg[3] = 1 s.SetFg(*fg.ToRGB().rgb)
res.bg = &rgbBg }
res.style = *color.NewRGBStyle(res.fg, rgbBg) if bg != nil {
} else { s.SetBg(*bg.ToRGB().rgb)
res.style = *color.NewRGBStyle(res.fg) }
s.SetOpts(decoration.ToOpts())
return s
} }
res.style.SetOpts(b.opts)
return res style := make([]color.Color, 0, 5)
if fg != nil {
style = append(style, *fg.basic)
}
if bg != nil {
style = append(style, *bg.basic)
}
style = append(style, decoration.ToOpts()...)
return color.Style(style)
} }
func (b BasicTextStyle) SetColor(other TextStyle) TextStyle { // // Need to convert bg to fg otherwise .RGB wont work
switch typedOther := other.(type) { // // for more info see https://github.com/gookit/color/issues/39
case BasicTextStyle: // rgbBg := (*b.bg - 10).RGB()
if typedOther.fg != 0 { // rgbBg[3] = 1
b.fg = typedOther.fg // *res.bg = rgbBg
} // res.style = *color.NewRGBStyle(*res.fg, rgbBg)
if typedOther.bg != 0 {
b.bg = typedOther.bg
}
for _, opt := range typedOther.opts {
b = b.setOpt(opt, true, false)
}
return b.deriveStyle()
case RGBTextStyle:
bAsRGB := b.convertToRGB()
for _, opt := range typedOther.opts { func (b TextStyle) MergeStyle(other TextStyle) TextStyle {
bAsRGB.setOpt(opt, true) b.decoration = b.decoration.Merge(other.decoration)
}
if typedOther.fgSet { if other.fg != nil {
bAsRGB.fg = typedOther.fg b.fg = other.fg
bAsRGB.style.SetFg(typedOther.fg)
}
if typedOther.bg != nil {
// Making sure to copy the value
bAsRGB.bg = &color.RGBColor{}
*bAsRGB.bg = *typedOther.bg
bAsRGB.style.SetBg(*typedOther.bg)
}
return bAsRGB
default:
panic(fmt.Sprintf("got %T but expected BasicTextStyle or RGBTextStyle", typedOther))
} }
if other.bg != nil {
b.bg = other.bg
}
return b
} }

35
pkg/gui/style/color.go Normal file
View File

@ -0,0 +1,35 @@
package style
import "github.com/gookit/color"
type Color struct {
rgb *color.RGBColor
basic *color.Color
}
func NewRGBColor(cl color.RGBColor) Color {
c := Color{}
c.rgb = &cl
return c
}
func NewBasicColor(cl color.Color) Color {
c := Color{}
c.basic = &cl
return c
}
func (c *Color) IsRGB() bool {
return c.rgb != nil
}
func (c *Color) ToRGB() Color {
if c.IsRGB() {
return *c
}
rgb := c.basic.RGB()
c.rgb = &rgb
return NewRGBColor(rgb)
}

View File

@ -0,0 +1,53 @@
package style
import "github.com/gookit/color"
type Decoration struct {
bold bool
underline bool
reverse bool
}
func (d Decoration) SetBold() {
d.bold = true
}
func (d Decoration) SetUnderline() {
d.underline = true
}
func (d Decoration) SetReverse() {
d.reverse = true
}
func (d Decoration) ToOpts() color.Opts {
opts := make([]color.Color, 0, 3)
if d.bold {
opts = append(opts, color.OpBold)
}
if d.underline {
opts = append(opts, color.OpUnderscore)
}
if d.reverse {
opts = append(opts, color.OpReverse)
}
return opts
}
func (d Decoration) Merge(other Decoration) Decoration {
if other.bold {
d.bold = true
}
if other.underline {
d.underline = true
}
if other.reverse {
d.reverse = true
}
return d
}

View File

@ -1,111 +0,0 @@
package style
import (
"fmt"
"github.com/gookit/color"
)
type RGBTextStyle struct {
opts color.Opts
fgSet bool
fg color.RGBColor
bg *color.RGBColor
style color.RGBStyle
}
func (b RGBTextStyle) Sprint(a ...interface{}) string {
return b.style.Sprint(a...)
}
func (b RGBTextStyle) Sprintf(format string, a ...interface{}) string {
return b.style.Sprintf(format, a...)
}
func (b RGBTextStyle) setOpt(opt color.Color, v bool) RGBTextStyle {
if v {
// Add value
for _, listOpt := range b.opts {
if listOpt == opt {
return b
}
}
b.opts = append(b.opts, opt)
} else {
// Remove value
for idx, listOpt := range b.opts {
if listOpt == opt {
b.opts = append(b.opts[:idx], b.opts[idx+1:]...)
return b
}
}
}
return b
}
func (b RGBTextStyle) SetBold(v bool) TextStyle {
b = b.setOpt(color.OpBold, v)
b.style.SetOpts(b.opts)
return b
}
func (b RGBTextStyle) SetReverse(v bool) TextStyle {
b = b.setOpt(color.OpReverse, v)
b.style.SetOpts(b.opts)
return b
}
func (b RGBTextStyle) SetUnderline(v bool) TextStyle {
b = b.setOpt(color.OpUnderscore, v)
b.style.SetOpts(b.opts)
return b
}
func (b RGBTextStyle) SetColor(style TextStyle) TextStyle {
var rgbStyle RGBTextStyle
switch typedStyle := style.(type) {
case BasicTextStyle:
rgbStyle = typedStyle.convertToRGB()
case RGBTextStyle:
rgbStyle = typedStyle
default:
panic(fmt.Sprintf("got %T but expected BasicTextStyle or RGBTextStyle", typedStyle))
}
for _, opt := range rgbStyle.GetOpts() {
b = b.setOpt(opt, true)
}
if rgbStyle.fgSet {
b.fg = rgbStyle.fg
b.style.SetFg(rgbStyle.fg)
b.fgSet = true
}
if rgbStyle.bg != nil {
// Making sure to copy value
b.bg = &color.RGBColor{}
*b.bg = *rgbStyle.bg
b.style.SetBg(*rgbStyle.bg)
}
return b
}
func (b RGBTextStyle) SetRGBColor(red, green, blue uint8, background bool) TextStyle {
parsedColor := color.Rgb(red, green, blue, background)
if background {
b.bg = &parsedColor
b.style.SetBg(parsedColor)
} else {
b.fg = parsedColor
b.style.SetFg(parsedColor)
b.fgSet = true
}
return b
}
func (b RGBTextStyle) GetOpts() color.Opts {
return b.opts
}

View File

@ -5,91 +5,90 @@ import (
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
) )
type TextStyle interface {
Sprint(a ...interface{}) string
Sprintf(format string, a ...interface{}) string
SetBold(v bool) TextStyle
SetReverse(v bool) TextStyle
SetUnderline(v bool) TextStyle
SetColor(style TextStyle) TextStyle
SetRGBColor(r, g, b uint8, background bool) TextStyle
}
var ( var (
FgWhite = New(color.FgWhite, 0) // FgWhite = New(pointerTo(color.FgWhite), nil)
FgLightWhite = New(color.FgLightWhite, 0) FgWhite = FromBasicFg(color.FgWhite)
FgBlack = New(color.FgBlack, 0) FgLightWhite = FromBasicFg(color.FgLightWhite)
FgBlackLighter = New(color.FgBlack.Light(), 0) FgBlack = FromBasicFg(color.FgBlack)
FgCyan = New(color.FgCyan, 0) FgBlackLighter = FromBasicFg(color.FgBlack.Light())
FgRed = New(color.FgRed, 0) FgCyan = FromBasicFg(color.FgCyan)
FgGreen = New(color.FgGreen, 0) FgRed = FromBasicFg(color.FgRed)
FgBlue = New(color.FgBlue, 0) FgGreen = FromBasicFg(color.FgGreen)
FgYellow = New(color.FgYellow, 0) FgBlue = FromBasicFg(color.FgBlue)
FgMagenta = New(color.FgMagenta, 0) FgYellow = FromBasicFg(color.FgYellow)
FgMagenta = FromBasicFg(color.FgMagenta)
BgWhite = New(0, color.BgWhite) BgWhite = FromBasicBg(color.BgWhite)
BgBlack = New(0, color.BgBlack) BgBlack = FromBasicBg(color.BgBlack)
BgRed = New(0, color.BgRed) BgRed = FromBasicBg(color.BgRed)
BgGreen = New(0, color.BgGreen) BgGreen = FromBasicBg(color.BgGreen)
BgYellow = New(0, color.BgYellow) BgYellow = FromBasicBg(color.BgYellow)
BgBlue = New(0, color.BgBlue) BgBlue = FromBasicBg(color.BgBlue)
BgMagenta = New(0, color.BgMagenta) BgMagenta = FromBasicBg(color.BgMagenta)
BgCyan = New(0, color.BgCyan) BgCyan = FromBasicBg(color.BgCyan)
AttrUnderline = New(0, 0).SetUnderline(true) AttrUnderline = New().SetUnderline()
AttrBold = New(0, 0).SetUnderline(true) AttrBold = New().SetBold()
) )
func New(fg color.Color, bg color.Color, opts ...color.Color) TextStyle { func New() TextStyle {
return BasicTextStyle{ return TextStyle{}
fg: fg,
bg: bg,
opts: opts,
style: color.Style{},
}.deriveStyle()
} }
func SetConfigStyles(s TextStyle, keys []string, background bool) TextStyle { func FromBasicFg(fg color.Color) TextStyle {
s := New()
c := NewBasicColor(fg)
s.fg = &c
return s
}
func FromBasicBg(bg color.Color) TextStyle {
s := New()
c := NewBasicColor(bg)
s.bg = &c
return s
}
var colorMap = map[string]struct {
forground TextStyle
background TextStyle
}{
"default": {FgWhite, BgBlack},
"black": {FgBlack, BgBlack},
"red": {FgRed, BgRed},
"green": {FgGreen, BgGreen},
"yellow": {FgYellow, BgYellow},
"blue": {FgBlue, BgBlue},
"magenta": {FgMagenta, BgMagenta},
"cyan": {FgCyan, BgCyan},
"white": {FgWhite, BgWhite},
}
func SetConfigStyles(keys []string, background bool) TextStyle {
s := New()
for _, key := range keys { for _, key := range keys {
colorMap := map[string]struct { switch key {
forground TextStyle case "bold":
background TextStyle s = s.SetBold()
}{ case "reverse":
"default": {FgWhite, BgBlack}, s = s.SetReverse()
"black": {FgBlack, BgBlack}, case "underline":
"red": {FgRed, BgRed}, s = s.SetUnderline()
"green": {FgGreen, BgGreen}, default:
"yellow": {FgYellow, BgYellow}, value, present := colorMap[key]
"blue": {FgBlue, BgBlue}, if present {
"magenta": {FgMagenta, BgMagenta}, var c TextStyle
"cyan": {FgCyan, BgCyan}, if background {
"white": {FgWhite, BgWhite}, c = value.background
} } else {
value, present := colorMap[key] c = value.forground
if present { }
if background { s = s.MergeStyle(c)
s = s.SetColor(value.background) } else if utils.IsValidHexValue(key) {
} else { c := NewRGBColor(color.HEX(key, background))
s = s.SetColor(value.forground) s.bg = &c
} }
continue
}
if key == "bold" {
s = s.SetBold(true)
continue
} else if key == "reverse" {
s = s.SetReverse(true)
continue
} else if key == "underline" {
s = s.SetUnderline(true)
continue
}
r, g, b, validHexColor := utils.GetHexColorValues(key)
if validHexColor {
s = s.SetRGBColor(r, g, b, background)
continue
} }
} }

View File

@ -53,39 +53,39 @@ func TestNewStyle(t *testing.T) {
func TestBasicSetColor(t *testing.T) { func TestBasicSetColor(t *testing.T) {
type scenario struct { type scenario struct {
name string name string
colorToSet BasicTextStyle colorToSet TextStyle
expect BasicTextStyle expect TextStyle
} }
scenarios := []scenario{ scenarios := []scenario{
{ {
"empty color", "empty color",
BasicTextStyle{}, TextStyle{},
BasicTextStyle{fg: color.FgRed, bg: color.BgBlue, opts: []color.Color{color.OpBold}}}, TextStyle{fg: color.FgRed, bg: color.BgBlue, opts: []color.Color{color.OpBold}}},
{ {
"set new fg color", "set new fg color",
BasicTextStyle{fg: color.FgCyan}, TextStyle{fg: color.FgCyan},
BasicTextStyle{fg: color.FgCyan, bg: color.BgBlue, opts: []color.Color{color.OpBold}}, TextStyle{fg: color.FgCyan, bg: color.BgBlue, opts: []color.Color{color.OpBold}},
}, },
{ {
"set new bg color", "set new bg color",
BasicTextStyle{bg: color.BgGray}, TextStyle{bg: color.BgGray},
BasicTextStyle{fg: color.FgRed, bg: color.BgGray, opts: []color.Color{color.OpBold}}, TextStyle{fg: color.FgRed, bg: color.BgGray, opts: []color.Color{color.OpBold}},
}, },
{ {
"set new fg and bg color", "set new fg and bg color",
BasicTextStyle{fg: color.FgCyan, bg: color.BgGray}, TextStyle{fg: color.FgCyan, bg: color.BgGray},
BasicTextStyle{fg: color.FgCyan, bg: color.BgGray, opts: []color.Color{color.OpBold}}, TextStyle{fg: color.FgCyan, bg: color.BgGray, opts: []color.Color{color.OpBold}},
}, },
{ {
"add options", "add options",
BasicTextStyle{opts: []color.Color{color.OpUnderscore}}, TextStyle{opts: []color.Color{color.OpUnderscore}},
BasicTextStyle{fg: color.FgRed, bg: color.BgBlue, opts: []color.Color{color.OpBold, color.OpUnderscore}}, TextStyle{fg: color.FgRed, bg: color.BgBlue, opts: []color.Color{color.OpBold, color.OpUnderscore}},
}, },
{ {
"add options that already exists", "add options that already exists",
BasicTextStyle{opts: []color.Color{color.OpBold}}, TextStyle{opts: []color.Color{color.OpBold}},
BasicTextStyle{fg: color.FgRed, bg: color.BgBlue, opts: []color.Color{color.OpBold}}, TextStyle{fg: color.FgRed, bg: color.BgBlue, opts: []color.Color{color.OpBold}},
}, },
} }
@ -127,12 +127,12 @@ func TestRGBSetColor(t *testing.T) {
}, },
{ {
"empty BasicTextStyle input", "empty BasicTextStyle input",
BasicTextStyle{}, TextStyle{},
RGBTextStyle{fgSet: true, fg: red, bg: toBg(blue), opts: []color.Color{color.OpBold}}, RGBTextStyle{fgSet: true, fg: red, bg: toBg(blue), opts: []color.Color{color.OpBold}},
}, },
{ {
"set fg and bg color using BasicTextStyle", "set fg and bg color using BasicTextStyle",
BasicTextStyle{fg: color.FgCyan, bg: color.BgGray}, TextStyle{fg: color.FgCyan, bg: color.BgGray},
RGBTextStyle{fgSet: true, fg: cyan, bg: toBg(gray), opts: []color.Color{color.OpBold}}, RGBTextStyle{fgSet: true, fg: cyan, bg: toBg(gray), opts: []color.Color{color.OpBold}},
}, },
{ {
@ -147,7 +147,7 @@ func TestRGBSetColor(t *testing.T) {
}, },
{ {
"add options using BasicTextStyle", "add options using BasicTextStyle",
BasicTextStyle{opts: []color.Color{color.OpUnderscore}}, TextStyle{opts: []color.Color{color.OpUnderscore}},
RGBTextStyle{fgSet: true, fg: red, bg: toBg(blue), opts: []color.Color{color.OpBold, color.OpUnderscore}}, RGBTextStyle{fgSet: true, fg: red, bg: toBg(blue), opts: []color.Color{color.OpBold, color.OpUnderscore}},
}, },
{ {
@ -159,10 +159,10 @@ func TestRGBSetColor(t *testing.T) {
for _, s := range scenarios { for _, s := range scenarios {
t.Run(s.name, func(t *testing.T) { t.Run(s.name, func(t *testing.T) {
style, ok := New(color.FgRed, color.BgBlue).SetBold(true).(BasicTextStyle) style, ok := New(color.FgRed, color.BgBlue).SetBold().(BasicTextStyle)
assert.True(t, ok, "SetBold should return a interface of type BasicTextStyle") assert.True(t, ok, "SetBold should return a interface of type BasicTextStyle")
rgbStyle, ok := style.convertToRGB().SetColor(s.colorToSet).(RGBTextStyle) rgbStyle, ok := style.convertToRGB().MergeStyle(s.colorToSet).(RGBTextStyle)
assert.True(t, ok, "SetColor should return a interface of type RGBTextColor") assert.True(t, ok, "SetColor should return a interface of type RGBTextColor")
rgbStyle.style = color.RGBStyle{} rgbStyle.style = color.RGBStyle{}

View File

@ -24,31 +24,31 @@ var (
OptionsColor gocui.Attribute OptionsColor gocui.Attribute
// DefaultTextColor is the default text color // DefaultTextColor is the default text color
DefaultTextColor = style.New(color.FgWhite, 0) DefaultTextColor = style.FgWhite
// DefaultHiTextColor is the default highlighted text color // DefaultHiTextColor is the default highlighted text color
DefaultHiTextColor = style.New(color.FgLightWhite, 0) DefaultHiTextColor = style.FgLightWhite
// SelectedLineBgColor is the background color for the selected line // SelectedLineBgColor is the background color for the selected line
SelectedLineBgColor = style.New(0, 0) SelectedLineBgColor = style.New()
// SelectedRangeBgColor is the background color of the selected range of lines // SelectedRangeBgColor is the background color of the selected range of lines
SelectedRangeBgColor = style.New(0, 0) SelectedRangeBgColor = style.New()
OptionsFgColor = style.New(0, 0) OptionsFgColor = style.New()
DiffTerminalColor = style.New(color.FgMagenta, 0) DiffTerminalColor = style.FgMagenta
) )
// UpdateTheme updates all theme variables // UpdateTheme updates all theme variables
func UpdateTheme(themeConfig config.ThemeConfig) { func UpdateTheme(themeConfig config.ThemeConfig) {
ActiveBorderColor = GetGocuiColor(themeConfig.ActiveBorderColor) ActiveBorderColor = GetGocuiColor(themeConfig.ActiveBorderColor)
InactiveBorderColor = GetGocuiColor(themeConfig.InactiveBorderColor) InactiveBorderColor = GetGocuiColor(themeConfig.InactiveBorderColor)
SelectedLineBgColor = style.SetConfigStyles(SelectedLineBgColor, themeConfig.SelectedLineBgColor, true) SelectedLineBgColor = style.SetConfigStyles(themeConfig.SelectedLineBgColor, true)
SelectedRangeBgColor = style.SetConfigStyles(SelectedRangeBgColor, themeConfig.SelectedRangeBgColor, true) SelectedRangeBgColor = style.SetConfigStyles(themeConfig.SelectedRangeBgColor, true)
GocuiSelectedLineBgColor = GetGocuiColor(themeConfig.SelectedLineBgColor) GocuiSelectedLineBgColor = GetGocuiColor(themeConfig.SelectedLineBgColor)
OptionsColor = GetGocuiColor(themeConfig.OptionsTextColor) OptionsColor = GetGocuiColor(themeConfig.OptionsTextColor)
OptionsFgColor = style.SetConfigStyles(OptionsFgColor, themeConfig.OptionsTextColor, false) OptionsFgColor = style.SetConfigStyles(themeConfig.OptionsTextColor, false)
isLightTheme := themeConfig.LightTheme isLightTheme := themeConfig.LightTheme
if isLightTheme { if isLightTheme {
@ -64,9 +64,9 @@ func UpdateTheme(themeConfig config.ThemeConfig) {
// GetAttribute gets the gocui color attribute from the string // GetAttribute gets the gocui color attribute from the string
func GetGocuiAttribute(key string) gocui.Attribute { func GetGocuiAttribute(key string) gocui.Attribute {
r, g, b, validHexColor := utils.GetHexColorValues(key) if utils.IsValidHexValue(key) {
if validHexColor { values := color.HEX(key).Values()
return gocui.NewRGBColor(int32(r), int32(g), int32(b)) return gocui.NewRGBColor(int32(values[0]), int32(values[1]), int32(values[2]))
} }
colorMap := map[string]gocui.Attribute{ colorMap := map[string]gocui.Attribute{

View File

@ -1,7 +1,6 @@
package utils package utils
import ( import (
"encoding/hex"
"regexp" "regexp"
) )
@ -33,22 +32,23 @@ func getPadWidths(stringArrays [][]string) []int {
return padWidths return padWidths
} }
// GetHexColorValues returns the rgb values of a hex color func IsValidHexValue(v string) bool {
func GetHexColorValues(v string) (r uint8, g uint8, b uint8, valid bool) { if len(v) != 4 && len(v) != 7 {
if len(v) == 4 { return false
v = string([]byte{v[0], v[1], v[1], v[2], v[2], v[3], v[3]})
} else if len(v) != 7 {
return
} }
if v[0] != '#' { if v[0] != '#' {
return return false
} }
rgb, err := hex.DecodeString(v[1:]) for _, char := range v[1:] {
if err != nil { switch char {
return case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F':
continue
default:
return false
}
} }
return rgb[0], rgb[1], rgb[2], true return true
} }