Skip to content

Commit

Permalink
text: 256 and true color support
Browse files Browse the repository at this point in the history
  • Loading branch information
jedib0t committed Aug 31, 2023
1 parent 05c0986 commit a6ce26d
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 0 deletions.
49 changes: 49 additions & 0 deletions text/colors_256.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package text

import (
"fmt"
)

const (
escCodeColor256Background = "48;5;"
escCodeColor256Foreground = "38;5;"
)

// Colors256 contains 8-bit (256) colors for foreground and background.
type Colors256 struct {
Background uint8 `json:"background"`
Foreground uint8 `json:"foreground"`
}

var (
mapColors256EscapeSeq = map[uint]string{}
)

// EscapeSeq returns the ANSI escape sequence for the color.
func (c Colors256) EscapeSeq() string {
mapKey := (uint(c.Background) * 1000) + uint(c.Foreground)
if _, ok := mapColors256EscapeSeq[mapKey]; !ok {
mapColors256EscapeSeq[mapKey] = fmt.Sprintf("%s%s%d;%s%d;%s",
EscapeStart,
escCodeColor256Background, c.Background,
escCodeColor256Foreground, c.Foreground,
EscapeStop,
)
}
return mapColors256EscapeSeq[mapKey]
}

// HTMLProperty returns the "style" attribute for the colors with for.
func (c Colors256) HTMLProperty() string {
return "" // TODO
}

// Sprint colorizes and prints the given string(s).
func (c Colors256) Sprint(a ...interface{}) string {
return colorize(fmt.Sprint(a...), c.EscapeSeq())
}

// Sprintf formats and colorizes and prints the given string(s).
func (c Colors256) Sprintf(format string, a ...interface{}) string {
return colorize(fmt.Sprintf(format, a...), c.EscapeSeq())
}
Binary file added text/colors_256.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
53 changes: 53 additions & 0 deletions text/colors_true.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package text

import (
"fmt"
"strings"
)

const (
escCodeColorRGBForeground = "38;2;"
escCodeColorRGBBackground = "48;2;"
)

// ColorsTrue represents True-color values for foreground and background.
type ColorsTrue struct {
Foreground RGB `json:"foreground"`
Background RGB `json:"background"`

escapeSeq string
}

// EscapeSeq returns the ANSI escape sequence for the color.
func (c ColorsTrue) EscapeSeq() string {
if c.escapeSeq == "" {
c.escapeSeq = fmt.Sprintf("%s%s%d;%d;%d;%s%d;%d;%d;%s",
EscapeStart,
escCodeColorRGBForeground, c.Foreground.R, c.Foreground.G, c.Foreground.B,
escCodeColorRGBBackground, c.Background.R, c.Background.G, c.Background.B,
EscapeStop,
)
}
return c.escapeSeq
}

// HTMLProperty returns the "style" attribute for the colors with for.
func (c ColorsTrue) HTMLProperty() string {
sb := strings.Builder{}
sb.WriteString("style=\"")
sb.WriteString(fmt.Sprintf("color: #%s;", c.Foreground.HexValue()))
sb.WriteString(fmt.Sprintf("background-color: #%s;", c.Background.HexValue()))
sb.WriteString("\"")
return sb.String()
}

// Sprint colorizes and
// Sprint colorizes and prints the given string(s).
func (c ColorsTrue) Sprint(a ...interface{}) string {
return colorize(fmt.Sprint(a...), c.EscapeSeq())
}

// Sprintf formats and colorizes and prints the given string(s).
func (c ColorsTrue) Sprintf(format string, a ...interface{}) string {
return colorize(fmt.Sprintf(format, a...), c.EscapeSeq())
}
22 changes: 22 additions & 0 deletions text/rgb.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package text

import "fmt"

// RGB contains the Red/Green/Blue values that make up a True Color.
type RGB struct {
R uint8 `json:"r"`
G uint8 `json:"g"`
B uint8 `json:"b"`
}

func (rgb RGB) HexValue() string {
return fmt.Sprintf("#%02x%02x%02x", rgb.R, rgb.G, rgb.B)
}

func RGBFrom8BitColor(c uint8) RGB {
return RGB{
R: (((c >> 5) & 0x07) * 255) / 7,
G: (((c >> 2) & 0x07) * 255) / 7,
B: ((c & 0x03) * 255) / 3,
}
}
47 changes: 47 additions & 0 deletions text/rgb_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package text

import (
"fmt"
"strings"
"testing"

"github.com/stretchr/testify/assert"
)

func TestRGB_HexValue(t *testing.T) {
assert.Equal(t, "#000000", RGB{0, 0, 0}.HexValue())
assert.Equal(t, "#ff0000", RGB{255, 0, 0}.HexValue())
assert.Equal(t, "#00ff00", RGB{0, 255, 0}.HexValue())
assert.Equal(t, "#0000ff", RGB{0, 0, 255}.HexValue())
assert.Equal(t, "#ffffff", RGB{255, 255, 255}.HexValue())
assert.Equal(t, "#7f7f7f", RGB{127, 127, 127}.HexValue())
}

func TestRGBFrom8BitColor(t *testing.T) {
sb := strings.Builder{}
sb.WriteString("<html><table>\n")
for idx := uint8(0); idx <= uint8(255); idx++ {
if idx == 0 || (idx > 15 && idx < 232 && ((idx-16)%36) == 0) || idx == 232 {
sb.WriteString("<tr>\n")
}
if idx == 8 || idx == 244 {
sb.WriteString("<td>&nbsp;</td>")
}
rgb := RGBFrom8BitColor(idx)
sb.WriteString(
fmt.Sprintf(
"<td style=\"background-color: %s\">%03d</td>\n",
rgb.HexValue(), idx,
),
)
if idx == 15 || (idx > 15 && idx < 232 && ((idx-16)%36) == 35) || idx == 255 {
sb.WriteString("</tr>\n")
}
if idx == 255 {
break
}
}
sb.WriteString("</table></html>\n")

fmt.Println(sb.String())
}

0 comments on commit a6ce26d

Please sign in to comment.