pax_global_header00006660000000000000000000000064152023734700014515gustar00rootroot0000000000000052 comment=0fb7826462abc12f0955d7a7ed28f310e4116c35 golang-github-leaanthony-go-ansi-parser-1.6.1/000077500000000000000000000000001520237347000212365ustar00rootroot00000000000000golang-github-leaanthony-go-ansi-parser-1.6.1/LICENSE000066400000000000000000000020641520237347000222450ustar00rootroot00000000000000MIT License Copyright (c) 2021-Present Lea Anthony Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. golang-github-leaanthony-go-ansi-parser-1.6.1/README.md000066400000000000000000000056251520237347000225250ustar00rootroot00000000000000


A library for parsing ANSI encoded strings

CodeFactor

Go ANSI Parser converts strings with [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code) into a slice of structs that represent styled text. Features: * Can parse ANSI 16, 256 and TrueColor * Supports all styles: Regular, Bold, Faint, Italic, Blinking, Inversed, Invisible, Underlined, Strikethrough * Provides RGB, Hex, HSL, ANSI ID and Name for parsed colours * Truncation - works with emojis and grapheme clusters * Length - works with emojis and grapheme clusters * Cleanse - removes the ansi escape codes * Configurable colour map for customisation * 100% Test Coverage # Installation ```shell go get github.com/leaanthony/go-ansi-parser ``` ## Usage ### Parse ```go text, err := ansi.Parse("\u001b[1;31;40mHello World\033[0m") // is the equivalent of... text := []*ansi.StyledText{ { Label: "Hello World", FgCol: &ansi.Col{ Id: 9, Hex: "#ff0000", Rgb: &ansi.Rgb{ R: 255, G: 0, B: 0 }, Hsl: &ansi.Hsl{ H: 0, S: 100, L: 50 }, Name: "Red", }, BgCol: &ansi.Col{ Id: 0, Hex: "#000000", Rgb: &ansi.Rgb{0, 0, 0}, Hsl: &ansi.Hsl{0, 0, 0}, Name: "Black", }, Style: 1, }, } ``` ### Truncating ```go shorter, err := ansi.Truncate("\u001b[1;31;40mHello\033[0m \u001b[0;30mWorld!\033[0m", 8) // is the equivalent of... shorter := "\u001b[1;31;40mHello\033[0m \u001b[0;30mWo\033[0m" ``` ### Cleanse ```go cleaner, err := ansi.Cleanse("\u001b[1;31;40mHello\033[0m \u001b[0;30mWorld!\033[0m") // is the equivalent of... cleaner := "Hello World!" ``` ### Length ```go length, err := ansi.Length("\u001b[1;31;40mHello\033[0m \u001b[0;30mWorld!\033[0m") // is the equivalent of... length := 12 // Works with grapheme clusters and emoji length, err := ansi.Length("\u001b[1;31;40m👩🏽‍🔧😎\033[0m") // 2 ``` golang-github-leaanthony-go-ansi-parser-1.6.1/ansi.go000066400000000000000000000332721520237347000225260ustar00rootroot00000000000000package ansi import ( "fmt" "strconv" "strings" "github.com/rivo/uniseg" ) // TextStyle is a type representing the // ansi text styles type TextStyle int const ( // Bold Style Bold TextStyle = 1 << 0 // Faint Style Faint TextStyle = 1 << 1 // Italic Style Italic TextStyle = 1 << 2 // Blinking Style Blinking TextStyle = 1 << 3 // Inversed Style Inversed TextStyle = 1 << 4 // Invisible Style Invisible TextStyle = 1 << 5 // Underlined Style Underlined TextStyle = 1 << 6 // Strikethrough Style Strikethrough TextStyle = 1 << 7 // Bright Style Bright TextStyle = 1 << 8 ) type ColourMode int const ( Default ColourMode = 0 TwoFiveSix ColourMode = 1 TrueColour ColourMode = 2 ) var invalid = fmt.Errorf("invalid ansi string") var missingTerminator = fmt.Errorf("missing escape terminator 'm'") var invalidTrueColorSequence = fmt.Errorf("invalid TrueColor sequence") var invalid256ColSequence = fmt.Errorf("invalid 256 colour sequence") const ( // Default colors uses foreground color codes [30-37]. // See ColourMap and case for background colors. defaultForegroundColor = "37" defaultBackgroundColor = "30" ) // StyledText represents a single formatted string type StyledText struct { Label string FgCol *Col BgCol *Col Style TextStyle ColourMode ColourMode // Offset is the offset into the input string where the StyledText begins Offset int // Len is the length in bytes of the substring of the input text that // contains the styled text Len int } func (s *StyledText) styleToParams() []string { var params []string if s.Bold() { params = append(params, "1") } if s.Faint() { params = append(params, "2") } if s.Italic() { params = append(params, "3") } if s.Underlined() { params = append(params, "4") } if s.Blinking() { params = append(params, "5") } if s.Inversed() { params = append(params, "7") } if s.Invisible() { params = append(params, "8") } if s.Strikethrough() { params = append(params, "9") } if s.FgCol != nil { // Do we have an ID? switch s.ColourMode { case Default: offset := 30 id := s.FgCol.Id // Adjust when bold has been applied to the id if (s.Bold() || s.Bright()) && id > 7 && id < 16 { id -= 8 } if s.Bright() { offset = 90 } params = append(params, fmt.Sprintf("%d", id+offset)) case TwoFiveSix: params = append(params, []string{"38", "5", fmt.Sprintf("%d", s.FgCol.Id)}...) case TrueColour: r := fmt.Sprintf("%d", s.FgCol.Rgb.R) g := fmt.Sprintf("%d", s.FgCol.Rgb.G) b := fmt.Sprintf("%d", s.FgCol.Rgb.B) params = append(params, []string{"38", "2", r, g, b}...) } } if s.BgCol != nil { // Do we have an ID? switch s.ColourMode { case Default: id := s.BgCol.Id offset := 40 if s.Bright() { offset = 100 } // Adjust when bold has been applied to the id if (s.Bold() || s.Bright()) && id > 7 && id < 16 { id -= 8 } params = append(params, fmt.Sprintf("%d", id+offset)) case TwoFiveSix: params = append(params, []string{"48", "5", fmt.Sprintf("%d", s.BgCol.Id)}...) case TrueColour: r := fmt.Sprintf("%d", s.BgCol.Rgb.R) g := fmt.Sprintf("%d", s.BgCol.Rgb.G) b := fmt.Sprintf("%d", s.BgCol.Rgb.B) params = append(params, []string{"48", "2", r, g, b}...) } } return params } func (s *StyledText) String() string { params := strings.Join(s.styleToParams(), ";") return "\033[0;" + params + "m" + s.Label + "\033[0m" } // Bold will return true if the text has a Bold style func (s *StyledText) Bold() bool { return s.Style&Bold == Bold } // Faint will return true if the text has a Faint style func (s *StyledText) Faint() bool { return s.Style&Faint == Faint } // Italic will return true if the text has an Italic style func (s *StyledText) Italic() bool { return s.Style&Italic == Italic } // Blinking will return true if the text has a Blinking style func (s *StyledText) Blinking() bool { return s.Style&Blinking == Blinking } // Inversed will return true if the text has an Inversed style func (s *StyledText) Inversed() bool { return s.Style&Inversed == Inversed } // Invisible will return true if the text has an Invisible style func (s *StyledText) Invisible() bool { return s.Style&Invisible == Invisible } // Underlined will return true if the text has an Underlined style func (s *StyledText) Underlined() bool { return s.Style&Underlined == Underlined } // Strikethrough will return true if the text has a Strikethrough style func (s *StyledText) Strikethrough() bool { return s.Style&Strikethrough == Strikethrough } // Bright will return true if the text has a Bright style func (s *StyledText) Bright() bool { return s.Style&Bright == Bright } // ColourMap maps ansi identifiers to a colour var ColourMap = map[string]map[string]*Col{ "Regular": { "30": Cols[0], "31": Cols[1], "32": Cols[2], "33": Cols[3], "34": Cols[4], "35": Cols[5], "36": Cols[6], "37": Cols[7], "90": Cols[8], "91": Cols[9], "92": Cols[10], "93": Cols[11], "94": Cols[12], "95": Cols[13], "96": Cols[14], "97": Cols[15], "100": Cols[8], "101": Cols[9], "102": Cols[10], "103": Cols[11], "104": Cols[12], "105": Cols[13], "106": Cols[14], "107": Cols[15], }, "Bold": { "30": Cols[8], "31": Cols[9], "32": Cols[10], "33": Cols[11], "34": Cols[12], "35": Cols[13], "36": Cols[14], "37": Cols[15], "90": Cols[8], "91": Cols[9], "92": Cols[10], "93": Cols[11], "94": Cols[12], "95": Cols[13], "96": Cols[14], "97": Cols[15], "100": Cols[8], "101": Cols[9], "102": Cols[10], "103": Cols[11], "104": Cols[12], "105": Cols[13], "106": Cols[14], "107": Cols[15], }, "Faint": { "30": Cols[0], "31": Cols[1], "32": Cols[2], "33": Cols[3], "34": Cols[4], "35": Cols[5], "36": Cols[6], "37": Cols[7], }, } // Parse will convert an ansi encoded string and return // a slice of StyledText structs that represent the text. // If parsing is unsuccessful, an error is returned. func Parse(input string, options ...ParseOption) ([]*StyledText, error) { var result []*StyledText index := 0 offset := 0 escapeCodeLen := 0 var currentStyledText = &StyledText{} if len(input) == 0 { return []*StyledText{currentStyledText}, nil } for { // Read all chars to next escape code esc := strings.Index(input, "\033[") // If no more esc chars, save what's left and return if esc == -1 { text := input[index:] if len(text) > 0 { currentStyledText.Label = text currentStyledText.Offset = offset currentStyledText.Len = len(text) + escapeCodeLen result = append(result, currentStyledText) } return result, nil } label := input[:esc] if len(label) > 0 { currentStyledText.Label = label currentStyledText.Offset = offset currentStyledText.Len = len(label) + escapeCodeLen offset += currentStyledText.Len result = append(result, currentStyledText) currentStyledText = &StyledText{ Label: "", FgCol: currentStyledText.FgCol, BgCol: currentStyledText.BgCol, Style: currentStyledText.Style, } escapeCodeLen = 0 } input = input[esc:] // skip input = input[2:] // Read in params endesc := strings.Index(input, "m") if endesc == -1 { return nil, missingTerminator } paramText := input[:endesc] input = input[endesc+1:] escapeCodeLen += 2 + endesc + 1 params := strings.Split(paramText, ";") colourMap := ColourMap["Regular"] skip := 0 for index, param := range params { if skip > 0 { skip-- continue } param = stripLeadingZeros(param) switch param { case "0", "": colourMap = ColourMap["Regular"] currentStyledText.Style = 0 currentStyledText.FgCol = nil currentStyledText.BgCol = nil case "1": // Bold colourMap = ColourMap["Bold"] currentStyledText.Style |= Bold case "2": // Dim/Feint colourMap = ColourMap["Faint"] currentStyledText.Style |= Faint case "3": // Italic currentStyledText.Style |= Italic case "4": // Underlined currentStyledText.Style |= Underlined case "5": // Blinking currentStyledText.Style |= Blinking case "7": // Inversed currentStyledText.Style |= Inversed case "8": // Invisible currentStyledText.Style |= Invisible case "9": // Strikethrough currentStyledText.Style |= Strikethrough case "30", "31", "32", "33", "34", "35", "36", "37": currentStyledText.FgCol = colourMap[param] case "90", "91", "92", "93", "94", "95", "96", "97": currentStyledText.FgCol = colourMap[param] currentStyledText.Style |= Bright case "100", "101", "102", "103", "104", "105", "106", "107": currentStyledText.BgCol = colourMap[param] currentStyledText.Style |= Bright case "40", "41", "42", "43", "44", "45", "46", "47": bgcol := "3" + param[1:] // Equivalent of -10 currentStyledText.BgCol = colourMap[bgcol] case "38", "48": if len(params)-index < 3 { return nil, invalid } // 256 colours param1 := stripLeadingZeros(params[index+1]) if param1 == "5" { skip = 2 colIndexText := stripLeadingZeros(params[index+2]) colIndex, err := strconv.Atoi(colIndexText) if err != nil { return nil, invalid256ColSequence } if colIndex < 0 || colIndex > 255 { return nil, invalid256ColSequence } currentStyledText.ColourMode = TwoFiveSix if param == "38" { currentStyledText.FgCol = Cols[colIndex] continue } currentStyledText.BgCol = Cols[colIndex] continue } // we must have 4 params left if len(params)-index < 5 { return nil, invalidTrueColorSequence } if param1 != "2" { return nil, invalidTrueColorSequence } var r, g, b uint8 ri, err := strconv.Atoi(params[index+2]) if err != nil { return nil, invalidTrueColorSequence } gi, err := strconv.Atoi(params[index+3]) if err != nil { return nil, invalidTrueColorSequence } bi, err := strconv.Atoi(params[index+4]) if err != nil { return nil, invalidTrueColorSequence } if bi > 255 || gi > 255 || ri > 255 { return nil, invalidTrueColorSequence } if bi < 0 || gi < 0 || ri < 0 { return nil, invalidTrueColorSequence } r = uint8(ri) g = uint8(gi) b = uint8(bi) skip = 4 colvalue := fmt.Sprintf("#%02x%02x%02x", r, g, b) currentStyledText.ColourMode = TrueColour if param == "38" { currentStyledText.FgCol = &Col{Id: 256, Hex: colvalue, Rgb: Rgb{r, g, b}} continue } currentStyledText.BgCol = &Col{Id: 256, Hex: colvalue, Rgb: Rgb{r, g, b}} case "39": // Lookup for default foreground color. foregroundColor := colourMap[defaultForegroundColor] for _, option := range options { if option.ansiForegroundColor != "" { foregroundColor = colourMap[option.ansiForegroundColor] break } } // Set selected foreground color. currentStyledText.FgCol = foregroundColor case "49": // Lookup for default background color. backgroundColor := colourMap[defaultBackgroundColor] for _, option := range options { if option.ansiBackgroundColor != "" { backgroundColor = colourMap[option.ansiBackgroundColor] break } } // Set selected background color. currentStyledText.BgCol = backgroundColor default: // Unexpected codes may be ignored. unexpectedCodeIgnored := false for _, option := range options { if option.ignoreUnexpectedCode { unexpectedCodeIgnored = true break } } if !unexpectedCodeIgnored { return nil, invalid } } } } } func stripLeadingZeros(s string) string { if len(s) < 2 { return s } return strings.TrimLeft(s, "0") } // HasEscapeCodes tests that input has escape codes. func HasEscapeCodes(input string) bool { return strings.IndexAny(input, "\033[") != -1 } // String builds an ANSI string for specified StyledText slice. func String(input []*StyledText) string { var result strings.Builder for _, text := range input { params := text.styleToParams() if len(params) == 0 { result.WriteString(text.Label) continue } result.WriteString(text.String()) } return result.String() } // Truncate truncates text to length but preserves control symbols in ANSI string. func Truncate(input string, maxChars int, options ...ParseOption) (string, error) { parsed, err := Parse(input, options...) if err != nil { return "", err } charsLeft := maxChars var result []*StyledText for _, element := range parsed { userPerceivedChars := uniseg.GraphemeClusterCount(element.Label) if userPerceivedChars >= charsLeft { var newLabel []rune graphemes := uniseg.NewGraphemes(element.Label) for graphemes.Next() { newLabel = append(newLabel, graphemes.Runes()...) charsLeft-- if charsLeft == 0 { element.Label = string(newLabel) result = append(result, element) return String(result), nil } } } result = append(result, element) charsLeft -= userPerceivedChars } return String(result), nil } // Cleanse removes ANSI control symbols from the string. func Cleanse(input string, options ...ParseOption) (string, error) { if input == "" { return "", nil } parsed, err := Parse(input, options...) if err != nil { return "", err } var result strings.Builder for _, element := range parsed { result.WriteString(element.Label) } return result.String(), nil } // Length calculates count of user-perceived characters in ANSI string. func Length(input string, options ...ParseOption) (int, error) { if input == "" { return 0, nil } parsed, err := Parse(input, options...) if err != nil { return -1, err } var result int for _, element := range parsed { userPerceivedChars := uniseg.GraphemeClusterCount(element.Label) result += userPerceivedChars } return result, nil } golang-github-leaanthony-go-ansi-parser-1.6.1/ansi_test.go000066400000000000000000000713531520237347000235670ustar00rootroot00000000000000package ansi import ( "testing" is "github.com/matryer/is" ) func TestParseAnsi16Styles(t *testing.T) { is2 := is.New(t) var got []*StyledText var err error // Bold got, err = Parse("\u001b[1;30mHello World\033[0m") is2.NoErr(err) is2.Equal(len(got), 1) is2.True(got[0].Bold()) is2.Equal(got[0].Len, 18) is2.Equal(got[0].Offset, 0) // Faint got, err = Parse("\u001b[2;30mHello World\033[0m") is2.NoErr(err) is2.Equal(len(got), 1) is2.True(got[0].Faint()) // Italic got, err = Parse("\u001b[3;30mHello World\033[0m") is2.NoErr(err) is2.Equal(len(got), 1) is2.True(got[0].Italic()) // Underlined got, err = Parse("\u001b[4;30mHello World\033[0m") is2.NoErr(err) is2.Equal(len(got), 1) is2.True(got[0].Underlined()) // Blinking got, err = Parse("\u001b[5;30mHello World\033[0m") is2.NoErr(err) is2.Equal(len(got), 1) is2.True(got[0].Blinking()) // Inversed got, err = Parse("\u001b[7;30mHello World\033[0m") is2.NoErr(err) is2.Equal(len(got), 1) is2.True(got[0].Inversed()) // Invisible got, err = Parse("\u001b[8;30mHello World\033[0m") is2.NoErr(err) is2.Equal(len(got), 1) is2.True(got[0].Invisible()) // Strikethrough got, err = Parse("\u001b[9;30mHello World\033[0m") is2.NoErr(err) is2.Equal(len(got), 1) is2.True(got[0].Strikethrough()) } func TestParseAnsi16Swap(t *testing.T) { is2 := is.New(t) var got []*StyledText var err error // Swap single c0ffee := &Col{ Id: 0, Hex: "c0ffee", Name: "Coffee", } original := ColourMap["Regular"]["30"] ColourMap["Regular"]["30"] = c0ffee got, err = Parse("\u001b[0;30mHello World\033[0m") is2.NoErr(err) is2.Equal(len(got), 1) is2.Equal(got[0].FgCol.Name, "Coffee") // Restore ColourMap["Regular"]["30"] = original got, err = Parse("\u001b[0;30mHello World\033[0m") is2.NoErr(err) is2.Equal(len(got), 1) is2.Equal(got[0].FgCol.Name, "Black") } func TestParseAnsi16SingleColour(t *testing.T) { is2 := is.New(t) tests := []struct { name string input string wantText string wantColor string wantErr bool }{ {"No formatting", "Hello World", "Hello World", "", false}, {"Black", "\u001b[0;30mHello World\033[0m", "Hello World", "Black", false}, {"Red", "\u001b[0;31mHello World\033[0m", "Hello World", "Maroon", false}, {"Green", "\u001b[0;32mGreen\033[0m", "Green", "Green", false}, {"Yellow", "\u001b[0;33m😀\033[0m", "😀", "Olive", false}, {"Blue", "\u001b[0;34m123\033[0m", "123", "Navy", false}, {"Purple", "\u001b[0;35m👩🏽‍🔧\u001B[0m", "👩🏽‍🔧", "Purple", false}, {"Cyan", "\033[0;36m😀\033[0m", "😀", "Teal", false}, {"White", "\u001b[0;37m[0;37m\033[0m", "[0;37m", "Silver", false}, {"Black Bold", "\u001b[1;30mHello World\033[0m", "Hello World", "Grey", false}, {"Red Bold", "\u001b[1;31mHello World\033[0m", "Hello World", "Red", false}, {"Green Bold", "\u001b[1;32mGreen\033[0m", "Green", "Lime", false}, {"Yellow Bold", "\u001b[1;33m😀\033[0m", "😀", "Yellow", false}, {"Blue Bold", "\u001b[1;34m123\033[0m", "123", "Blue", false}, {"Purple Bold", "\u001b[1;35m👩🏽‍🔧\u001B[0m", "👩🏽‍🔧", "Fuchsia", false}, {"Cyan Bold", "\033[1;36m😀\033[0m", "😀", "Aqua", false}, {"White Bold", "\u001b[1;37m[0;37m\033[0m", "[0;37m", "White", false}, {"Black Bold & Bright", "\u001b[1;90mHello World\033[0m", "Hello World", "Grey", false}, {"Red Bold & Bright", "\u001b[1;91mHello World\033[0m", "Hello World", "Red", false}, {"Green Bold & Bright", "\u001b[1;92mGreen\033[0m", "Green", "Lime", false}, {"Yellow Bold & Bright", "\u001b[1;93m😀\033[0m", "😀", "Yellow", false}, {"Blue Bold & Bright", "\u001b[1;94m123\033[0m", "123", "Blue", false}, {"Purple Bold & Bright", "\u001b[1;95m👩🏽‍🔧\u001B[0m", "👩🏽‍🔧", "Fuchsia", false}, {"Cyan Bold & Bright", "\033[1;96m😀\033[0m", "😀", "Aqua", false}, {"White Bold & Bright", "\u001b[1;97m[0;37m\033[0m", "[0;37m", "White", false}, {"Black Bright", "\u001b[90mHello World\033[0m", "Hello World", "Grey", false}, {"Red Bright", "\u001b[91mHello World\033[0m", "Hello World", "Red", false}, {"Green Bright", "\u001b[92mGreen\033[0m", "Green", "Lime", false}, {"Yellow Bright", "\u001b[93m😀\033[0m", "😀", "Yellow", false}, {"Blue Bright", "\u001b[94m123\033[0m", "123", "Blue", false}, {"Purple Bright", "\u001b[95m👩🏽‍🔧\u001B[0m", "👩🏽‍🔧", "Fuchsia", false}, {"Cyan Bright", "\033[96m😀\033[0m", "😀", "Aqua", false}, {"White Bright", "\u001b[97m[0;37m\033[0m", "[0;37m", "White", false}, {"Black Bold & Bright Background", "\u001b[1;100mHello World\033[0m", "Hello World", "Grey", false}, {"Red Bold & Bright Background", "\u001b[1;101mHello World\033[0m", "Hello World", "Red", false}, {"Green Bold & Bright Background", "\u001b[1;102mGreen\033[0m", "Green", "Lime", false}, {"Yellow Bold & Bright Background", "\u001b[1;103m😀\033[0m", "😀", "Yellow", false}, {"Blue Bold & Bright Background", "\u001b[1;104m123\033[0m", "123", "Blue", false}, {"Purple Bold & Bright Background", "\u001b[1;105m👩🏽‍🔧\u001B[0m", "👩🏽‍🔧", "Fuchsia", false}, {"Cyan Bold & Bright Background", "\033[1;106m😀\033[0m", "😀", "Aqua", false}, {"White Bold & Bright Background", "\u001b[1;107m[0;37m\033[0m", "[0;37m", "White", false}, {"Black Bright Background", "\u001b[100mHello World\033[0m", "Hello World", "Grey", false}, {"Red Bright Background", "\u001b[101mHello World\033[0m", "Hello World", "Red", false}, {"Green Bright Background", "\u001b[102mGreen\033[0m", "Green", "Lime", false}, {"Yellow Bright Background", "\u001b[103m😀\033[0m", "😀", "Yellow", false}, {"Blue Bright Background", "\u001b[104m123\033[0m", "123", "Blue", false}, {"Purple Bright Background", "\u001b[105m👩🏽‍🔧\u001B[0m", "👩🏽‍🔧", "Fuchsia", false}, {"Cyan Bright Background", "\033[106m😀\033[0m", "😀", "Aqua", false}, {"White Bright Background", "\u001b[107m[0;37m\033[0m", "[0;37m", "White", false}, {"Blank", "", "", "", false}, {"Emoji", "😀👩🏽‍🔧", "😀👩🏽‍🔧", "", false}, {"Spaces", " ", " ", "", false}, {"Bad code", "\u001b[1 ", "", "", true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := Parse(tt.input) is2.Equal(err != nil, tt.wantErr) expectedLength := 1 if tt.wantErr { expectedLength = 0 } is2.Equal(len(got), expectedLength) if expectedLength == 1 { if len(tt.wantColor) > 0 { if got[0].FgCol != nil { is2.Equal(got[0].FgCol.Name, tt.wantColor) } else { is2.Equal(got[0].BgCol.Name, tt.wantColor) } } } }) } } func TestParseAnsi16SingleBGColour(t *testing.T) { is2 := is.New(t) tests := []struct { name string input string wantText string wantColor string wantErr bool }{ {"No formatting", "Hello World", "Hello World", "", false}, {"Black", "\u001b[0;40mHello World\033[0m", "Hello World", "Black", false}, {"Red", "\u001b[0;41mHello World\033[0m", "Hello World", "Maroon", false}, {"Green", "\u001b[0;42mGreen\033[0m", "Green", "Green", false}, {"Yellow", "\u001b[0;43m😀\033[0m", "😀", "Olive", false}, {"Blue", "\u001b[0;44m123\033[0m", "123", "Navy", false}, {"Purple", "\u001b[0;45m👩🏽‍🔧\u001B[0m", "👩🏽‍🔧", "Purple", false}, {"Cyan", "\033[0;46m😀\033[0m", "😀", "Teal", false}, {"White", "\u001b[0;47m[0;47m\033[0m", "[0;47m", "Silver", false}, {"Black Bold", "\u001b[1;40mHello World\033[0m", "Hello World", "Grey", false}, {"Red Bold", "\u001b[1;41mHello World\033[0m", "Hello World", "Red", false}, {"Green Bold", "\u001b[1;42mGreen\033[0m", "Green", "Lime", false}, {"Yellow Bold", "\u001b[1;43m😀\033[0m", "😀", "Yellow", false}, {"Blue Bold", "\u001b[1;44m123\033[0m", "123", "Blue", false}, {"Purple Bold", "\u001b[1;45m👩🏽‍🔧\u001B[0m", "👩🏽‍🔧", "Fuchsia", false}, {"Cyan Bold", "\033[1;46m😀\033[0m", "😀", "Aqua", false}, {"White Bold", "\u001b[1;47m[0;47m\033[0m", "[0;47m", "White", false}, {"Pre text", "Hello\u001b[0m", "Hello", "", false}, {"Blank", "", "", "", false}, {"Emoji", "😀👩🏽‍🔧", "😀👩🏽‍🔧", "", false}, {"Spaces", " ", " ", "", false}, {"Bad code", "\u001b[1 ", "", "", true}, {"No colour", "\033[m\033[40m \033[0m", " ", "", false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := Parse(tt.input) is2.Equal(err != nil, tt.wantErr) expectedLength := 1 if tt.wantErr { expectedLength = 0 } is2.Equal(len(got), expectedLength) if expectedLength == 1 { if len(tt.wantColor) > 0 { is2.True(got[0].BgCol != nil) is2.Equal(got[0].BgCol.Name, tt.wantColor) } } }) } } func TestParseAnsi16MultiColour(t *testing.T) { is2 := is.New(t) tests := []struct { name string input string want []*StyledText wantErr bool }{ {"Black & Red", "\u001B[0;30mHello World\u001B[0m\u001B[0;31mHello World\u001B[0m", []*StyledText{ {Label: "Hello World", FgCol: &Col{Name: "Black"}, Offset: 0, Len: 18}, {Label: "Hello World", FgCol: &Col{Name: "Maroon"}, Offset: 18, Len: 22}, }, false}, {"Text then Black & Red", "This is great!\u001B[0;30mHello World\u001B[0m\u001B[0;31mHello World\u001B[0m", []*StyledText{ {Label: "This is great!", Offset: 0, Len: 14}, {Label: "Hello World", FgCol: &Col{Name: "Black"}, Offset: 14, Len: 18}, {Label: "Hello World", FgCol: &Col{Name: "Maroon"}, Offset: 32, Len: 22}, }, false}, {"Text Reset then Black & Red", "This is great!\u001B[0m\u001B[0;30mHello World\u001B[0m\u001B[0;31mHello World\u001B[0m", []*StyledText{ {Label: "This is great!", Offset: 0, Len: 14}, {Label: "Hello World", FgCol: &Col{Name: "Black"}, Offset: 14, Len: 22}, {Label: "Hello World", FgCol: &Col{Name: "Maroon"}, Offset: 36, Len: 22}, }, false}, {"Text Reset then Black & Red", "This is great!\u001B[0m", []*StyledText{ {Label: "This is great!", Offset: 0, Len: 14}, }, false}, {"Black & Red no reset", "\u001B[0;30mHello World\u001B[0;31mHello World", []*StyledText{ {Label: "Hello World", FgCol: &Col{Name: "Black"}, Offset: 0, Len: 18}, {Label: "Hello World", FgCol: &Col{Name: "Maroon"}, Offset: 18, Len: 18}, }, false}, {"Black,space,Red", "\u001B[0;30mHello World\u001B[0m \u001B[0;31mHello World\u001B[0m", []*StyledText{ {Label: "Hello World", FgCol: &Col{Name: "Black"}, Offset: 0, Len: 18}, {Label: " ", Offset: 18, Len: 5}, {Label: "Hello World", FgCol: &Col{Name: "Maroon"}, Offset: 23, Len: 18}, }, false}, {"Black,Red,Blue,Green underlined", "\033[4;30mBlack\u001B[0m\u001B[4;31mRed\u001B[0m\u001B[4;34mBlue\u001B[0m\u001B[4;32mGreen\u001B[0m", []*StyledText{ {Label: "Black", FgCol: &Col{Name: "Black"}, Style: Underlined, Offset: 0, Len: 12}, {Label: "Red", FgCol: &Col{Name: "Maroon"}, Style: Underlined, Offset: 12, Len: 14}, {Label: "Blue", FgCol: &Col{Name: "Navy"}, Style: Underlined, Offset: 26, Len: 15}, {Label: "Green", FgCol: &Col{Name: "Green"}, Style: Underlined, Offset: 41, Len: 16}, }, false}, {"Black,Red,Blue,Green bold", "\033[1;30mBlack\u001B[0m\u001B[1;31mRed\u001B[0m\u001B[1;34mBlue\u001B[0m\u001B[1;32mGreen\u001B[0m", []*StyledText{ {Label: "Black", FgCol: &Col{Name: "Grey"}, Style: Bold, Offset: 0, Len: 12}, {Label: "Red", FgCol: &Col{Name: "Red"}, Style: Bold, Offset: 12, Len: 14}, {Label: "Blue", FgCol: &Col{Name: "Blue"}, Style: Bold, Offset: 26, Len: 15}, {Label: "Green", FgCol: &Col{Name: "Lime"}, Style: Bold, Offset: 41, Len: 16}, }, false}, {"Green Feint & Yellow Italic", "\u001B[2;32m👩🏽‍🔧\u001B[0m\u001B[0;3;33m👩🏽‍🔧\u001B[0m", []*StyledText{ {Label: "👩🏽‍🔧", FgCol: &Col{Name: "Green"}, Style: Faint, Offset: 0, Len: len("👩🏽‍🔧") + 7}, {Label: "👩🏽‍🔧", FgCol: &Col{Name: "Olive"}, Style: Italic, Offset: len("👩🏽‍🔧") + 7, Len: len("👩🏽‍🔧") + 13}, }, false}, {"Green Blinking & Yellow Inversed", "\u001B[5;32m👩🏽‍🔧\u001B[0m\u001B[0;7;33m👩🏽‍🔧\u001B[0m", []*StyledText{ {Label: "👩🏽‍🔧", FgCol: &Col{Name: "Green"}, Style: Blinking, Offset: 0, Len: len("👩🏽‍🔧") + 7}, {Label: "👩🏽‍🔧", FgCol: &Col{Name: "Olive"}, Style: Inversed, Offset: len("👩🏽‍🔧") + 7, Len: len("👩🏽‍🔧") + 13}, }, false}, {"Green Invisible & Yellow Invisible & Strikethrough", "\u001B[8;32m👩🏽‍🔧\u001B[9;33m👩🏽‍🔧\u001B[0m", []*StyledText{ {Label: "👩🏽‍🔧", FgCol: &Col{Name: "Green"}, Style: Invisible, Offset: 0, Len: len("👩🏽‍🔧") + 7}, {Label: "👩🏽‍🔧", FgCol: &Col{Name: "Olive"}, Style: Invisible | Strikethrough, Offset: len("👩🏽‍🔧") + 7, Len: len("👩🏽‍🔧") + 7}, }, false}, {"Red Foregraound & Black Background", "\u001b[1;31;40mHello World\033[0m", []*StyledText{ {Label: "Hello World", FgCol: &Col{Name: "Red"}, BgCol: &Col{Name: "Black"}, Style: Bold, Offset: 0, Len: 21}, }, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := Parse(tt.input) is2.Equal(err != nil, tt.wantErr) for index, w := range tt.want { is2.Equal(got[index].Label, w.Label) if w.FgCol != nil { is2.Equal(got[index].FgCol.Name, w.FgCol.Name) } is2.Equal(got[index].Style, w.Style) is2.Equal(got[index].Offset, w.Offset) is2.Equal(got[index].Len, w.Len) } }) } } func TestParseAnsi256(t *testing.T) { is2 := is.New(t) tests := []struct { name string input string want []*StyledText wantErr bool }{ {"Grey93 & DarkViolet", "\u001B[38;5;255mGrey93\u001B[0m\u001B[38;5;128mDarkViolet\u001B[0m", []*StyledText{ {Label: "Grey93", FgCol: &Col{Name: "Grey93"}}, {Label: "DarkViolet", FgCol: &Col{Name: "DarkViolet"}}, }, false}, {"Grey93 Bold & DarkViolet Italic", "\u001B[0;1;38;5;255mGrey93\u001B[0m\u001B[0;3;38;5;128mDarkViolet\u001B[0m", []*StyledText{ {Label: "Grey93", FgCol: &Col{Name: "Grey93"}, Style: Bold}, {Label: "DarkViolet", FgCol: &Col{Name: "DarkViolet"}, Style: Italic}, }, false}, {"Grey93 Bold & DarkViolet Italic", "\u001B[0;1;38;5;256mGrey93\u001B[0m", nil, true}, {"Grey93 Bold & DarkViolet Italic", "\u001B[0;1;38;5;-1mGrey93\u001B[0m", nil, true}, {"Bad No of Params", "\u001B[0;1;38;5mGrey93\u001B[0m", nil, true}, {"Bad Params", "\u001B[0;1;38;fivemGrey93\u001B[0m", nil, true}, {"Bad Params 2", "\u001B[0;1;38;3mGrey93\u001B[0m", nil, true}, {"Bad Params 3", "\u001B[0;1;38;5;fivemGrey93\u001B[0m", nil, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := Parse(tt.input) is2.Equal(err != nil, tt.wantErr) for index, w := range tt.want { is2.Equal(got[index].Label, w.Label) if w.FgCol != nil { is2.Equal(got[index].FgCol.Name, w.FgCol.Name) } is2.Equal(got[index].Style, w.Style) } }) } } func TestRoundtripAnsi16(t *testing.T) { is2 := is.New(t) tests := []struct { name string input string }{ {"No formatting", "Hello World"}, {"Black", "\u001b[0;30mHello World\033[0m"}, {"Red", "\u001b[0;31mHello World\033[0m"}, {"Green", "\u001b[0;32mGreen\033[0m"}, {"Yellow", "\u001b[0;33m😀\033[0m"}, {"Blue", "\u001b[0;34m123\033[0m"}, {"Purple", "\u001b[0;35m👩🏽‍🔧\u001B[0m"}, {"Cyan", "\033[0;36m😀\033[0m"}, {"White", "\u001b[0;37m[0;37m\033[0m"}, {"Black Bold", "\u001b[0;1;30mHello World\033[0m"}, {"Red Bold", "\u001b[0;1;31mHello World\033[0m"}, {"Green Bold", "\u001b[0;1;32mGreen\033[0m"}, {"Yellow Bold", "\u001b[0;1;33m😀\033[0m"}, {"Blue Bold", "\u001b[0;1;34m123\033[0m"}, {"Purple Bold", "\u001b[0;1;35m👩🏽‍🔧\u001B[0m"}, {"Cyan Bold", "\033[0;1;36m😀\033[0m"}, {"White Bold", "\u001b[0;1;37m[0;37m\033[0m"}, {"Black Bright", "\u001b[0;90mHello World\033[0m"}, {"Red Bright", "\u001b[0;91mHello World\033[0m"}, {"Green Bright", "\u001b[0;92mGreen\033[0m"}, {"Yellow Bright", "\u001b[0;93m😀\033[0m"}, {"Blue Bright", "\u001b[0;94m123\033[0m"}, {"Purple Bright", "\u001b[0;95m👩🏽‍🔧\u001B[0m"}, {"Cyan Bright", "\033[0;96m😀\033[0m"}, {"White Bright", "\u001b[0;97m[0;37m\033[0m"}, {"Black Bright Background", "\u001b[0;100mHello World\033[0m"}, {"Red Bright Background", "\u001b[0;101mHello World\033[0m"}, {"Green Bright Background", "\u001b[0;102mGreen\033[0m"}, {"Yellow Bright Background", "\u001b[0;103m😀\033[0m"}, {"Blue Bright Background", "\u001b[0;104m123\033[0m"}, {"Purple Bright Background", "\u001b[0;105m👩🏽‍🔧\u001B[0m"}, {"Cyan Bright Background", "\033[0;106m😀\033[0m"}, {"White Bright Background", "\u001b[0;107m[0;37m\033[0m"}, {"Blank", ""}, {"Emoji", "😀👩🏽‍🔧"}, {"Spaces", " "}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := Parse(tt.input) is2.NoErr(err) output := String(got) is2.Equal(output, tt.input) }) } } func TestRoundtripAnsi256(t *testing.T) { is2 := is.New(t) tests := []struct { name string input string }{ {"Grey93 & DarkViolet", "\u001B[0;38;5;255mGrey93\u001B[0m\u001B[0;38;5;128mDarkViolet\u001B[0m"}, {"Grey93 Bold & DarkViolet Italic", "\u001B[0;1;38;5;255mGrey93\u001B[0m\u001B[0;3;38;5;128mDarkViolet\u001B[0m"}, {"White", "\u001B[0;38;5;15mWhite\u001B[0m\u001B[0;3;38;5;128mDarkViolet\u001B[0m"}, {"White Bold", "\u001B[0;1;38;5;15mWhite\u001B[0m\u001B[0;3;38;5;128mDarkViolet\u001B[0m"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := Parse(tt.input) is2.NoErr(err) output := String(got) is2.Equal(output, tt.input) }) } } func TestParseAnsiBG256(t *testing.T) { is2 := is.New(t) tests := []struct { name string input string want []*StyledText wantErr bool }{ {"Grey93 & DarkViolet", "\u001B[48;5;255mGrey93\u001B[0m\u001B[48;5;128mDarkViolet\u001B[0m", []*StyledText{ {Label: "Grey93", BgCol: &Col{Name: "Grey93"}}, {Label: "DarkViolet", BgCol: &Col{Name: "DarkViolet"}}, }, false}, {"Grey93 Bold & DarkViolet Italic", "\u001B[0;1;48;5;255mGrey93\u001B[0m\u001B[0;3;48;5;128mDarkViolet\u001B[0m", []*StyledText{ {Label: "Grey93", BgCol: &Col{Name: "Grey93"}, Style: Bold}, {Label: "DarkViolet", BgCol: &Col{Name: "DarkViolet"}, Style: Italic}, }, false}, {"Grey93 Bold & DarkViolet Italic", "\u001B[0;1;48;5;256mGrey93\u001B[0m", nil, true}, {"Grey93 Bold & DarkViolet Italic", "\u001B[0;1;48;5;-1mGrey93\u001B[0m", nil, true}, {"Bad No of Params", "\u001B[0;1;48;5mGrey93\u001B[0m", nil, true}, {"Bad Params", "\u001B[0;1;48;fivemGrey93\u001B[0m", nil, true}, {"Bad Params 2", "\u001B[0;1;48;3mGrey93\u001B[0m", nil, true}, {"Bad Params 2", "\u001B[0;1;50;3mGrey93\u001B[0m", nil, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := Parse(tt.input) is2.Equal(err != nil, tt.wantErr) for index, w := range tt.want { is2.Equal(got[index].Label, w.Label) if w.FgCol != nil { is2.Equal(got[index].BgCol.Name, w.BgCol.Name) } is2.Equal(got[index].Style, w.Style) } }) } } func TestParseAnsiTrueColor(t *testing.T) { is2 := is.New(t) tests := []struct { name string input string want []*StyledText wantErr bool }{ {"Red", "\u001B[38;2;255;0;0mRed\u001B[0m", []*StyledText{ {Label: "Red", FgCol: &Col{Rgb: Rgb{255, 0, 0}, Hex: "#ff0000"}}, }, false}, {"Red BG", "\u001B[48;2;255;0;0mRed\u001B[0m", []*StyledText{ {Label: "Red", BgCol: &Col{Rgb: Rgb{255, 0, 0}, Hex: "#ff0000"}}, }, false}, {"Red, text, Green", "\u001B[38;2;255;0;0mRed\u001B[0mI am plain text\u001B[38;2;0;255;0mGreen\u001B[0m", []*StyledText{ {Label: "Red", FgCol: &Col{Rgb: Rgb{255, 0, 0}, Hex: "#ff0000"}}, {Label: "I am plain text"}, {Label: "Green", FgCol: &Col{Rgb: Rgb{0, 255, 0}, Hex: "#00ff00"}}, }, false}, {"Bad 1", "\u001B[38;2;256;0;0mRed\u001B[0m", nil, true}, {"Bad 2", "\u001B[38;2;-1;0;0mRed\u001B[0m", nil, true}, {"Bad no of params", "\u001B[38;2;0;0mRed\u001B[0m", nil, true}, {"Bad params", "\u001B[38;2;0;onemRed\u001B[0m", nil, true}, {"Bad params 2", "\u001B[38;2;red;0;0mRed\u001B[0m", nil, true}, {"Bad params 3", "\u001B[38;2;0;red;0mRed\u001B[0m", nil, true}, {"Bad params 4", "\u001B[38;2;0;0;redmRed\u001B[0m", nil, true}, {"Bad params 4", "\u001B[38;3;0;0;redmRed\u001B[0m", nil, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := Parse(tt.input) is2.Equal(err != nil, tt.wantErr) for index, w := range tt.want { is2.Equal(got[index].Label, w.Label) if w.FgCol != nil { is2.Equal(got[index].FgCol.Hex, w.FgCol.Hex) is2.Equal(got[index].FgCol.Rgb, w.FgCol.Rgb) } if w.BgCol != nil { is2.Equal(got[index].BgCol.Hex, w.BgCol.Hex) is2.Equal(got[index].BgCol.Rgb, w.BgCol.Rgb) } is2.Equal(got[index].Style, w.Style) } }) } } func TestParseAnsiWithOptions(t *testing.T) { is2 := is.New(t) tests := []struct { name string input string options []ParseOption want []*StyledText wantErr bool }{ { "Unexpected code errored", "\u001b[0;99mHello World\033[0m", nil, nil, true, }, { "Unexpected code ignored", "\u001b[0;99mHello World\033[0m", []ParseOption{WithIgnoreInvalidCodes()}, []*StyledText{{Label: "Hello World"}}, false, }, { "Foreground code default", "\u001b[0;39mHello World\033[0m", nil, []*StyledText{{Label: "Hello World", FgCol: Cols[7]}}, false, }, { "Foreground code specified", "\u001b[0;39mHello World\033[0m", []ParseOption{WithDefaultForegroundColor("35")}, []*StyledText{{Label: "Hello World", FgCol: Cols[5]}}, false, }, { "Background code default", "\u001b[0;49mHello World\033[0m", nil, []*StyledText{{Label: "Hello World", BgCol: Cols[0]}}, false, }, { "Background code specified", "\u001b[0;49mHello World\033[0m", []ParseOption{WithDefaultBackgroundColor("36")}, []*StyledText{{Label: "Hello World", BgCol: Cols[6]}}, false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := Parse(tt.input, tt.options...) is2.Equal(err != nil, tt.wantErr) for index, w := range tt.want { is2.Equal(got[index].Label, w.Label) if w.FgCol != nil { is2.Equal(got[index].FgCol.Name, w.FgCol.Name) } if w.BgCol != nil { is2.Equal(got[index].BgCol.Name, w.BgCol.Name) } is2.Equal(got[index].Style, w.Style) } }) } } func TestHasEscapeCodes(t *testing.T) { is2 := is.New(t) tests := []struct { name string input string want bool }{ {"yes", "\u001B[0;30mHello World\033[0m\u001B[0;31mHello World\u001B[0m", true}, {"no", "This is great!", false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := HasEscapeCodes(tt.input) is2.Equal(got, tt.want) }) } } func TestString(t *testing.T) { is2 := is.New(t) tests := []struct { name string input []*StyledText want string }{ {"Blank", []*StyledText{}, ""}, {"ANSI16 Fg", []*StyledText{{Label: "Red", FgCol: Cols[1]}}, "\033[0;31mRed\033[0m"}, {"ANSI16 Fg Bold", []*StyledText{{Label: "Red", FgCol: Cols[1], Style: Bold}}, "\033[0;1;31mRed\033[0m"}, {"ANSI16 Fg Strikethrough", []*StyledText{{Label: "Red", FgCol: Cols[1], Style: Strikethrough}}, "\033[0;9;31mRed\033[0m"}, {"ANSI16 Fg Bold & Italic", []*StyledText{{Label: "Red", FgCol: Cols[1], Style: Bold | Italic}}, "\033[0;1;3;31mRed\033[0m"}, {"ANSI16 Bg", []*StyledText{{Label: "Black", BgCol: Cols[0]}}, "\033[0;40mBlack\033[0m"}, {"ANSI16 Mixed", []*StyledText{{Label: "Mixed", FgCol: Cols[1], BgCol: Cols[0]}}, "\033[0;31;40mMixed\033[0m"}, {"ANSI256 Fg", []*StyledText{{ColourMode: TwoFiveSix, Label: "Dark Blue", FgCol: Cols[18]}}, "\033[0;38;5;18mDark Blue\033[0m"}, {"ANSI256 Fg Bold", []*StyledText{{ColourMode: TwoFiveSix, Label: "Dark Blue", FgCol: Cols[18], Style: Bold}}, "\033[0;1;38;5;18mDark Blue\033[0m"}, {"ANSI256 Bg", []*StyledText{{ColourMode: TwoFiveSix, Label: "Dark Blue", BgCol: Cols[18]}}, "\033[0;48;5;18mDark Blue\033[0m"}, {"ANSI256 Bg Bold", []*StyledText{{ColourMode: TwoFiveSix, Label: "Dark Blue", BgCol: Cols[18], Style: Bold}}, "\033[0;1;48;5;18mDark Blue\033[0m"}, {"Truecolor Fg", []*StyledText{{ColourMode: TrueColour, Label: "TrueColor!", FgCol: &Col{Id: 256, Rgb: Rgb{R: 128, G: 127, B: 126}}}}, "\033[0;38;2;128;127;126mTrueColor!\033[0m"}, {"Truecolor Fg Bold", []*StyledText{{ColourMode: TrueColour, Label: "TrueColor!", FgCol: &Col{Id: 256, Rgb: Rgb{R: 128, G: 127, B: 126}}, Style: Bold}}, "\033[0;1;38;2;128;127;126mTrueColor!\033[0m"}, {"Truecolor Bg", []*StyledText{{ColourMode: TrueColour, Label: "TrueColor!", BgCol: &Col{Id: 256, Rgb: Rgb{R: 128, G: 127, B: 126}}}}, "\033[0;48;2;128;127;126mTrueColor!\033[0m"}, {"Truecolor Bg Bold", []*StyledText{{ColourMode: TrueColour, Label: "TrueColor!", BgCol: &Col{Id: 256, Rgb: Rgb{R: 128, G: 127, B: 126}}, Style: Bold}}, "\033[0;1;48;2;128;127;126mTrueColor!\033[0m"}, {"Truecolor Mixed", []*StyledText{{ColourMode: TrueColour, Label: "TrueColor!", FgCol: &Col{Id: 256, Rgb: Rgb{R: 90, G: 91, B: 92}}, BgCol: &Col{Id: 256, Rgb: Rgb{R: 128, G: 127, B: 126}}, Style: Bold | Faint | Underlined | Strikethrough | Italic | Invisible | Blinking | Inversed}}, "\033[0;1;2;3;4;5;7;8;9;38;2;90;91;92;48;2;128;127;126mTrueColor!\033[0m"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := String(tt.input) is2.Equal(got, tt.want) }) } } func TestTruncate(t *testing.T) { is2 := is.New(t) tests := []struct { name string input string maxChars int want string wantErr bool }{ {"No formatting", "Hello World", 11, "Hello World", false}, {"No formatting truncated", "Hello World", 5, "Hello", false}, {"No formatting many chars", "Hello World", 50, "Hello World", false}, {"Black", "\u001b[0;30mHello World\033[0m", 5, "\u001B[0;30mHello\u001B[0m", false}, {"Red Bold", "\u001b[0;1;31mHello World\033[0m", 5, "\033[0;1;31mHello\033[0m", false}, {"Red Bold & Black", "\u001b[0;1;31mI am Red\033[0m\u001B[0;30mI am Black\u001B[0m", 12, "\u001B[0;1;31mI am Red\u001B[0m\u001B[0;30mI am\u001B[0m", false}, {"Red Bold & text & Black", "\u001b[0;1;31mI am Red\033[0m and \u001B[0;30mI am Black\u001B[0m", 17, "\u001B[0;1;31mI am Red\u001B[0m and \u001B[0;30mI am\u001B[0m", false}, {"Emoji", "\u001B[0;1;31m😀👩🏽‍🔧\u001B[0m", 1, "\u001B[0;1;31m😀\u001B[0m", false}, {"Emoji 2", "\u001B[0;1;31m😀👩🏽‍🔧\u001B[0m", 2, "\u001B[0;1;31m😀👩🏽‍🔧\u001B[0m", false}, {"Emoji 3", "\u001B[0;1;31m😀👩🏽‍🔧😀\u001B[0m", 2, "\u001B[0;1;31m😀👩🏽‍🔧\u001B[0m", false}, {"Bad", "\033[44;32;12", 10, "", true}, //{"Spaces", " ", " ", "", false}, //{"Bad code", "\u001b[1 ", "", "", true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := Truncate(tt.input, tt.maxChars) is2.Equal(err != nil, tt.wantErr) is2.Equal(got, tt.want) }) } } func TestCleanse(t *testing.T) { is2 := is.New(t) tests := []struct { name string input string want string wantErr bool }{ {"Blank", "", "", false}, {"No formatting", "Hello World", "Hello World", false}, {"ANSI16 Fg", "\033[0;31mRed\033[0m", "Red", false}, {"Black", "\u001b[0;30mHello World\033[0m", "Hello World", false}, {"Red Bold & Black", "\u001b[0;1;31mI am Red\033[0m & \u001B[0;30mI am Black\u001B[0m", "I am Red & I am Black", false}, {"Red All the styles", "\u001b[0;1;2;3;4;5;7;8;9;31mI am Red\033[0m", "I am Red", false}, {"Emoji", "\u001B[0;1;31m😀\u001B[0m", "😀", false}, {"Emoji 2", "\u001B[0;1;31m😀👩🏽‍🔧\u001B[0m", "😀👩🏽‍🔧", false}, {"Bad", "\033[44;32;12", "", true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := Cleanse(tt.input) is2.Equal(err != nil, tt.wantErr) is2.Equal(got, tt.want) }) } } func TestLength(t *testing.T) { is2 := is.New(t) tests := []struct { name string input string want int wantErr bool }{ {"Blank", "", 0, false}, {"No formatting", "Hello World", 11, false}, {"ANSI16 Fg", "\033[0;31mRed\033[0m", 3, false}, {"Zero chats", "\u001b[0;30m\033[0m", 0, false}, {"Red Bold & Black", "\u001b[0;1;31mI am Red\033[0m & \u001B[0;30mI am Black\u001B[0m", 21, false}, {"Red All the styles", "\u001b[0;1;2;3;4;5;7;8;9;31mI am Red\033[0m", 8, false}, {"Emoji", "\u001B[0;1;31m😀\u001B[0m", 1, false}, {"Emoji 2", "\u001B[0;1;31m😀👩🏽‍🔧\u001B[0m", 2, false}, {"Bad", "\033[44;32;12", -1, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := Length(tt.input) is2.Equal(err != nil, tt.wantErr) is2.Equal(got, tt.want) }) } } func TestStripLeadingZeros(t *testing.T) { is2 := is.New(t) tests := []struct { name string input string want string }{ {"Blank", "", ""}, {"One rune not 0", "4", "4"}, {"Only 0", "0", "0"}, {"Multi-digit non-0", "35", "35"}, {"Two-digit leading 0", "05", "5"}, {"Three-digit leading 0", "045", "45"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := stripLeadingZeros(tt.input) is2.Equal(got, tt.want) }) } } golang-github-leaanthony-go-ansi-parser-1.6.1/cols.go000077500000000000000000000726361520237347000225460ustar00rootroot00000000000000package ansi // Rgb represents an RGB colour value // with 8bits per channel type Rgb struct { R uint8 `json:"r"` G uint8 `json:"g"` B uint8 `json:"b"` } // Hsl represents the HSL value of the colour type Hsl struct { H float64 `json:"h"` S float64 `json:"s"` L float64 `json:"l"` } // Col represents a colour value. // The Id is the ANSI colour ID. type Col struct { Id int `json:"id"` Hex string `json:"hex"` Rgb Rgb `json:"rgb"` Hsl Hsl `json:"hsl"` Name string `json:"name"` } // Cols represents the default colour definitions // used by the library. This may be overridden. var Cols = []*Col{ { Id: 0, Hex: "#000000", Rgb: Rgb{0, 0, 0}, Hsl: Hsl{0, 0, 0}, Name: "Black", }, { Id: 1, Hex: "#800000", Rgb: Rgb{128, 0, 0}, Hsl: Hsl{0, 100, 25}, Name: "Maroon", }, { Id: 2, Hex: "#008000", Rgb: Rgb{0, 128, 0}, Hsl: Hsl{120, 100, 25}, Name: "Green", }, { Id: 3, Hex: "#808000", Rgb: Rgb{128, 128, 0}, Hsl: Hsl{60, 100, 25}, Name: "Olive", }, { Id: 4, Hex: "#000080", Rgb: Rgb{0, 0, 128}, Hsl: Hsl{240, 100, 25}, Name: "Navy", }, { Id: 5, Hex: "#800080", Rgb: Rgb{128, 0, 128}, Hsl: Hsl{300, 100, 25}, Name: "Purple", }, { Id: 6, Hex: "#008080", Rgb: Rgb{0, 128, 128}, Hsl: Hsl{180, 100, 25}, Name: "Teal", }, { Id: 7, Hex: "#c0c0c0", Rgb: Rgb{192, 192, 192}, Hsl: Hsl{0, 0, 75}, Name: "Silver", }, { Id: 8, Hex: "#808080", Rgb: Rgb{128, 128, 128}, Hsl: Hsl{0, 0, 50}, Name: "Grey", }, { Id: 9, Hex: "#ff0000", Rgb: Rgb{255, 0, 0}, Hsl: Hsl{0, 100, 50}, Name: "Red", }, { Id: 10, Hex: "#00ff00", Rgb: Rgb{0, 255, 0}, Hsl: Hsl{120, 100, 50}, Name: "Lime", }, { Id: 11, Hex: "#ffff00", Rgb: Rgb{255, 255, 0}, Hsl: Hsl{60, 100, 50}, Name: "Yellow", }, { Id: 12, Hex: "#0000ff", Rgb: Rgb{0, 0, 255}, Hsl: Hsl{240, 100, 50}, Name: "Blue", }, { Id: 13, Hex: "#ff00ff", Rgb: Rgb{255, 0, 255}, Hsl: Hsl{300, 100, 50}, Name: "Fuchsia", }, { Id: 14, Hex: "#00ffff", Rgb: Rgb{0, 255, 255}, Hsl: Hsl{180, 100, 50}, Name: "Aqua", }, { Id: 15, Hex: "#ffffff", Rgb: Rgb{255, 255, 255}, Hsl: Hsl{0, 0, 100}, Name: "White", }, { Id: 16, Hex: "#000000", Rgb: Rgb{0, 0, 0}, Hsl: Hsl{0, 0, 0}, Name: "Grey0", }, { Id: 17, Hex: "#00005f", Rgb: Rgb{0, 0, 95}, Hsl: Hsl{240, 100, 18}, Name: "NavyBlue", }, { Id: 18, Hex: "#000087", Rgb: Rgb{0, 0, 135}, Hsl: Hsl{240, 100, 26}, Name: "DarkBlue", }, { Id: 19, Hex: "#0000af", Rgb: Rgb{0, 0, 175}, Hsl: Hsl{240, 100, 34}, Name: "Blue3", }, { Id: 20, Hex: "#0000d7", Rgb: Rgb{0, 0, 215}, Hsl: Hsl{240, 100, 42}, Name: "Blue3", }, { Id: 21, Hex: "#0000ff", Rgb: Rgb{0, 0, 255}, Hsl: Hsl{240, 100, 50}, Name: "Blue1", }, { Id: 22, Hex: "#005f00", Rgb: Rgb{0, 95, 0}, Hsl: Hsl{120, 100, 18}, Name: "DarkGreen", }, { Id: 23, Hex: "#005f5f", Rgb: Rgb{0, 95, 95}, Hsl: Hsl{180, 100, 18}, Name: "DeepSkyBlue4", }, { Id: 24, Hex: "#005f87", Rgb: Rgb{0, 95, 135}, Hsl: Hsl{197.777777777778, 100, 26}, Name: "DeepSkyBlue4", }, { Id: 25, Hex: "#005faf", Rgb: Rgb{0, 95, 175}, Hsl: Hsl{207.428571428571, 100, 34}, Name: "DeepSkyBlue4", }, { Id: 26, Hex: "#005fd7", Rgb: Rgb{0, 95, 215}, Hsl: Hsl{213.488372093023, 100, 42}, Name: "DodgerBlue3", }, { Id: 27, Hex: "#005fff", Rgb: Rgb{0, 95, 255}, Hsl: Hsl{217.647058823529, 100, 50}, Name: "DodgerBlue2", }, { Id: 28, Hex: "#008700", Rgb: Rgb{0, 135, 0}, Hsl: Hsl{120, 100, 26}, Name: "Green4", }, { Id: 29, Hex: "#00875f", Rgb: Rgb{0, 135, 95}, Hsl: Hsl{162.222222222222, 100, 26}, Name: "SpringGreen4", }, { Id: 30, Hex: "#008787", Rgb: Rgb{0, 135, 135}, Hsl: Hsl{180, 100, 26}, Name: "Turquoise4", }, { Id: 31, Hex: "#0087af", Rgb: Rgb{0, 135, 175}, Hsl: Hsl{193.714285714286, 100, 34}, Name: "DeepSkyBlue3", }, { Id: 32, Hex: "#0087d7", Rgb: Rgb{0, 135, 215}, Hsl: Hsl{202.325581395349, 100, 42}, Name: "DeepSkyBlue3", }, { Id: 33, Hex: "#0087ff", Rgb: Rgb{0, 135, 255}, Hsl: Hsl{208.235294117647, 100, 50}, Name: "DodgerBlue1", }, { Id: 34, Hex: "#00af00", Rgb: Rgb{0, 175, 0}, Hsl: Hsl{120, 100, 34}, Name: "Green3", }, { Id: 35, Hex: "#00af5f", Rgb: Rgb{0, 175, 95}, Hsl: Hsl{152.571428571429, 100, 34}, Name: "SpringGreen3", }, { Id: 36, Hex: "#00af87", Rgb: Rgb{0, 175, 135}, Hsl: Hsl{166.285714285714, 100, 34}, Name: "DarkCyan", }, { Id: 37, Hex: "#00afaf", Rgb: Rgb{0, 175, 175}, Hsl: Hsl{180, 100, 34}, Name: "LightSeaGreen", }, { Id: 38, Hex: "#00afd7", Rgb: Rgb{0, 175, 215}, Hsl: Hsl{191.162790697674, 100, 42}, Name: "DeepSkyBlue2", }, { Id: 39, Hex: "#00afff", Rgb: Rgb{0, 175, 255}, Hsl: Hsl{198.823529411765, 100, 50}, Name: "DeepSkyBlue1", }, { Id: 40, Hex: "#00d700", Rgb: Rgb{0, 215, 0}, Hsl: Hsl{120, 100, 42}, Name: "Green3", }, { Id: 41, Hex: "#00d75f", Rgb: Rgb{0, 215, 95}, Hsl: Hsl{146.511627906977, 100, 42}, Name: "SpringGreen3", }, { Id: 42, Hex: "#00d787", Rgb: Rgb{0, 215, 135}, Hsl: Hsl{157.674418604651, 100, 42}, Name: "SpringGreen2", }, { Id: 43, Hex: "#00d7af", Rgb: Rgb{0, 215, 175}, Hsl: Hsl{168.837209302326, 100, 42}, Name: "Cyan3", }, { Id: 44, Hex: "#00d7d7", Rgb: Rgb{0, 215, 215}, Hsl: Hsl{180, 100, 42}, Name: "DarkTurquoise", }, { Id: 45, Hex: "#00d7ff", Rgb: Rgb{0, 215, 255}, Hsl: Hsl{189.411764705882, 100, 50}, Name: "Turquoise2", }, { Id: 46, Hex: "#00ff00", Rgb: Rgb{0, 255, 0}, Hsl: Hsl{120, 100, 50}, Name: "Green1", }, { Id: 47, Hex: "#00ff5f", Rgb: Rgb{0, 255, 95}, Hsl: Hsl{142.352941176471, 100, 50}, Name: "SpringGreen2", }, { Id: 48, Hex: "#00ff87", Rgb: Rgb{0, 255, 135}, Hsl: Hsl{151.764705882353, 100, 50}, Name: "SpringGreen1", }, { Id: 49, Hex: "#00ffaf", Rgb: Rgb{0, 255, 175}, Hsl: Hsl{161.176470588235, 100, 50}, Name: "MediumSpringGreen", }, { Id: 50, Hex: "#00ffd7", Rgb: Rgb{0, 255, 215}, Hsl: Hsl{170.588235294118, 100, 50}, Name: "Cyan2", }, { Id: 51, Hex: "#00ffff", Rgb: Rgb{0, 255, 255}, Hsl: Hsl{180, 100, 50}, Name: "Cyan1", }, { Id: 52, Hex: "#5f0000", Rgb: Rgb{95, 0, 0}, Hsl: Hsl{0, 100, 18}, Name: "DarkRed", }, { Id: 53, Hex: "#5f005f", Rgb: Rgb{95, 0, 95}, Hsl: Hsl{300, 100, 18}, Name: "DeepPink4", }, { Id: 54, Hex: "#5f0087", Rgb: Rgb{95, 0, 135}, Hsl: Hsl{282.222222222222, 100, 26}, Name: "Purple4", }, { Id: 55, Hex: "#5f00af", Rgb: Rgb{95, 0, 175}, Hsl: Hsl{272.571428571429, 100, 34}, Name: "Purple4", }, { Id: 56, Hex: "#5f00d7", Rgb: Rgb{95, 0, 215}, Hsl: Hsl{266.511627906977, 100, 42}, Name: "Purple3", }, { Id: 57, Hex: "#5f00ff", Rgb: Rgb{95, 0, 255}, Hsl: Hsl{262.352941176471, 100, 50}, Name: "BlueViolet", }, { Id: 58, Hex: "#5f5f00", Rgb: Rgb{95, 95, 0}, Hsl: Hsl{60, 100, 18}, Name: "Orange4", }, { Id: 59, Hex: "#5f5f5f", Rgb: Rgb{95, 95, 95}, Hsl: Hsl{0, 0, 37}, Name: "Grey37", }, { Id: 60, Hex: "#5f5f87", Rgb: Rgb{95, 95, 135}, Hsl: Hsl{240, 17, 45}, Name: "MediumPurple4", }, { Id: 61, Hex: "#5f5faf", Rgb: Rgb{95, 95, 175}, Hsl: Hsl{240, 33, 52}, Name: "SlateBlue3", }, { Id: 62, Hex: "#5f5fd7", Rgb: Rgb{95, 95, 215}, Hsl: Hsl{240, 60, 60}, Name: "SlateBlue3", }, { Id: 63, Hex: "#5f5fff", Rgb: Rgb{95, 95, 255}, Hsl: Hsl{240, 100, 68}, Name: "RoyalBlue1", }, { Id: 64, Hex: "#5f8700", Rgb: Rgb{95, 135, 0}, Hsl: Hsl{77.7777777777778, 100, 26}, Name: "Chartreuse4", }, { Id: 65, Hex: "#5f875f", Rgb: Rgb{95, 135, 95}, Hsl: Hsl{120, 17, 45}, Name: "DarkSeaGreen4", }, { Id: 66, Hex: "#5f8787", Rgb: Rgb{95, 135, 135}, Hsl: Hsl{180, 17, 45}, Name: "PaleTurquoise4", }, { Id: 67, Hex: "#5f87af", Rgb: Rgb{95, 135, 175}, Hsl: Hsl{210, 33, 52}, Name: "SteelBlue", }, { Id: 68, Hex: "#5f87d7", Rgb: Rgb{95, 135, 215}, Hsl: Hsl{220, 60, 60}, Name: "SteelBlue3", }, { Id: 69, Hex: "#5f87ff", Rgb: Rgb{95, 135, 255}, Hsl: Hsl{225, 100, 68}, Name: "CornflowerBlue", }, { Id: 70, Hex: "#5faf00", Rgb: Rgb{95, 175, 0}, Hsl: Hsl{87.4285714285714, 100, 34}, Name: "Chartreuse3", }, { Id: 71, Hex: "#5faf5f", Rgb: Rgb{95, 175, 95}, Hsl: Hsl{120, 33, 52}, Name: "DarkSeaGreen4", }, { Id: 72, Hex: "#5faf87", Rgb: Rgb{95, 175, 135}, Hsl: Hsl{150, 33, 52}, Name: "CadetBlue", }, { Id: 73, Hex: "#5fafaf", Rgb: Rgb{95, 175, 175}, Hsl: Hsl{180, 33, 52}, Name: "CadetBlue", }, { Id: 74, Hex: "#5fafd7", Rgb: Rgb{95, 175, 215}, Hsl: Hsl{200, 60, 60}, Name: "SkyBlue3", }, { Id: 75, Hex: "#5fafff", Rgb: Rgb{95, 175, 255}, Hsl: Hsl{210, 100, 68}, Name: "SteelBlue1", }, { Id: 76, Hex: "#5fd700", Rgb: Rgb{95, 215, 0}, Hsl: Hsl{93.4883720930233, 100, 42}, Name: "Chartreuse3", }, { Id: 77, Hex: "#5fd75f", Rgb: Rgb{95, 215, 95}, Hsl: Hsl{120, 60, 60}, Name: "PaleGreen3", }, { Id: 78, Hex: "#5fd787", Rgb: Rgb{95, 215, 135}, Hsl: Hsl{140, 60, 60}, Name: "SeaGreen3", }, { Id: 79, Hex: "#5fd7af", Rgb: Rgb{95, 215, 175}, Hsl: Hsl{160, 60, 60}, Name: "Aquamarine3", }, { Id: 80, Hex: "#5fd7d7", Rgb: Rgb{95, 215, 215}, Hsl: Hsl{180, 60, 60}, Name: "MediumTurquoise", }, { Id: 81, Hex: "#5fd7ff", Rgb: Rgb{95, 215, 255}, Hsl: Hsl{195, 100, 68}, Name: "SteelBlue1", }, { Id: 82, Hex: "#5fff00", Rgb: Rgb{95, 255, 0}, Hsl: Hsl{97.6470588235294, 100, 50}, Name: "Chartreuse2", }, { Id: 83, Hex: "#5fff5f", Rgb: Rgb{95, 255, 95}, Hsl: Hsl{120, 100, 68}, Name: "SeaGreen2", }, { Id: 84, Hex: "#5fff87", Rgb: Rgb{95, 255, 135}, Hsl: Hsl{135, 100, 68}, Name: "SeaGreen1", }, { Id: 85, Hex: "#5fffaf", Rgb: Rgb{95, 255, 175}, Hsl: Hsl{150, 100, 68}, Name: "SeaGreen1", }, { Id: 86, Hex: "#5fffd7", Rgb: Rgb{95, 255, 215}, Hsl: Hsl{165, 100, 68}, Name: "Aquamarine1", }, { Id: 87, Hex: "#5fffff", Rgb: Rgb{95, 255, 255}, Hsl: Hsl{180, 100, 68}, Name: "DarkSlateGray2", }, { Id: 88, Hex: "#870000", Rgb: Rgb{135, 0, 0}, Hsl: Hsl{0, 100, 26}, Name: "DarkRed", }, { Id: 89, Hex: "#87005f", Rgb: Rgb{135, 0, 95}, Hsl: Hsl{317.777777777778, 100, 26}, Name: "DeepPink4", }, { Id: 90, Hex: "#870087", Rgb: Rgb{135, 0, 135}, Hsl: Hsl{300, 100, 26}, Name: "DarkMagenta", }, { Id: 91, Hex: "#8700af", Rgb: Rgb{135, 0, 175}, Hsl: Hsl{286.285714285714, 100, 34}, Name: "DarkMagenta", }, { Id: 92, Hex: "#8700d7", Rgb: Rgb{135, 0, 215}, Hsl: Hsl{277.674418604651, 100, 42}, Name: "DarkViolet", }, { Id: 93, Hex: "#8700ff", Rgb: Rgb{135, 0, 255}, Hsl: Hsl{271.764705882353, 100, 50}, Name: "Purple", }, { Id: 94, Hex: "#875f00", Rgb: Rgb{135, 95, 0}, Hsl: Hsl{42.2222222222222, 100, 26}, Name: "Orange4", }, { Id: 95, Hex: "#875f5f", Rgb: Rgb{135, 95, 95}, Hsl: Hsl{0, 17, 45}, Name: "LightPink4", }, { Id: 96, Hex: "#875f87", Rgb: Rgb{135, 95, 135}, Hsl: Hsl{300, 17, 45}, Name: "Plum4", }, { Id: 97, Hex: "#875faf", Rgb: Rgb{135, 95, 175}, Hsl: Hsl{270, 33, 52}, Name: "MediumPurple3", }, { Id: 98, Hex: "#875fd7", Rgb: Rgb{135, 95, 215}, Hsl: Hsl{260, 60, 60}, Name: "MediumPurple3", }, { Id: 99, Hex: "#875fff", Rgb: Rgb{135, 95, 255}, Hsl: Hsl{255, 100, 68}, Name: "SlateBlue1", }, { Id: 100, Hex: "#878700", Rgb: Rgb{135, 135, 0}, Hsl: Hsl{60, 100, 26}, Name: "Yellow4", }, { Id: 101, Hex: "#87875f", Rgb: Rgb{135, 135, 95}, Hsl: Hsl{60, 17, 45}, Name: "Wheat4", }, { Id: 102, Hex: "#878787", Rgb: Rgb{135, 135, 135}, Hsl: Hsl{0, 0, 52}, Name: "Grey53", }, { Id: 103, Hex: "#8787af", Rgb: Rgb{135, 135, 175}, Hsl: Hsl{240, 20, 60}, Name: "LightSlateGrey", }, { Id: 104, Hex: "#8787d7", Rgb: Rgb{135, 135, 215}, Hsl: Hsl{240, 50, 68}, Name: "MediumPurple", }, { Id: 105, Hex: "#8787ff", Rgb: Rgb{135, 135, 255}, Hsl: Hsl{240, 100, 76}, Name: "LightSlateBlue", }, { Id: 106, Hex: "#87af00", Rgb: Rgb{135, 175, 0}, Hsl: Hsl{73.7142857142857, 100, 34}, Name: "Yellow4", }, { Id: 107, Hex: "#87af5f", Rgb: Rgb{135, 175, 95}, Hsl: Hsl{90, 33, 52}, Name: "DarkOliveGreen3", }, { Id: 108, Hex: "#87af87", Rgb: Rgb{135, 175, 135}, Hsl: Hsl{120, 20, 60}, Name: "DarkSeaGreen", }, { Id: 109, Hex: "#87afaf", Rgb: Rgb{135, 175, 175}, Hsl: Hsl{180, 20, 60}, Name: "LightSkyBlue3", }, { Id: 110, Hex: "#87afd7", Rgb: Rgb{135, 175, 215}, Hsl: Hsl{210, 50, 68}, Name: "LightSkyBlue3", }, { Id: 111, Hex: "#87afff", Rgb: Rgb{135, 175, 255}, Hsl: Hsl{220, 100, 76}, Name: "SkyBlue2", }, { Id: 112, Hex: "#87d700", Rgb: Rgb{135, 215, 0}, Hsl: Hsl{82.3255813953488, 100, 42}, Name: "Chartreuse2", }, { Id: 113, Hex: "#87d75f", Rgb: Rgb{135, 215, 95}, Hsl: Hsl{100, 60, 60}, Name: "DarkOliveGreen3", }, { Id: 114, Hex: "#87d787", Rgb: Rgb{135, 215, 135}, Hsl: Hsl{120, 50, 68}, Name: "PaleGreen3", }, { Id: 115, Hex: "#87d7af", Rgb: Rgb{135, 215, 175}, Hsl: Hsl{150, 50, 68}, Name: "DarkSeaGreen3", }, { Id: 116, Hex: "#87d7d7", Rgb: Rgb{135, 215, 215}, Hsl: Hsl{180, 50, 68}, Name: "DarkSlateGray3", }, { Id: 117, Hex: "#87d7ff", Rgb: Rgb{135, 215, 255}, Hsl: Hsl{200, 100, 76}, Name: "SkyBlue1", }, { Id: 118, Hex: "#87ff00", Rgb: Rgb{135, 255, 0}, Hsl: Hsl{88.2352941176471, 100, 50}, Name: "Chartreuse1", }, { Id: 119, Hex: "#87ff5f", Rgb: Rgb{135, 255, 95}, Hsl: Hsl{105, 100, 68}, Name: "LightGreen", }, { Id: 120, Hex: "#87ff87", Rgb: Rgb{135, 255, 135}, Hsl: Hsl{120, 100, 76}, Name: "LightGreen", }, { Id: 121, Hex: "#87ffaf", Rgb: Rgb{135, 255, 175}, Hsl: Hsl{140, 100, 76}, Name: "PaleGreen1", }, { Id: 122, Hex: "#87ffd7", Rgb: Rgb{135, 255, 215}, Hsl: Hsl{160, 100, 76}, Name: "Aquamarine1", }, { Id: 123, Hex: "#87ffff", Rgb: Rgb{135, 255, 255}, Hsl: Hsl{180, 100, 76}, Name: "DarkSlateGray1", }, { Id: 124, Hex: "#af0000", Rgb: Rgb{175, 0, 0}, Hsl: Hsl{0, 100, 34}, Name: "Red3", }, { Id: 125, Hex: "#af005f", Rgb: Rgb{175, 0, 95}, Hsl: Hsl{327.428571428571, 100, 34}, Name: "DeepPink4", }, { Id: 126, Hex: "#af0087", Rgb: Rgb{175, 0, 135}, Hsl: Hsl{313.714285714286, 100, 34}, Name: "MediumVioletRed", }, { Id: 127, Hex: "#af00af", Rgb: Rgb{175, 0, 175}, Hsl: Hsl{300, 100, 34}, Name: "Magenta3", }, { Id: 128, Hex: "#af00d7", Rgb: Rgb{175, 0, 215}, Hsl: Hsl{288.837209302326, 100, 42}, Name: "DarkViolet", }, { Id: 129, Hex: "#af00ff", Rgb: Rgb{175, 0, 255}, Hsl: Hsl{281.176470588235, 100, 50}, Name: "Purple", }, { Id: 130, Hex: "#af5f00", Rgb: Rgb{175, 95, 0}, Hsl: Hsl{32.5714285714286, 100, 34}, Name: "DarkOrange3", }, { Id: 131, Hex: "#af5f5f", Rgb: Rgb{175, 95, 95}, Hsl: Hsl{0, 33, 52}, Name: "IndianRed", }, { Id: 132, Hex: "#af5f87", Rgb: Rgb{175, 95, 135}, Hsl: Hsl{330, 33, 52}, Name: "HotPink3", }, { Id: 133, Hex: "#af5faf", Rgb: Rgb{175, 95, 175}, Hsl: Hsl{300, 33, 52}, Name: "MediumOrchid3", }, { Id: 134, Hex: "#af5fd7", Rgb: Rgb{175, 95, 215}, Hsl: Hsl{280, 60, 60}, Name: "MediumOrchid", }, { Id: 135, Hex: "#af5fff", Rgb: Rgb{175, 95, 255}, Hsl: Hsl{270, 100, 68}, Name: "MediumPurple2", }, { Id: 136, Hex: "#af8700", Rgb: Rgb{175, 135, 0}, Hsl: Hsl{46.2857142857143, 100, 34}, Name: "DarkGoldenrod", }, { Id: 137, Hex: "#af875f", Rgb: Rgb{175, 135, 95}, Hsl: Hsl{30, 33, 52}, Name: "LightSalmon3", }, { Id: 138, Hex: "#af8787", Rgb: Rgb{175, 135, 135}, Hsl: Hsl{0, 20, 60}, Name: "RosyBrown", }, { Id: 139, Hex: "#af87af", Rgb: Rgb{175, 135, 175}, Hsl: Hsl{300, 20, 60}, Name: "Grey63", }, { Id: 140, Hex: "#af87d7", Rgb: Rgb{175, 135, 215}, Hsl: Hsl{270, 50, 68}, Name: "MediumPurple2", }, { Id: 141, Hex: "#af87ff", Rgb: Rgb{175, 135, 255}, Hsl: Hsl{260, 100, 76}, Name: "MediumPurple1", }, { Id: 142, Hex: "#afaf00", Rgb: Rgb{175, 175, 0}, Hsl: Hsl{60, 100, 34}, Name: "Gold3", }, { Id: 143, Hex: "#afaf5f", Rgb: Rgb{175, 175, 95}, Hsl: Hsl{60, 33, 52}, Name: "DarkKhaki", }, { Id: 144, Hex: "#afaf87", Rgb: Rgb{175, 175, 135}, Hsl: Hsl{60, 20, 60}, Name: "NavajoWhite3", }, { Id: 145, Hex: "#afafaf", Rgb: Rgb{175, 175, 175}, Hsl: Hsl{0, 0, 68}, Name: "Grey69", }, { Id: 146, Hex: "#afafd7", Rgb: Rgb{175, 175, 215}, Hsl: Hsl{240, 33, 76}, Name: "LightSteelBlue3", }, { Id: 147, Hex: "#afafff", Rgb: Rgb{175, 175, 255}, Hsl: Hsl{240, 100, 84}, Name: "LightSteelBlue", }, { Id: 148, Hex: "#afd700", Rgb: Rgb{175, 215, 0}, Hsl: Hsl{71.1627906976744, 100, 42}, Name: "Yellow3", }, { Id: 149, Hex: "#afd75f", Rgb: Rgb{175, 215, 95}, Hsl: Hsl{80, 60, 60}, Name: "DarkOliveGreen3", }, { Id: 150, Hex: "#afd787", Rgb: Rgb{175, 215, 135}, Hsl: Hsl{90, 50, 68}, Name: "DarkSeaGreen3", }, { Id: 151, Hex: "#afd7af", Rgb: Rgb{175, 215, 175}, Hsl: Hsl{120, 33, 76}, Name: "DarkSeaGreen2", }, { Id: 152, Hex: "#afd7d7", Rgb: Rgb{175, 215, 215}, Hsl: Hsl{180, 33, 76}, Name: "LightCyan3", }, { Id: 153, Hex: "#afd7ff", Rgb: Rgb{175, 215, 255}, Hsl: Hsl{210, 100, 84}, Name: "LightSkyBlue1", }, { Id: 154, Hex: "#afff00", Rgb: Rgb{175, 255, 0}, Hsl: Hsl{78.8235294117647, 100, 50}, Name: "GreenYellow", }, { Id: 155, Hex: "#afff5f", Rgb: Rgb{175, 255, 95}, Hsl: Hsl{90, 100, 68}, Name: "DarkOliveGreen2", }, { Id: 156, Hex: "#afff87", Rgb: Rgb{175, 255, 135}, Hsl: Hsl{100, 100, 76}, Name: "PaleGreen1", }, { Id: 157, Hex: "#afffaf", Rgb: Rgb{175, 255, 175}, Hsl: Hsl{120, 100, 84}, Name: "DarkSeaGreen2", }, { Id: 158, Hex: "#afffd7", Rgb: Rgb{175, 255, 215}, Hsl: Hsl{150, 100, 84}, Name: "DarkSeaGreen1", }, { Id: 159, Hex: "#afffff", Rgb: Rgb{175, 255, 255}, Hsl: Hsl{180, 100, 84}, Name: "PaleTurquoise1", }, { Id: 160, Hex: "#d70000", Rgb: Rgb{215, 0, 0}, Hsl: Hsl{0, 100, 42}, Name: "Red3", }, { Id: 161, Hex: "#d7005f", Rgb: Rgb{215, 0, 95}, Hsl: Hsl{333.488372093023, 100, 42}, Name: "DeepPink3", }, { Id: 162, Hex: "#d70087", Rgb: Rgb{215, 0, 135}, Hsl: Hsl{322.325581395349, 100, 42}, Name: "DeepPink3", }, { Id: 163, Hex: "#d700af", Rgb: Rgb{215, 0, 175}, Hsl: Hsl{311.162790697674, 100, 42}, Name: "Magenta3", }, { Id: 164, Hex: "#d700d7", Rgb: Rgb{215, 0, 215}, Hsl: Hsl{300, 100, 42}, Name: "Magenta3", }, { Id: 165, Hex: "#d700ff", Rgb: Rgb{215, 0, 255}, Hsl: Hsl{290.588235294118, 100, 50}, Name: "Magenta2", }, { Id: 166, Hex: "#d75f00", Rgb: Rgb{215, 95, 0}, Hsl: Hsl{26.5116279069767, 100, 42}, Name: "DarkOrange3", }, { Id: 167, Hex: "#d75f5f", Rgb: Rgb{215, 95, 95}, Hsl: Hsl{0, 60, 60}, Name: "IndianRed", }, { Id: 168, Hex: "#d75f87", Rgb: Rgb{215, 95, 135}, Hsl: Hsl{340, 60, 60}, Name: "HotPink3", }, { Id: 169, Hex: "#d75faf", Rgb: Rgb{215, 95, 175}, Hsl: Hsl{320, 60, 60}, Name: "HotPink2", }, { Id: 170, Hex: "#d75fd7", Rgb: Rgb{215, 95, 215}, Hsl: Hsl{300, 60, 60}, Name: "Orchid", }, { Id: 171, Hex: "#d75fff", Rgb: Rgb{215, 95, 255}, Hsl: Hsl{285, 100, 68}, Name: "MediumOrchid1", }, { Id: 172, Hex: "#d78700", Rgb: Rgb{215, 135, 0}, Hsl: Hsl{37.6744186046512, 100, 42}, Name: "Orange3", }, { Id: 173, Hex: "#d7875f", Rgb: Rgb{215, 135, 95}, Hsl: Hsl{20, 60, 60}, Name: "LightSalmon3", }, { Id: 174, Hex: "#d78787", Rgb: Rgb{215, 135, 135}, Hsl: Hsl{0, 50, 68}, Name: "LightPink3", }, { Id: 175, Hex: "#d787af", Rgb: Rgb{215, 135, 175}, Hsl: Hsl{330, 50, 68}, Name: "Pink3", }, { Id: 176, Hex: "#d787d7", Rgb: Rgb{215, 135, 215}, Hsl: Hsl{300, 50, 68}, Name: "Plum3", }, { Id: 177, Hex: "#d787ff", Rgb: Rgb{215, 135, 255}, Hsl: Hsl{280, 100, 76}, Name: "Violet", }, { Id: 178, Hex: "#d7af00", Rgb: Rgb{215, 175, 0}, Hsl: Hsl{48.8372093023256, 100, 42}, Name: "Gold3", }, { Id: 179, Hex: "#d7af5f", Rgb: Rgb{215, 175, 95}, Hsl: Hsl{40, 60, 60}, Name: "LightGoldenrod3", }, { Id: 180, Hex: "#d7af87", Rgb: Rgb{215, 175, 135}, Hsl: Hsl{30, 50, 68}, Name: "Tan", }, { Id: 181, Hex: "#d7afaf", Rgb: Rgb{215, 175, 175}, Hsl: Hsl{0, 33, 76}, Name: "MistyRose3", }, { Id: 182, Hex: "#d7afd7", Rgb: Rgb{215, 175, 215}, Hsl: Hsl{300, 33, 76}, Name: "Thistle3", }, { Id: 183, Hex: "#d7afff", Rgb: Rgb{215, 175, 255}, Hsl: Hsl{270, 100, 84}, Name: "Plum2", }, { Id: 184, Hex: "#d7d700", Rgb: Rgb{215, 215, 0}, Hsl: Hsl{60, 100, 42}, Name: "Yellow3", }, { Id: 185, Hex: "#d7d75f", Rgb: Rgb{215, 215, 95}, Hsl: Hsl{60, 60, 60}, Name: "Khaki3", }, { Id: 186, Hex: "#d7d787", Rgb: Rgb{215, 215, 135}, Hsl: Hsl{60, 50, 68}, Name: "LightGoldenrod2", }, { Id: 187, Hex: "#d7d7af", Rgb: Rgb{215, 215, 175}, Hsl: Hsl{60, 33, 76}, Name: "LightYellow3", }, { Id: 188, Hex: "#d7d7d7", Rgb: Rgb{215, 215, 215}, Hsl: Hsl{0, 0, 84}, Name: "Grey84", }, { Id: 189, Hex: "#d7d7ff", Rgb: Rgb{215, 215, 255}, Hsl: Hsl{240, 100, 92}, Name: "LightSteelBlue1", }, { Id: 190, Hex: "#d7ff00", Rgb: Rgb{215, 255, 0}, Hsl: Hsl{69.4117647058823, 100, 50}, Name: "Yellow2", }, { Id: 191, Hex: "#d7ff5f", Rgb: Rgb{215, 255, 95}, Hsl: Hsl{75, 100, 68}, Name: "DarkOliveGreen1", }, { Id: 192, Hex: "#d7ff87", Rgb: Rgb{215, 255, 135}, Hsl: Hsl{80, 100, 76}, Name: "DarkOliveGreen1", }, { Id: 193, Hex: "#d7ffaf", Rgb: Rgb{215, 255, 175}, Hsl: Hsl{90, 100, 84}, Name: "DarkSeaGreen1", }, { Id: 194, Hex: "#d7ffd7", Rgb: Rgb{215, 255, 215}, Hsl: Hsl{120, 100, 92}, Name: "Honeydew2", }, { Id: 195, Hex: "#d7ffff", Rgb: Rgb{215, 255, 255}, Hsl: Hsl{180, 100, 92}, Name: "LightCyan1", }, { Id: 196, Hex: "#ff0000", Rgb: Rgb{255, 0, 0}, Hsl: Hsl{0, 100, 50}, Name: "Red1", }, { Id: 197, Hex: "#ff005f", Rgb: Rgb{255, 0, 95}, Hsl: Hsl{337.647058823529, 100, 50}, Name: "DeepPink2", }, { Id: 198, Hex: "#ff0087", Rgb: Rgb{255, 0, 135}, Hsl: Hsl{328.235294117647, 100, 50}, Name: "DeepPink1", }, { Id: 199, Hex: "#ff00af", Rgb: Rgb{255, 0, 175}, Hsl: Hsl{318.823529411765, 100, 50}, Name: "DeepPink1", }, { Id: 200, Hex: "#ff00d7", Rgb: Rgb{255, 0, 215}, Hsl: Hsl{309.411764705882, 100, 50}, Name: "Magenta2", }, { Id: 201, Hex: "#ff00ff", Rgb: Rgb{255, 0, 255}, Hsl: Hsl{300, 100, 50}, Name: "Magenta1", }, { Id: 202, Hex: "#ff5f00", Rgb: Rgb{255, 95, 0}, Hsl: Hsl{22.3529411764706, 100, 50}, Name: "OrangeRed1", }, { Id: 203, Hex: "#ff5f5f", Rgb: Rgb{255, 95, 95}, Hsl: Hsl{0, 100, 68}, Name: "IndianRed1", }, { Id: 204, Hex: "#ff5f87", Rgb: Rgb{255, 95, 135}, Hsl: Hsl{345, 100, 68}, Name: "IndianRed1", }, { Id: 205, Hex: "#ff5faf", Rgb: Rgb{255, 95, 175}, Hsl: Hsl{330, 100, 68}, Name: "HotPink", }, { Id: 206, Hex: "#ff5fd7", Rgb: Rgb{255, 95, 215}, Hsl: Hsl{315, 100, 68}, Name: "HotPink", }, { Id: 207, Hex: "#ff5fff", Rgb: Rgb{255, 95, 255}, Hsl: Hsl{300, 100, 68}, Name: "MediumOrchid1", }, { Id: 208, Hex: "#ff8700", Rgb: Rgb{255, 135, 0}, Hsl: Hsl{31.7647058823529, 100, 50}, Name: "DarkOrange", }, { Id: 209, Hex: "#ff875f", Rgb: Rgb{255, 135, 95}, Hsl: Hsl{15, 100, 68}, Name: "Salmon1", }, { Id: 210, Hex: "#ff8787", Rgb: Rgb{255, 135, 135}, Hsl: Hsl{0, 100, 76}, Name: "LightCoral", }, { Id: 211, Hex: "#ff87af", Rgb: Rgb{255, 135, 175}, Hsl: Hsl{340, 100, 76}, Name: "PaleVioletRed1", }, { Id: 212, Hex: "#ff87d7", Rgb: Rgb{255, 135, 215}, Hsl: Hsl{320, 100, 76}, Name: "Orchid2", }, { Id: 213, Hex: "#ff87ff", Rgb: Rgb{255, 135, 255}, Hsl: Hsl{300, 100, 76}, Name: "Orchid1", }, { Id: 214, Hex: "#ffaf00", Rgb: Rgb{255, 175, 0}, Hsl: Hsl{41.1764705882353, 100, 50}, Name: "Orange1", }, { Id: 215, Hex: "#ffaf5f", Rgb: Rgb{255, 175, 95}, Hsl: Hsl{30, 100, 68}, Name: "SandyBrown", }, { Id: 216, Hex: "#ffaf87", Rgb: Rgb{255, 175, 135}, Hsl: Hsl{20, 100, 76}, Name: "LightSalmon1", }, { Id: 217, Hex: "#ffafaf", Rgb: Rgb{255, 175, 175}, Hsl: Hsl{0, 100, 84}, Name: "LightPink1", }, { Id: 218, Hex: "#ffafd7", Rgb: Rgb{255, 175, 215}, Hsl: Hsl{330, 100, 84}, Name: "Pink1", }, { Id: 219, Hex: "#ffafff", Rgb: Rgb{255, 175, 255}, Hsl: Hsl{300, 100, 84}, Name: "Plum1", }, { Id: 220, Hex: "#ffd700", Rgb: Rgb{255, 215, 0}, Hsl: Hsl{50.5882352941176, 100, 50}, Name: "Gold1", }, { Id: 221, Hex: "#ffd75f", Rgb: Rgb{255, 215, 95}, Hsl: Hsl{45, 100, 68}, Name: "LightGoldenrod2", }, { Id: 222, Hex: "#ffd787", Rgb: Rgb{255, 215, 135}, Hsl: Hsl{40, 100, 76}, Name: "LightGoldenrod2", }, { Id: 223, Hex: "#ffd7af", Rgb: Rgb{255, 215, 175}, Hsl: Hsl{30, 100, 84}, Name: "NavajoWhite1", }, { Id: 224, Hex: "#ffd7d7", Rgb: Rgb{255, 215, 215}, Hsl: Hsl{0, 100, 92}, Name: "MistyRose1", }, { Id: 225, Hex: "#ffd7ff", Rgb: Rgb{255, 215, 255}, Hsl: Hsl{300, 100, 92}, Name: "Thistle1", }, { Id: 226, Hex: "#ffff00", Rgb: Rgb{255, 255, 0}, Hsl: Hsl{60, 100, 50}, Name: "Yellow1", }, { Id: 227, Hex: "#ffff5f", Rgb: Rgb{255, 255, 95}, Hsl: Hsl{60, 100, 68}, Name: "LightGoldenrod1", }, { Id: 228, Hex: "#ffff87", Rgb: Rgb{255, 255, 135}, Hsl: Hsl{60, 100, 76}, Name: "Khaki1", }, { Id: 229, Hex: "#ffffaf", Rgb: Rgb{255, 255, 175}, Hsl: Hsl{60, 100, 84}, Name: "Wheat1", }, { Id: 230, Hex: "#ffffd7", Rgb: Rgb{255, 255, 215}, Hsl: Hsl{60, 100, 92}, Name: "Cornsilk1", }, { Id: 231, Hex: "#ffffff", Rgb: Rgb{255, 255, 255}, Hsl: Hsl{0, 0, 100}, Name: "Grey100", }, { Id: 232, Hex: "#080808", Rgb: Rgb{8, 8, 8}, Hsl: Hsl{0, 0, 3}, Name: "Grey3", }, { Id: 233, Hex: "#121212", Rgb: Rgb{18, 18, 18}, Hsl: Hsl{0, 0, 7}, Name: "Grey7", }, { Id: 234, Hex: "#1c1c1c", Rgb: Rgb{28, 28, 28}, Hsl: Hsl{0, 0, 10}, Name: "Grey11", }, { Id: 235, Hex: "#262626", Rgb: Rgb{38, 38, 38}, Hsl: Hsl{0, 0, 14}, Name: "Grey15", }, { Id: 236, Hex: "#303030", Rgb: Rgb{48, 48, 48}, Hsl: Hsl{0, 0, 18}, Name: "Grey19", }, { Id: 237, Hex: "#3a3a3a", Rgb: Rgb{58, 58, 58}, Hsl: Hsl{0, 0, 22}, Name: "Grey23", }, { Id: 238, Hex: "#444444", Rgb: Rgb{68, 68, 68}, Hsl: Hsl{0, 0, 26}, Name: "Grey27", }, { Id: 239, Hex: "#4e4e4e", Rgb: Rgb{78, 78, 78}, Hsl: Hsl{0, 0, 30}, Name: "Grey30", }, { Id: 240, Hex: "#585858", Rgb: Rgb{88, 88, 88}, Hsl: Hsl{0, 0, 34}, Name: "Grey35", }, { Id: 241, Hex: "#626262", Rgb: Rgb{98, 98, 98}, Hsl: Hsl{0, 0, 37}, Name: "Grey39", }, { Id: 242, Hex: "#6c6c6c", Rgb: Rgb{108, 108, 108}, Hsl: Hsl{0, 0, 40}, Name: "Grey42", }, { Id: 243, Hex: "#767676", Rgb: Rgb{118, 118, 118}, Hsl: Hsl{0, 0, 46}, Name: "Grey46", }, { Id: 244, Hex: "#808080", Rgb: Rgb{128, 128, 128}, Hsl: Hsl{0, 0, 50}, Name: "Grey50", }, { Id: 245, Hex: "#8a8a8a", Rgb: Rgb{138, 138, 138}, Hsl: Hsl{0, 0, 54}, Name: "Grey54", }, { Id: 246, Hex: "#949494", Rgb: Rgb{148, 148, 148}, Hsl: Hsl{0, 0, 58}, Name: "Grey58", }, { Id: 247, Hex: "#9e9e9e", Rgb: Rgb{158, 158, 158}, Hsl: Hsl{0, 0, 61}, Name: "Grey62", }, { Id: 248, Hex: "#a8a8a8", Rgb: Rgb{168, 168, 168}, Hsl: Hsl{0, 0, 65}, Name: "Grey66", }, { Id: 249, Hex: "#b2b2b2", Rgb: Rgb{178, 178, 178}, Hsl: Hsl{0, 0, 69}, Name: "Grey70", }, { Id: 250, Hex: "#bcbcbc", Rgb: Rgb{188, 188, 188}, Hsl: Hsl{0, 0, 73}, Name: "Grey74", }, { Id: 251, Hex: "#c6c6c6", Rgb: Rgb{198, 198, 198}, Hsl: Hsl{0, 0, 77}, Name: "Grey78", }, { Id: 252, Hex: "#d0d0d0", Rgb: Rgb{208, 208, 208}, Hsl: Hsl{0, 0, 81}, Name: "Grey82", }, { Id: 253, Hex: "#dadada", Rgb: Rgb{218, 218, 218}, Hsl: Hsl{0, 0, 85}, Name: "Grey85", }, { Id: 254, Hex: "#e4e4e4", Rgb: Rgb{228, 228, 228}, Hsl: Hsl{0, 0, 89}, Name: "Grey89", }, { Id: 255, Hex: "#eeeeee", Rgb: Rgb{238, 238, 238}, Hsl: Hsl{0, 0, 93}, Name: "Grey93", }, } golang-github-leaanthony-go-ansi-parser-1.6.1/go.mod000066400000000000000000000001771520237347000223510ustar00rootroot00000000000000module github.com/leaanthony/go-ansi-parser go 1.16 require ( github.com/matryer/is v1.4.0 github.com/rivo/uniseg v0.2.0 ) golang-github-leaanthony-go-ansi-parser-1.6.1/go.sum000066400000000000000000000005041520237347000223700ustar00rootroot00000000000000github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= golang-github-leaanthony-go-ansi-parser-1.6.1/logo.png000066400000000000000000000241721520237347000227120ustar00rootroot00000000000000PNG  IHDRDPXPLTE333TTT­GGGfffppp555\\\888֘NNNxxx:::mmmiii|||JJJ@@@===444sssEEEdddYYYRRR```]]] VVVbbbBBB<<<Ϲ---󛛛[[[111'''###пʺ  Q%wIDATx`'(/:>ʵ@Q ĄH] A081ttq0q4qޗѽ/-\Υܣg(Á%""""""""""""""""""""""""""""""""""""""""""zR[+A-a825SߚY_ՋLC#w)Gʣfmp6;BD-Z$ljp;oUpO1[$\-ad"f bn QJb Q|~Z"A3O3p+DEc8@tG(tb QlbۀQDeU(F:E^_D1$M@(" $;VQl+$z/E ^QB(rS<(+D@nF ۔YAVbɂ[I?>GŘUSE N%vaZ Ÿjp$O2x Q}(`+)j'HKi(noEϪH\HY6L4pSH(b.l,OB۽`Sa(+FqhEYNHU+- 00R}ba9-6-^DN-t RbrZ)=~"lBD`9taz-`:RbRE[`y#:h90%ӣxˉRaM_K9EٚRekz$a)EqQ$z4;s.aJ%])1=K#uFK1 Q!,Oӣ(0GQ`9H(GV%(UE GhȜa/Y Q\eG!`;~yQDuQ<,QHbܓ("%cWL´& KB!QG/mx|3u @w`UA?\M"CXvH*fQf8 'RyeW$oD ("ud5(f̌[Pc6Orˎ]`8}!rW0^ɢwIMI3y8)5"=XHn lJYfYeS0<@c`ImTKAJMVuH tNhG0m_.gVT9hCoZ`{Dq$I9( VM،%)eY{K̀ ǩsF(ROfl X Ev[LĢ03$sV#YAT.`{GўTFYL6IOшbQTQ(M\lxFqtR1Evf~PZY10j3&QܣhD1 ˔FQEX|x ֟DqdRQEN XDѽm3{wmg9,)Dq0*b3GXNbŕ,9tW6`+57ˉFF"f,+ #> ObaFFQEE\X4)IŢ(($[=JED=eQ\~r6'qڜDQC4*"wv'bxK:+ZA/?k`DqZ(ړ/7[&Xi‹"ˤQ\sPj bڄwIEbx5E[,+Zh bQ{bD!DQvbV!&QAHXFB]DqCc(Wh<X_Gq lQa)Q̔.F%{]u}F%⿎bBf1Q4EQ,P@޺]F3 x6XD|QTa[[{Lg].#iqU׵MEA`y?Q%Q|(~khU8Z4ضVsbQ' ~G.9g`{EXQ;(їsՖwYGF6B˭ǯ# !,KEy[P0ai?|& (~e(p 9 `]BQBuK--bs6(v̴ 'D l籍-XMM~I`imXjU8jnKQlǯ`1O|{L<QLbjr:Q!.BMZ~˫c F'nQiV;ód2yM uREʋuur420(b>\΀׽]Hi\f',I摝}Փeg*f=4185ê[3}) F -XD'bmraG)(HSㇳ.\i!ϓS)W(ne%uA(&Y"Q<Т Mi&C_k +>H^2) ?k(W5ssQWr(Н"uތYE?9XGnhU^|D\ 'F.C"u"1854*t3qmOQ`TA{-Ӣj=4У&WɖFQ/ughKΙgR`F [WX٬Q\ rC3( 944*t介QMך fo0 Ll)P5&9i&S%IŪ$YNӏXv/M6P!:X+$W1F::uD>ǩRJ)RJ)RJ)RJk# ;un@{`l {m%WW%. )JQRb(E))JQRb(E))JQRb(E))JQRb(N ;H#E)JQR)JQRHQRGR8R(ő(E)(E)Jq(E)JQ#E)JQR)JQRHQRGR8R(ő(E)(E)Jq(E)JQ#E)JQR)JQRHQRGR8R(ő(E)(E)Jq(ةcA{QIQR)JQRHQRGR8R(ő(E)(E)Jq(E)JQ#E)JQR)JQRHQRGR8R={ym*8^r&:EARDD,YEp\gqӢHT,U Rl%4"Nbwn|#{1:|Q(r9E"GQ(r9EbDb83(T ZxqT$Ƨtm(z(.Ou]6@l.VQD1<-۩0r۴qP(;jF^@=Z9Q<].82> -jX G$"a6UZA$r4Mb")EVzk(.^d8*7S !1Ex5aj{bCQp]gRdwҰN(:0) /ZU-E1K_,#+8I-%Ei*ŋϟcQę*[(V}(J/PǦ+6r\4Ql, QA))KcP$(ͮ%(b0Zo(RvtMqKBKHHQ01Dq3Eqɇx9]U8DQ  qKT 2(_Maw{ng0/Dܱlѱo6iB#ŵHKȚ%G2"C׋߹~GtŽxs@q vDu6EϹ.D;FD@ c2h $80X{ DqF(fDQǑ(ڄ.l&Q$X+9ע8X?O1|ޣz0L Q<6sCڣkh@ p.D`O ݜ%9_o'o/Ff;xᰑ( ɠ1@(R쉢WjciQw>qk8``3QDMH&cE^lⵣf8"tdQ(>~ TI)DqHX.?3Q~gᮁ(ޢw%:w{D1p ɠ@(Ҭb߹.E55|ߝ(eD1pAhE5Q<հ%JtDс(^ k@(l\?Vh^Q?Q쑚"Fvq#K(v셃p5$ lbw,P;Wp–SneyXϨ29Ѣq<-wԒ⒜VH6DJuWM%ş[Yv-7v~O*(>(շNqG:MhQ rVM(GATM7FY6"~`ͲT*~y2oSk(op4Vu%\Y%QL`CbQrd9E۲ (߲rX1*k 8gD D1Q ݦ.NHc[QQ9uc0]w??~-SD<*ESgƻ*6p)JQRl(E)6FRn#E)JQ (ņHQRbm(E)J6Rp)JQRl(E)6FRn#E)JQ (ņHQRbm(E)J6Rp)JQRl(E)6FRn#E)JQ (ņHQRbm(E)J#~㑯G>~0)JQRl(ņ0)JQRl(ņ0)JQRl(ņ0)JQRl(ņ0)JQRl(ņ0)JQRl(ņ0)JQRl(ņ0)JQRl(ņ0)JQRl(ņ0)JQRl(ņ0)JQRl(ņ0)JQ?1E1H `w?¿]^""Rl(ņ0)JQRl(ņ0)JQRl(ņ0)JQRl(ņ0)JQRl(ņ0)JQRl(ņ0)JQRl(ņ0)JQRl(ņ0)JQRl(ņ0)JQRl(ņ0)JQRl(ņ0)JQRl(ņ}u|Oxw?1q?ץswcchm&߿.cCBlp1kfLۅneQg5!!!4V%/,SH6 wwl>^}N=w4E"IX+ڻx}Zq#)ӆ9bY+6$ĊKbtPxp+nq@1!z84C.k"Ӓ>PT,#zb2+I-7(~ubk|#Z3kU,RX=5ӊm]ޝņ[#YcstȻPmܐ0VM6(2-Ř(_sE=Fr=U \3v;/0?<Ң0C<*`%@<3QV *R (Kw!@qNpOx_SšէSf 5_vO#9Ns +̾ l( p_V EF..BⲰwb~hUWa%pu AZn_=%g{\.T(>=£Gr3 U1b%bIbif+-){7D(^P<\iPܔYLp460ӁšF6aObVW}}_SafS6Lvx9hP,Ⱝ ~LJ =%*\ྙ (láx.7q%@qn %> c`J'p:އjGvNe0 @c#- Q3l(B<+'-b\{؇E,E4A([wq/T(b<`M:LPz%xNE Q_\zy ΢1CphMђDQO(ie~8b&Q4VP,2IE,[p8eDPTFawjHכ b"5x_+=ph]%*GrFD1d4WQ((GB?7^l"ӘPx9 2a_ D-wu*áX=CbyssR8(+9aϱEhɢtE> Ϫ,#謃{<(]Jŭo !8E)]Q ϯ#G1m1+\w(-#=9 rE%=JĖ C(d@DvFBq:8"9#8v4Ks*2-QPѱîx$KB"+H(:ϞQ|[u_8 $Rx5NP, 89 L\Qlb(QLtp~E̽g=&(vٍb,Yp?+5.X[Vdc)8 PtɴH(V(b3n(r:%z(*b(澰EG!j7(b݋Gk+#Eb?.XgQ5Kb.PKIEܨQR/[.Fx6W(^U{YP,ٴ$q\ dE![:iB%Öҩ:KEBA@_,&b<3a-I-8&˱p)VXX),R}uJ^oZ_AZt?0}\Bd-{ _&܇:of(" RG"A4N?m$bhL~?cX#%ɨ⤸a&? s' g4;6mPK>dnHZ.H>䤹9q?y6K<ј|ȹ' O>pF] [8@ڰ+9]ɐ"@c%Er)ChU] Em$ra =ӋNjOhȥxn!E\\X_u[I1-CRH)é:z#<>I$) $$! ⓝ:&A?*xOHQRt(E)JqC:R!)JQRܐ(E)nHGR