summaryrefslogtreecommitdiffstats
path: root/modules/log/colors.go
diff options
context:
space:
mode:
Diffstat (limited to 'modules/log/colors.go')
-rw-r--r--modules/log/colors.go66
1 files changed, 63 insertions, 3 deletions
diff --git a/modules/log/colors.go b/modules/log/colors.go
index ed6477d431..0ec8ce4ba8 100644
--- a/modules/log/colors.go
+++ b/modules/log/colors.go
@@ -7,6 +7,7 @@ package log
import (
"fmt"
"io"
+ "reflect"
"strconv"
"strings"
)
@@ -195,11 +196,12 @@ normalLoop:
lasti := i
if c.mode == escapeAll {
- for i < end && (bytes[i] >= ' ' || bytes[i] == '\n') {
+ for i < end && (bytes[i] >= ' ' || bytes[i] == '\n' || bytes[i] == '\t') {
i++
}
} else {
- for i < end && bytes[i] >= ' ' {
+ // Allow tabs if we're not escaping everything
+ for i < end && (bytes[i] >= ' ' || bytes[i] == '\t') {
i++
}
}
@@ -266,6 +268,39 @@ normalLoop:
return totalWritten, nil
}
+// ColorSprintf returns a colored string from a format and arguments
+// arguments will be wrapped in ColoredValues to protect against color spoofing
+func ColorSprintf(format string, args ...interface{}) string {
+ if len(args) > 0 {
+ v := make([]interface{}, len(args))
+ for i := 0; i < len(v); i++ {
+ v[i] = NewColoredValuePointer(&args[i])
+ }
+ return fmt.Sprintf(format, v...)
+ }
+ return fmt.Sprintf(format)
+}
+
+// ColorFprintf will write to the provided writer similar to ColorSprintf
+func ColorFprintf(w io.Writer, format string, args ...interface{}) (int, error) {
+ if len(args) > 0 {
+ v := make([]interface{}, len(args))
+ for i := 0; i < len(v); i++ {
+ v[i] = NewColoredValuePointer(&args[i])
+ }
+ return fmt.Fprintf(w, format, v...)
+ }
+ return fmt.Fprintf(w, format)
+}
+
+// ColorFormatted structs provide their own colored string when formatted with ColorSprintf
+type ColorFormatted interface {
+ // ColorFormat provides the colored representation of the value
+ ColorFormat(s fmt.State)
+}
+
+var colorFormattedType = reflect.TypeOf((*ColorFormatted)(nil)).Elem()
+
// ColoredValue will Color the provided value
type ColoredValue struct {
colorBytes *[]byte
@@ -316,8 +351,33 @@ func NewColoredValueBytes(value interface{}, colorBytes *[]byte) *ColoredValue {
}
}
-// Format will format the provided value and protect against ANSI spoofing within the value
+// NewColoredIDValue is a helper function to create a ColoredValue from a Value
+// The Value will be colored with FgCyan
+// If a ColoredValue is provided it is not changed
+func NewColoredIDValue(value interface{}) *ColoredValue {
+ return NewColoredValueBytes(&value, &fgCyanBytes)
+}
+
+// Format will format the provided value and protect against ANSI color spoofing within the value
+// If the wrapped value is ColorFormatted and the format is "%-v" then its ColorString will
+// be used. It is presumed that this ColorString is safe.
func (cv *ColoredValue) Format(s fmt.State, c rune) {
+ if c == 'v' && s.Flag('-') {
+ if val, ok := (*cv.Value).(ColorFormatted); ok {
+ val.ColorFormat(s)
+ return
+ }
+ v := reflect.ValueOf(*cv.Value)
+ t := v.Type()
+
+ if reflect.PtrTo(t).Implements(colorFormattedType) {
+ vp := reflect.New(t)
+ vp.Elem().Set(v)
+ val := vp.Interface().(ColorFormatted)
+ val.ColorFormat(s)
+ return
+ }
+ }
s.Write([]byte(*cv.colorBytes))
fmt.Fprintf(&protectedANSIWriter{w: s}, fmtString(s, c), *(cv.Value))
s.Write([]byte(*cv.resetBytes))