Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ref(color): simplify the color interface #113

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
34 changes: 17 additions & 17 deletions ansicolors.go
Original file line number Diff line number Diff line change
@@ -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
69 changes: 40 additions & 29 deletions color.go
Original file line number Diff line number Diff line change
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,14 +48,20 @@ func (c NoColor) String() string {
}

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

func (c ANSIColor) String() string {
return ansiHex[c]
if c.Color >= 16 {
return ""
}
return ansiHex[c.Color]
}

// ANSI256Color is a color (16-255) as defined by the ANSI Standard.
type ANSI256Color int
type ANSI256Color uint8

func (c ANSI256Color) String() string {
return ansiHex[c]
Expand All @@ -58,7 +77,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 +87,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 +108,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 @@ -141,7 +152,7 @@ func xTermColor(s string) (RGBColor, error) {
}

func ansi256ToANSIColor(c ANSI256Color) ANSIColor {
var r int
var r uint8
md := math.MaxFloat64

h, _ := colorful.Hex(ansiHex[c])
Expand All @@ -151,11 +162,11 @@ func ansi256ToANSIColor(c ANSI256Color) ANSIColor {

if d < md {
md = d
r = i
r = uint8(i)
}
}

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

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

if i < 16 {
c = ANSIColor(i)
c = ANSIColor{Color: uint8(i)}
} else {
c = ANSI256Color(i)
}
Expand Down
20 changes: 18 additions & 2 deletions style.go
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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}
}

// EnableVirtualTerminalProcessing enables virtual terminal processing on
Expand Down