mirror of
https://github.com/1f349/voidterm.git
synced 2024-11-09 22:52:55 +00:00
215 lines
4.0 KiB
Go
215 lines
4.0 KiB
Go
|
package termutil
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"image/color"
|
||
|
"strconv"
|
||
|
)
|
||
|
|
||
|
type Colour uint8
|
||
|
|
||
|
// See https://en.wikipedia.org/wiki/ANSI_escape_code#3-bit_and_4-bit
|
||
|
const (
|
||
|
ColourBlack Colour = iota
|
||
|
ColourRed
|
||
|
ColourGreen
|
||
|
ColourYellow
|
||
|
ColourBlue
|
||
|
ColourMagenta
|
||
|
ColourCyan
|
||
|
ColourWhite
|
||
|
ColourBrightBlack
|
||
|
ColourBrightRed
|
||
|
ColourBrightGreen
|
||
|
ColourBrightYellow
|
||
|
ColourBrightBlue
|
||
|
ColourBrightMagenta
|
||
|
ColourBrightCyan
|
||
|
ColourBrightWhite
|
||
|
ColourBackground
|
||
|
ColourForeground
|
||
|
ColourSelectionBackground
|
||
|
ColourSelectionForeground
|
||
|
ColourCursorForeground
|
||
|
ColourCursorBackground
|
||
|
)
|
||
|
|
||
|
type Theme struct {
|
||
|
colourMap map[Colour]color.Color
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
map4Bit = map[uint8]Colour{
|
||
|
30: ColourBlack,
|
||
|
31: ColourRed,
|
||
|
32: ColourGreen,
|
||
|
33: ColourYellow,
|
||
|
34: ColourBlue,
|
||
|
35: ColourMagenta,
|
||
|
36: ColourCyan,
|
||
|
37: ColourWhite,
|
||
|
90: ColourBrightBlack,
|
||
|
91: ColourBrightRed,
|
||
|
92: ColourBrightGreen,
|
||
|
93: ColourBrightYellow,
|
||
|
94: ColourBrightBlue,
|
||
|
95: ColourBrightMagenta,
|
||
|
96: ColourBrightCyan,
|
||
|
97: ColourBrightWhite,
|
||
|
40: ColourBlack,
|
||
|
41: ColourRed,
|
||
|
42: ColourGreen,
|
||
|
43: ColourYellow,
|
||
|
44: ColourBlue,
|
||
|
45: ColourMagenta,
|
||
|
46: ColourCyan,
|
||
|
47: ColourWhite,
|
||
|
100: ColourBrightBlack,
|
||
|
101: ColourBrightRed,
|
||
|
102: ColourBrightGreen,
|
||
|
103: ColourBrightYellow,
|
||
|
104: ColourBrightBlue,
|
||
|
105: ColourBrightMagenta,
|
||
|
106: ColourBrightCyan,
|
||
|
107: ColourBrightWhite,
|
||
|
}
|
||
|
)
|
||
|
|
||
|
func (t *Theme) ColourFrom4Bit(code uint8) color.Color {
|
||
|
colour, ok := map4Bit[code]
|
||
|
if !ok {
|
||
|
return color.Black
|
||
|
}
|
||
|
return t.colourMap[colour]
|
||
|
}
|
||
|
|
||
|
func (t *Theme) DefaultBackground() color.Color {
|
||
|
c, ok := t.colourMap[ColourBackground]
|
||
|
if !ok {
|
||
|
return color.RGBA{0, 0, 0, 0xff}
|
||
|
}
|
||
|
return c
|
||
|
}
|
||
|
|
||
|
func (t *Theme) DefaultForeground() color.Color {
|
||
|
c, ok := t.colourMap[ColourForeground]
|
||
|
if !ok {
|
||
|
return color.RGBA{255, 255, 255, 0xff}
|
||
|
}
|
||
|
return c
|
||
|
}
|
||
|
|
||
|
func (t *Theme) SelectionBackground() color.Color {
|
||
|
c, ok := t.colourMap[ColourSelectionBackground]
|
||
|
if !ok {
|
||
|
return color.RGBA{0, 0, 0, 0xff}
|
||
|
}
|
||
|
return c
|
||
|
}
|
||
|
|
||
|
func (t *Theme) SelectionForeground() color.Color {
|
||
|
c, ok := t.colourMap[ColourSelectionForeground]
|
||
|
if !ok {
|
||
|
return color.RGBA{255, 255, 255, 0xff}
|
||
|
}
|
||
|
return c
|
||
|
}
|
||
|
|
||
|
func (t *Theme) CursorBackground() color.Color {
|
||
|
c, ok := t.colourMap[ColourCursorBackground]
|
||
|
if !ok {
|
||
|
return color.RGBA{255, 255, 255, 0xff}
|
||
|
}
|
||
|
return c
|
||
|
}
|
||
|
|
||
|
func (t *Theme) CursorForeground() color.Color {
|
||
|
c, ok := t.colourMap[ColourCursorForeground]
|
||
|
if !ok {
|
||
|
return color.RGBA{0, 0, 0, 0xff}
|
||
|
}
|
||
|
return c
|
||
|
}
|
||
|
|
||
|
func (t *Theme) ColourFrom8Bit(n string) (color.Color, error) {
|
||
|
|
||
|
index, err := strconv.Atoi(n)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
if index < 16 {
|
||
|
return t.colourMap[Colour(index)], nil
|
||
|
}
|
||
|
|
||
|
if index >= 232 {
|
||
|
c := ((index - 232) * 0xff) / 0x18
|
||
|
return color.RGBA{
|
||
|
R: byte(c),
|
||
|
G: byte(c),
|
||
|
B: byte(c),
|
||
|
A: 0xff,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
var colour color.RGBA
|
||
|
colour.A = 0xff
|
||
|
indexR := ((index - 16) / 36)
|
||
|
if indexR > 0 {
|
||
|
colour.R = uint8(55 + indexR*40)
|
||
|
}
|
||
|
indexG := (((index - 16) % 36) / 6)
|
||
|
if indexG > 0 {
|
||
|
colour.G = uint8(55 + indexG*40)
|
||
|
}
|
||
|
indexB := ((index - 16) % 6)
|
||
|
if indexB > 0 {
|
||
|
colour.B = uint8(55 + indexB*40)
|
||
|
}
|
||
|
|
||
|
return colour, nil
|
||
|
}
|
||
|
|
||
|
func (t *Theme) ColourFrom24Bit(r, g, b string) (color.Color, error) {
|
||
|
ri, err := strconv.Atoi(r)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
gi, err := strconv.Atoi(g)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
bi, err := strconv.Atoi(b)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return color.RGBA{
|
||
|
R: byte(ri),
|
||
|
G: byte(gi),
|
||
|
B: byte(bi),
|
||
|
A: 0xff,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func (t *Theme) ColourFromAnsi(ansi []string, bg bool) (color.Color, error) {
|
||
|
|
||
|
if len(ansi) == 0 {
|
||
|
return nil, fmt.Errorf("invalid ansi colour code")
|
||
|
}
|
||
|
|
||
|
switch ansi[0] {
|
||
|
case "2":
|
||
|
if len(ansi) != 4 {
|
||
|
return nil, fmt.Errorf("invalid 24-bit ansi colour code")
|
||
|
}
|
||
|
return t.ColourFrom24Bit(ansi[1], ansi[2], ansi[3])
|
||
|
case "5":
|
||
|
if len(ansi) != 2 {
|
||
|
return nil, fmt.Errorf("invalid 8-bit ansi colour code")
|
||
|
}
|
||
|
return t.ColourFrom8Bit(ansi[1])
|
||
|
default:
|
||
|
return nil, fmt.Errorf("invalid ansi colour code")
|
||
|
}
|
||
|
}
|