Skip to content

Commit

Permalink
fix(text): style multiline value before rendering
Browse files Browse the repository at this point in the history
Fixes: cddf0df ("fix(text) escape value before rendering styles (#20)")
  • Loading branch information
aymanbagabas committed Feb 27, 2023
1 parent 761ad44 commit cc3834d
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 56 deletions.
42 changes: 22 additions & 20 deletions text.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package log

import (
"bytes"
"fmt"
"io"
"strings"
Expand All @@ -23,7 +22,11 @@ func (l *logger) writeIndent(w io.Writer, str string, indent string, newline boo
if nl == -1 {
if str != "" {
_, _ = w.Write([]byte(indent))
l.writeEscapedForOutput(w, str, false)
val := escapeStringForOutput(str, false)
if !l.noStyles {
val = ValueStyle.Render(val)
}
_, _ = w.Write([]byte(val))
if newline {
_, _ = w.Write([]byte{'\n'})
}
Expand All @@ -32,7 +35,11 @@ func (l *logger) writeIndent(w io.Writer, str string, indent string, newline boo
}

_, _ = w.Write([]byte(indent))
l.writeEscapedForOutput(w, str[:nl], false)
val := escapeStringForOutput(str[:nl], false)
if !l.noStyles {
val = ValueStyle.Render(val)
}
_, _ = w.Write([]byte(val))
_, _ = w.Write([]byte{'\n'})
str = str[nl+1:]
}
Expand All @@ -54,21 +61,17 @@ const (

var bufPool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
return new(strings.Builder)
},
}

func (l *logger) writeEscapedForOutput(w io.Writer, str string, escapeQuotes bool) {
func escapeStringForOutput(str string, escapeQuotes bool) string {
// kindly borrowed from hclog
if !needsEscaping(str) {
if !l.noStyles {
str = ValueStyle.Render(str)
}
_, _ = w.Write([]byte(str))
return
return str
}

bb := bufPool.Get().(*bytes.Buffer)
bb := bufPool.Get().(*strings.Builder)
bb.Reset()

defer bufPool.Put(bb)
Expand Down Expand Up @@ -118,12 +121,7 @@ func (l *logger) writeEscapedForOutput(w io.Writer, str string, escapeQuotes boo
}
}

s := bb.String()
if !l.noStyles {
s = ValueStyle.Render(s)
}

_, _ = w.Write([]byte(s))
return bb.String()
}

// isNormal indicates if the rune is one allowed to exist as an unquoted
Expand Down Expand Up @@ -235,9 +233,13 @@ func (l *logger) textFormatter(keyvals ...interface{}) {
l.b.WriteByte(' ')
l.b.WriteString(key)
l.b.WriteString(sep)
l.b.WriteByte('"')
l.writeEscapedForOutput(&l.b, val, true)
l.b.WriteByte('"')
if !l.noStyles {
l.b.WriteString(ValueStyle.Render(fmt.Sprintf(`"%s"`,
escapeStringForOutput(val, true))))
} else {
l.b.WriteString(fmt.Sprintf(`"%s"`,
escapeStringForOutput(val, true)))
}
} else {
if !l.noStyles {
val = ValueStyle.Render(val)
Expand Down
74 changes: 38 additions & 36 deletions text_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ func TestTextValueStyles(t *testing.T) {
var buf bytes.Buffer
logger := New(WithOutput(&buf)).(*logger)
logger.noStyles = false
oldValueStyle := ValueStyle
defer func() { ValueStyle = oldValueStyle }()
ValueStyle = lipgloss.NewStyle().Bold(true)
cases := []struct {
name string
Expand All @@ -244,7 +246,7 @@ func TestTextValueStyles(t *testing.T) {
}{
{
name: "simple message",
expected: fmt.Sprintf("%s info\n", InfoLevelStyle.Render("INFO")),
expected: fmt.Sprintf("%s info\n", InfoLevelStyle),
msg: "info",
kvs: nil,
f: logger.Info,
Expand All @@ -260,9 +262,9 @@ func TestTextValueStyles(t *testing.T) {
name: "message with keyvals",
expected: fmt.Sprintf(
"%s info %s%s%s %s%s%s\n",
InfoLevelStyle.Render("INFO"),
KeyStyle.Render("key1"), SeparatorStyle.Render("="), ValueStyle.Render("val1"),
KeyStyle.Render("key2"), SeparatorStyle.Render("="), ValueStyle.Render("val2"),
InfoLevelStyle,
KeyStyle.Render("key1"), SeparatorStyle.Render(separator), ValueStyle.Render("val1"),
KeyStyle.Render("key2"), SeparatorStyle.Render(separator), ValueStyle.Render("val2"),
),
msg: "info",
kvs: []interface{}{"key1", "val1", "key2", "val2"},
Expand All @@ -272,10 +274,10 @@ func TestTextValueStyles(t *testing.T) {
name: "error message with multiline",
expected: fmt.Sprintf(
"%s info\n %s%s\n%s%s\n%s%s\n",
ErrorLevelStyle.Render("ERRO"),
KeyStyle.Render("key1"), SeparatorStyle.Render("="),
SeparatorStyle.Render(" │ "), ValueStyle.Render("val1"),
SeparatorStyle.Render(" │ "), ValueStyle.Render("val2"),
ErrorLevelStyle,
KeyStyle.Render("key1"), SeparatorStyle.Render(separator),
SeparatorStyle.Render(indentSeparator), ValueStyle.Render("val1"),
SeparatorStyle.Render(indentSeparator), ValueStyle.Render("val2"),
),
msg: "info",
kvs: []interface{}{"key1", "val1\nval2"},
Expand All @@ -285,9 +287,9 @@ func TestTextValueStyles(t *testing.T) {
name: "error message with keyvals",
expected: fmt.Sprintf(
"%s info %s%s%s %s%s%s\n",
ErrorLevelStyle.Render("ERRO"),
KeyStyle.Render("key1"), SeparatorStyle.Render("="), ValueStyle.Render("val1"),
KeyStyle.Render("key2"), SeparatorStyle.Render("="), ValueStyle.Render("val2"),
ErrorLevelStyle,
KeyStyle.Render("key1"), SeparatorStyle.Render(separator), ValueStyle.Render("val1"),
KeyStyle.Render("key2"), SeparatorStyle.Render(separator), ValueStyle.Render("val2"),
),
msg: "info",
kvs: []interface{}{"key1", "val1", "key2", "val2"},
Expand All @@ -296,11 +298,11 @@ func TestTextValueStyles(t *testing.T) {
{
name: "odd number of keyvals",
expected: fmt.Sprintf(
"%s info %s%s%s %s%s%s %s%s\"%s\"\n",
ErrorLevelStyle.Render("ERRO"),
KeyStyle.Render("key1"), SeparatorStyle.Render("="), ValueStyle.Render("val1"),
KeyStyle.Render("key2"), SeparatorStyle.Render("="), ValueStyle.Render("val2"),
KeyStyle.Render("key3"), SeparatorStyle.Render("="), ValueStyle.Render("missing value"),
"%s info %s%s%s %s%s%s %s%s%s\n",
ErrorLevelStyle,
KeyStyle.Render("key1"), SeparatorStyle.Render(separator), ValueStyle.Render("val1"),
KeyStyle.Render("key2"), SeparatorStyle.Render(separator), ValueStyle.Render("val2"),
KeyStyle.Render("key3"), SeparatorStyle.Render(separator), ValueStyle.Render(`"missing value"`),
),
msg: "info",
kvs: []interface{}{"key1", "val1", "key2", "val2", "key3"},
Expand All @@ -309,9 +311,9 @@ func TestTextValueStyles(t *testing.T) {
{
name: "error field",
expected: fmt.Sprintf(
"%s info %s%s\"%s\"\n",
ErrorLevelStyle.Render("ERRO"),
KeyStyle.Render("key1"), SeparatorStyle.Render("="), ValueStyle.Render("error value"),
"%s info %s%s%s\n",
ErrorLevelStyle,
KeyStyle.Render("key1"), SeparatorStyle.Render(separator), ValueStyle.Render(`"error value"`),
),
msg: "info",
kvs: []interface{}{"key1", errors.New("error value")},
Expand All @@ -321,8 +323,8 @@ func TestTextValueStyles(t *testing.T) {
name: "struct field",
expected: fmt.Sprintf(
"%s info %s%s%s\n",
InfoLevelStyle.Render("INFO"),
KeyStyle.Render("key1"), SeparatorStyle.Render("="), ValueStyle.Render("{foo:bar}"),
InfoLevelStyle,
KeyStyle.Render("key1"), SeparatorStyle.Render(separator), ValueStyle.Render("{foo:bar}"),
),
msg: "info",
kvs: []interface{}{"key1", struct{ foo string }{foo: "bar"}},
Expand All @@ -331,9 +333,9 @@ func TestTextValueStyles(t *testing.T) {
{
name: "struct field quoted",
expected: fmt.Sprintf(
"%s info %s%s\"%s\"\n",
InfoLevelStyle.Render("INFO"),
KeyStyle.Render("key1"), SeparatorStyle.Render("="), ValueStyle.Render("{foo:bar baz}"),
"%s info %s%s%s\n",
InfoLevelStyle,
KeyStyle.Render("key1"), SeparatorStyle.Render(separator), ValueStyle.Render(`"{foo:bar baz}"`),
),
msg: "info",
kvs: []interface{}{"key1", struct{ foo string }{foo: "bar baz"}},
Expand All @@ -342,9 +344,9 @@ func TestTextValueStyles(t *testing.T) {
{
name: "slice of strings",
expected: fmt.Sprintf(
"%s info %s%s\"%s\"\n",
ErrorLevelStyle.Render("ERRO"),
KeyStyle.Render("key1"), SeparatorStyle.Render("="), ValueStyle.Render("[foo bar]"),
"%s info %s%s%s\n",
ErrorLevelStyle,
KeyStyle.Render("key1"), SeparatorStyle.Render(separator), ValueStyle.Render(`"[foo bar]"`),
),
msg: "info",
kvs: []interface{}{"key1", []string{"foo", "bar"}},
Expand All @@ -353,9 +355,9 @@ func TestTextValueStyles(t *testing.T) {
{
name: "slice of structs",
expected: fmt.Sprintf(
"%s info %s%s\"%s\"\n",
ErrorLevelStyle.Render("ERRO"),
KeyStyle.Render("key1"), SeparatorStyle.Render("="), ValueStyle.Render("[{foo:bar} {foo:baz}]"),
"%s info %s%s%s\n",
ErrorLevelStyle,
KeyStyle.Render("key1"), SeparatorStyle.Render(separator), ValueStyle.Render(`"[{foo:bar} {foo:baz}]"`),
),
msg: "info",
kvs: []interface{}{"key1", []struct{ foo string }{{foo: "bar"}, {foo: "baz"}}},
Expand All @@ -364,9 +366,9 @@ func TestTextValueStyles(t *testing.T) {
{
name: "slice of errors",
expected: fmt.Sprintf(
"%s info %s%s\"%s\"\n",
ErrorLevelStyle.Render("ERRO"),
KeyStyle.Render("key1"), SeparatorStyle.Render("="), ValueStyle.Render("[error value1 error value2]"),
"%s info %s%s%s\n",
ErrorLevelStyle,
KeyStyle.Render("key1"), SeparatorStyle.Render(separator), ValueStyle.Render(`"[error value1 error value2]"`),
),
msg: "info",
kvs: []interface{}{"key1", []error{errors.New("error value1"), errors.New("error value2")}},
Expand All @@ -375,9 +377,9 @@ func TestTextValueStyles(t *testing.T) {
{
name: "map of strings",
expected: fmt.Sprintf(
"%s info %s%s\"%s\"\n",
ErrorLevelStyle.Render("ERRO"),
KeyStyle.Render("key1"), SeparatorStyle.Render("="), ValueStyle.Render("map[baz:qux foo:bar]"),
"%s info %s%s%s\n",
ErrorLevelStyle,
KeyStyle.Render("key1"), SeparatorStyle.Render(separator), ValueStyle.Render(`"map[baz:qux foo:bar]"`),
),
msg: "info",
kvs: []interface{}{"key1", map[string]string{"foo": "bar", "baz": "qux"}},
Expand Down

0 comments on commit cc3834d

Please sign in to comment.