Skip to content

Commit

Permalink
ref(color): simplify the color interface
Browse files Browse the repository at this point in the history
The `Sequence` function doesn't need to have a bg argument, this should
be the job of the styler to apply bg specific modifications.

Make `ANSIColor` into a struct with a `bg` flag.
  • Loading branch information
aymanbagabas committed Feb 6, 2023
1 parent 0822a5c commit a9f4749
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 87 deletions.
34 changes: 17 additions & 17 deletions ansicolors.go
@@ -1,23 +1,23 @@
package termenv

// ANSI color codes
const (
ANSIBlack ANSIColor = iota
ANSIRed
ANSIGreen
ANSIYellow
ANSIBlue
ANSIMagenta
ANSICyan
ANSIWhite
ANSIBrightBlack
ANSIBrightRed
ANSIBrightGreen
ANSIBrightYellow
ANSIBrightBlue
ANSIBrightMagenta
ANSIBrightCyan
ANSIBrightWhite
var (
ANSIBlack = ANSIColor{Color: 0}
ANSIRed = ANSIColor{Color: 1}
ANSIGreen = ANSIColor{Color: 2}
ANSIYellow = ANSIColor{Color: 3}
ANSIBlue = ANSIColor{Color: 4}
ANSIMagenta = ANSIColor{Color: 5}
ANSICyan = ANSIColor{Color: 6}
ANSIWhite = ANSIColor{Color: 7}
ANSIBrightBlack = ANSIColor{Color: 8}
ANSIBrightRed = ANSIColor{Color: 9}
ANSIBrightGreen = ANSIColor{Color: 10}
ANSIBrightYellow = ANSIColor{Color: 11}
ANSIBrightBlue = ANSIColor{Color: 12}
ANSIBrightMagenta = ANSIColor{Color: 13}
ANSIBrightCyan = ANSIColor{Color: 14}
ANSIBrightWhite = ANSIColor{Color: 15}
)

// RGB values of ANSI colors (0-255).
Expand Down
60 changes: 34 additions & 26 deletions color.go
Expand Up @@ -14,17 +14,30 @@ var (
ErrInvalidColor = errors.New("invalid color")
)

const (
// Foreground sequence code.
ForegroudSeq = "38"
// Background sequence code.
BackgroundSeq = "48"
)

// Foreground and Background sequence codes
const (
Foreground = "38"
Background = "48"
// Foreground sequence code.
//
// Deprecated: use ForegroudSeq
Foreground = ForegroudSeq
// Background sequence code.
//
// Deprecated: use BackgroundSeq
Background = BackgroundSeq
)

// Color is an interface implemented by all colors that can be converted to an
// ANSI sequence.
type Color interface {
// Sequence returns the ANSI Sequence for the color.
Sequence(bg bool) string
Sequence() string
}

// NoColor is a nop for terminals that don't support colors.
Expand All @@ -35,10 +48,13 @@ func (c NoColor) String() string {
}

// ANSIColor is a color (0-15) as defined by the ANSI Standard.
type ANSIColor int
type ANSIColor struct {
Color int
bg bool
}

func (c ANSIColor) String() string {
return ansiHex[c]
return ansiHex[c.Color]
}

// ANSI256Color is a color (16-255) as defined by the ANSI Standard.
Expand All @@ -58,7 +74,7 @@ func ConvertToRGB(c Color) colorful.Color {
case RGBColor:
hex = string(v)
case ANSIColor:
hex = ansiHex[v]
hex = ansiHex[v.Color]
case ANSI256Color:
hex = ansiHex[v]
}
Expand All @@ -68,18 +84,18 @@ func ConvertToRGB(c Color) colorful.Color {
}

// Sequence returns the ANSI Sequence for the color.
func (c NoColor) Sequence(bg bool) string {
func (c NoColor) Sequence() string {
return ""
}

// Sequence returns the ANSI Sequence for the color.
func (c ANSIColor) Sequence(bg bool) string {
col := int(c)
bgMod := func(c int) int {
if bg {
return c + 10
func (c ANSIColor) Sequence() string {
col := int(c.Color)
bgMod := func(col int) int {
if c.bg {
return col + 10
}
return c
return col
}

if col < 8 {
Expand All @@ -89,26 +105,18 @@ func (c ANSIColor) Sequence(bg bool) string {
}

// Sequence returns the ANSI Sequence for the color.
func (c ANSI256Color) Sequence(bg bool) string {
prefix := Foreground
if bg {
prefix = Background
}
return fmt.Sprintf("%s;5;%d", prefix, c)
func (c ANSI256Color) Sequence() string {
return fmt.Sprintf("5;%d", c)
}

// Sequence returns the ANSI Sequence for the color.
func (c RGBColor) Sequence(bg bool) string {
func (c RGBColor) Sequence() string {
f, err := colorful.Hex(string(c))
if err != nil {
return ""
}

prefix := Foreground
if bg {
prefix = Background
}
return fmt.Sprintf("%s;2;%d;%d;%d", prefix, uint8(f.R*255), uint8(f.G*255), uint8(f.B*255))
return fmt.Sprintf("2;%d;%d;%d", uint8(f.R*255), uint8(f.G*255), uint8(f.B*255))
}

func xTermColor(s string) (RGBColor, error) {
Expand Down Expand Up @@ -155,7 +163,7 @@ func ansi256ToANSIColor(c ANSI256Color) ANSIColor {
}
}

return ANSIColor(r)
return ANSIColor{Color: r}
}

func hexToANSI256Color(c colorful.Color) ANSI256Color {
Expand Down
2 changes: 1 addition & 1 deletion profile.go
Expand Up @@ -81,7 +81,7 @@ func (p Profile) Color(s string) Color {
}

if i < 16 {
c = ANSIColor(i)
c = ANSIColor{Color: i}
} else {
c = ANSI256Color(i)
}
Expand Down
20 changes: 18 additions & 2 deletions style.go
Expand Up @@ -59,15 +59,31 @@ func (t Style) Styled(s string) string {
// Foreground sets a foreground color.
func (t Style) Foreground(c Color) Style {
if c != nil {
t.styles = append(t.styles, c.Sequence(false))
if ac, ok := c.(ANSIColor); ok {
// ANSIColor(s) are their own sequences.
ac.bg = false
c = ac
} else if _, ok := c.(NoColor); !ok {
// NoColor can't have any sequences
t.styles = append(t.styles, ForegroudSeq)
}
t.styles = append(t.styles, c.Sequence())
}
return t
}

// Background sets a background color.
func (t Style) Background(c Color) Style {
if c != nil {
t.styles = append(t.styles, c.Sequence(true))
if ac, ok := c.(ANSIColor); ok {
// ANSIColor(s) are their own sequences.
ac.bg = true
c = ac
} else if _, ok := c.(NoColor); !ok {
// NoColor can't have any sequences
t.styles = append(t.styles, BackgroundSeq)
}
t.styles = append(t.styles, c.Sequence())
}
return t
}
Expand Down
4 changes: 2 additions & 2 deletions termenv_other.go
Expand Up @@ -13,12 +13,12 @@ func (o Output) ColorProfile() Profile {

func (o Output) foregroundColor() Color {
// default gray
return ANSIColor(7)
return ANSIColor{color: 7}
}

func (o Output) backgroundColor() Color {
// default black
return ANSIColor(0)
return ANSIColor{color: 0, bg: true}
}

// EnableVirtualTerminalProcessing enables virtual terminal processing on
Expand Down

0 comments on commit a9f4749

Please sign in to comment.