diff --git a/README.md b/README.md index 23abd47..bbf6a26 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ cfmt.Println("{{%s}}::flag ", flag) ### HEX colors -If the standard colors are not enough for you, then you can use the colors in the Hex format (note, not all consoles support all colors fully!). +If the standard colors are not enough for you, then you can use the colors in the `HEX` format (note, not all terminals support all colors fully!). ```go cfmt.Println("This is a {{red color}}::#ff0000") @@ -123,7 +123,7 @@ To set the background color, you need to add the prefix `bg` to the color, in th cfmt.Println("This is a {{red color}}::bgRed") ``` -For HEX it will look like this: +For `HEX` it will look like this: ```go cfmt.Println("This is a {{red color}}::bg#ff0000") @@ -178,16 +178,15 @@ cfmt.Print(` ## Supported colors and styles -| Styles | -| ------------------------------------------------------ | -| *italic* | -| **bold** | -| ~~crossout~~ | -| underline | -| overline | -|faint| -|reverse| -|blink| +| Styles | +| -------------------- | +| *italic* | +| **bold** | +| ~~crossout~~ | +| underline | +| concealed | +| reverse | +| blink | | Colors | | | | @@ -206,7 +205,7 @@ And colors in HEX format. See [HEX colors](#hex-colors) part. ## Motivation -The existing libraries for styling output are very powerful, and this library is built on two of them (gookit/color and muesli/termenv). However, they are not very convenient to use for styling specific words or sentences, since you need to use `Sprintf` and put the stylized into a format string, which greatly reduces readability if you need to style many elements. +The existing libraries for styling the output are very powerful and this library builds on one of them ([gookit / color] (https://github.com/gookit/color)). However, they are not very useful for styling certain words or sentences, since you need to use `Sprintf` and put the styled ones in a format string, which greatly reduces readability if you need to style many elements. I believe that the library will be useful primarily for formatting ready-made text, for reference or examples. However, in other cases it should be just as convenient. diff --git a/go.mod b/go.mod index 917d01f..21b731d 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,5 @@ module github.com/i582/cfmt go 1.15 require ( - github.com/google/go-cmp v0.5.3 github.com/gookit/color v1.3.2 - github.com/muesli/termenv v0.7.4 ) diff --git a/internal/bench/bench_test.go b/internal/bench/bench_test.go deleted file mode 100644 index 737a6ad..0000000 --- a/internal/bench/bench_test.go +++ /dev/null @@ -1,11 +0,0 @@ -package bench - -import ( - "testing" - - "github.com/i582/cfmt" -) - -func TestParse(t *testing.T) { - cfmt.Println("{{some}}::faint") -} diff --git a/internal/map.go b/internal/map.go index e1eb0a3..188f8d1 100644 --- a/internal/map.go +++ b/internal/map.go @@ -5,12 +5,7 @@ import ( ) // CustomMap is the custom styles map -var CustomMap = map[string]func(string) string{ - "overline": overline, - "faint": faint, - "reverse": reverse, - "blink": blink, -} +var CustomMap = map[string]func(string) string{} // Map is the styles map var Map = map[string]color.Color{ @@ -54,4 +49,7 @@ var Map = map[string]color.Color{ "italic": color.OpItalic, "crossout": color.OpStrikethrough, "underline": color.OpUnderscore, + "blink": color.OpBlink, + "reverse": color.OpReverse, + "concealed": color.OpConcealed, } diff --git a/internal/parser.go b/internal/parser.go index eae9310..81777bf 100644 --- a/internal/parser.go +++ b/internal/parser.go @@ -5,8 +5,8 @@ import ( "strings" ) -// Parse parses the passed format string and applies styles, returning a styled string. -func Parse(text string) string { +// ParseAndApply parses the passed format string and applies styles, returning a styled string. +func ParseAndApply(text string) string { var resParts = make([]string, 0, 50) var err error @@ -149,9 +149,9 @@ func Parse(text string) string { // text from :: or previous | to current | singleFormat := text[tempTokenStartIndex:tempTokenEndIndex] - lastToken, err = ApplyStyle(lastToken, singleFormat) + lastToken, err = applyStyle(lastToken, singleFormat) if err != nil { - log.Fatalf("Error parse style string in '%s' text string: %v", text, err) + log.Fatalf("Error parse style string in '%s' text string: %v", strings.ReplaceAll(text, "\n", "\\n"), err) } // index after | @@ -164,9 +164,9 @@ func Parse(text string) string { // last format singleFormat := text[tempTokenStartIndex:tempTokenEndIndex] - lastToken, err = ApplyStyle(lastToken, singleFormat) + lastToken, err = applyStyle(lastToken, singleFormat) if err != nil { - log.Fatalf("Error parse style string in '%s' text string: %v", text, err) + log.Fatalf("Error parse style string in '%s' text string: %v", strings.ReplaceAll(text, "\n", "\\n"), err) } tempTokenStartIndex = index @@ -192,9 +192,9 @@ func Parse(text string) string { if lastIsFormatGroup { singleFormat := text[tempTokenStartIndex:] - lastToken, err = ApplyStyle(lastToken, singleFormat) + lastToken, err = applyStyle(lastToken, singleFormat) if err != nil { - log.Fatalf("Error parse style string in '%s' text string: %v", text, err) + log.Fatalf("Error parse style string in '%s' text string: %v", strings.ReplaceAll(text, "\n", "\\n"), err) } resParts = append(resParts, lastToken) } else { diff --git a/internal/style.go b/internal/style.go index 236a88f..37bcc6c 100644 --- a/internal/style.go +++ b/internal/style.go @@ -3,6 +3,8 @@ package internal import ( "fmt" "strings" + + "github.com/gookit/color" ) // StyleBuilder is a function that returns a styled string based on the supplied style. @@ -13,7 +15,7 @@ func StyleBuilder(styles []string, text string) (string, error) { var err error for _, style := range styles { - text, err = ApplyStyle(text, style) + text, err = applyStyle(text, style) if err != nil { return "", err } @@ -22,14 +24,14 @@ func StyleBuilder(styles []string, text string) (string, error) { return text, nil } -// StyleBuilder is a function that apply a style for string. -func ApplyStyle(text, style string) (string, error) { +// applyStyle is a function that apply a style for string. +func applyStyle(text, style string) (string, error) { if isHex(style) { err := checkHex(style) if err != nil { return "", err } - text = hexForegroundColorFunc(style, text) + text = hexForegroundColor(style, text) return text, nil } @@ -39,7 +41,7 @@ func ApplyStyle(text, style string) (string, error) { if err != nil { return "", err } - text = hexBackgroundColorFunc(rawHex, text) + text = hexBackgroundColor(rawHex, text) return text, nil } @@ -47,7 +49,7 @@ func ApplyStyle(text, style string) (string, error) { if !ok { customStyleFunc, ok := CustomMap[style] if !ok { - return "", fmt.Errorf("unknown style %s", style) + return "", fmt.Errorf("unknown style '%s'", style) } text = customStyleFunc(text) return text, nil @@ -56,17 +58,27 @@ func ApplyStyle(text, style string) (string, error) { return clr.Sprint(text), nil } +func hexBackgroundColor(cl string, text string) string { + return color.HEX(cl, true).Sprint(text) +} + +func hexForegroundColor(cl string, text string) string { + return color.HEX(cl).Sprint(text) +} + func isHex(val string) bool { return strings.HasPrefix(val, "#") } +func isBackgroundHex(val string) bool { + return strings.HasPrefix(val, "bg#") +} + func checkHex(val string) error { - if len(val) != 7 { - return fmt.Errorf("invalid hex: length of hex color must be 6") + rgb := color.HexToRGB(val) + if len(rgb) > 0 { + return nil } - return nil -} -func isBackgroundHex(val string) bool { - return strings.HasPrefix(val, "bg#") + return fmt.Errorf("invalid '%s' hex color", val) } diff --git a/internal/styles.go b/internal/styles.go deleted file mode 100644 index 4a4842d..0000000 --- a/internal/styles.go +++ /dev/null @@ -1,47 +0,0 @@ -package internal - -import ( - "github.com/muesli/termenv" -) - -var colorProfile termenv.Profile - -func init() { - colorProfile = termenv.ColorProfile() -} - -func overline(text string) string { - out := termenv.String(text) - out = out.Overline() - return out.String() -} - -func reverse(text string) string { - out := termenv.String(text) - out = out.Reverse() - return out.String() -} - -func blink(text string) string { - out := termenv.String(text) - out = out.Blink() - return out.String() -} - -func faint(text string) string { - out := termenv.String(text) - out = out.Faint() - return out.String() -} - -func hexBackgroundColorFunc(cl string, text string) string { - out := termenv.String(text) - out = out.Background(colorProfile.Color(cl)) - return out.String() -} - -func hexForegroundColorFunc(cl string, text string) string { - out := termenv.String(text) - out = out.Foreground(colorProfile.Color(cl)) - return out.String() -} diff --git a/main.go b/main.go index fd9cdcd..6da40e9 100644 --- a/main.go +++ b/main.go @@ -25,8 +25,7 @@ func RegisterStyle(name string, fn func(string) string) { // Sprint is the same as fmt. func Sprint(a ...interface{}) string { text := fmt.Sprint(a...) - parsed := internal.Parse(text) - return parsed + return internal.ParseAndApply(text) } // Fprint is the same as fmt. @@ -59,8 +58,7 @@ func Println(a ...interface{}) (n int, err error) { // Sprintf is the same as fmt. func Sprintf(format string, a ...interface{}) string { text := fmt.Sprintf(format, a...) - parsed := internal.Parse(text) - return parsed + return internal.ParseAndApply(text) } // Fprintf is the same as fmt. @@ -76,12 +74,18 @@ func Printf(format string, a ...interface{}) (n int, err error) { // Fatalf is the same as fmt. func Fatalf(format string, a ...interface{}) { - Printf(format, a...) + _, _ = Printf(format, a...) os.Exit(1) } // Fatal is the same as fmt. func Fatal(a ...interface{}) { - Print(a...) + _, _ = Print(a...) + os.Exit(1) +} + +// Fatalln is the same as fmt. +func Fatalln(a ...interface{}) { + _, _ = Println(a...) os.Exit(1) } diff --git a/tests/parser_test.go b/tests/parser_test.go index 90670f0..e5cb7b2 100644 --- a/tests/parser_test.go +++ b/tests/parser_test.go @@ -25,11 +25,12 @@ func TestParse(t *testing.T) { cfmt.Println("{{こんにちは, correct group}}::code sdas") cfmt.Println("{{привет, correct group}}::red|underline and {{other}}::red") cfmt.Print("{{error group}} \n") - cfmt.Print("{{overline group}}::overline\n") + cfmt.Print("{{underline group}}::underline\n") cfmt.Print("{{reverse group, こんにちは}}::reverse\n") - cfmt.Print(cfmt.Sprintln("{{faint group}}::faint sfafs")) + cfmt.Print(cfmt.Sprintln("{{some group}}::red sfafs")) cfmt.Println(cfmt.Sprint("{{blink group}}::blink")) cfmt.Printf("{{hex %s}}::#ff00ff sfas\n", "color group") + cfmt.Printf("{{3 hex %s}}::#ff0 sfas\n", "color group") cfmt.Printf(cfmt.Sprintf("{{background color %s}}::bg#ffff00\n", "hex color")) cfmt.Printf("{{{hello}}}::red|underline\n") cfmt.Printf("{{some test struct: %v}}::red|underline\n", TestStruct{"hello", 1}) diff --git a/tests/style_test.go b/tests/style_test.go index 35d4e47..a5d69a1 100644 --- a/tests/style_test.go +++ b/tests/style_test.go @@ -3,8 +3,6 @@ package tests import ( "testing" - "github.com/google/go-cmp/cmp" - "github.com/i582/cfmt" "github.com/i582/cfmt/internal" ) @@ -41,20 +39,28 @@ func TestStyleBuilder(t *testing.T) { Error: "", }, { - Value: []string{"overline", "reverse", "faint"}, + Value: []string{"underline", "reverse"}, Error: "", }, { Value: []string{"bg#ff0", "bold"}, - Error: "invalid hex: length of hex color must be 6", + Error: "", }, { Value: []string{"#ff0", "bold"}, - Error: "invalid hex: length of hex color must be 6", + Error: "", + }, + { + Value: []string{"#ff01", "bold"}, + Error: "invalid '#ff01' hex color", + }, + { + Value: []string{"bg#ff01", "bold"}, + Error: "invalid '#ff01' hex color", }, { Value: []string{"some", "bold"}, - Error: "unknown style some", + Error: "unknown style 'some'", }, { Value: []string{}, @@ -65,12 +71,12 @@ func TestStyleBuilder(t *testing.T) { for _, suite := range suites { _, err := internal.StyleBuilder(suite.Value, "") if err == nil && suite.Error != "" { - t.Error(cmp.Diff("", suite.Error)) + t.Errorf("mismatch\nwant: ''\nhave: %s", suite.Error) continue } - if err != nil && !cmp.Equal(err.Error(), suite.Error) { - t.Error(cmp.Diff(err.Error(), suite.Error)) + if err != nil && err.Error() != suite.Error { + t.Errorf("mismatch\nwant: %s\nhave: %s", suite.Error, err.Error()) } } }