8000 Add colorization support for Hjson encoding by bingoohuang · Pull Request #64 · hjson/hjson-go · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add colorization support for Hjson encoding #64

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions color.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package hjson

// Style is the color style
type Style struct {
Key, String, Number [2]string
True, False, Null [2]string
Escape [2]string
Remark [2]string
Append func(dst []byte, c byte) []byte
}

// TerminalStyle is for terminals
var TerminalStyle *Style

func init() {
TerminalStyle = &Style{
Key: [2]string{"\x1B[94m", "\x1B[0m"},
String: [2]string{"\x1B[92m", "\x1B[0m"},
Number: [2]string{"\x1B[93m", "\x1B[0m"},
True: [2]string{"\x1B[96m", "\x1B[0m"},
False: [2]string{"\x1B[96m", "\x1B[0m"},
Null: [2]string{"\x1B[91m", "\x1B[0m"},
Escape: [2]string{"\x1B[35m", "\x1B[0m"},
Remark: [2]string{"\x1B[90m", "\x1B[0m"},
Append: func(dst []byte, c byte) []byte {
if c < ' ' && (c != '\r' && c != '\n' && c != '\t' && c != '\v') {
dst = append(dst, "\\u00"...)
dst = append(dst, hexp((c>>4)&0xF))
return append(dst, hexp((c)&0xF))
}
return append(dst, c)
},
}
}
func hexp(p byte) byte {
switch {
case p < 10:
return p + '0'
default:
return (p - 10) + 'a'
}
}
86 changes: 66 additions & 20 deletions encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ type EncoderOptions struct {
// Write comments, if any are found in hjson.Node structs or as tags on
// other structs.
Comments bool

// EnableColor enables colorized output
EnableColor bool
// ColorStyle is the style to use for colorized output
ColorStyle *Style
}

// DefaultOptions returns the default encoding options.
Expand All @@ -55,6 +60,8 @@ func DefaultOptions() EncoderOptions {
IndentBy: " ",
BaseIndentation: "",
Comments: true,
EnableColor: false,
ColorStyle: TerminalStyle,
}
}

Expand Down Expand Up @@ -123,14 +130,18 @@ func (e *hjsonEncoder) quoteForComment(cmStr string) bool {
return false
}

func (e *hjsonEncoder) quote(value string, separator string, isRootObject bool,
func (e *hjsonEncoder) quote(value, separator string, isRootObject bool,
keyComment string, hasCommentAfter bool) {

// Check if we can insert this string without quotes
// see hjson syntax (must not parse as true, false, null or number)
l, r := "", ""
if e.EnableColor {
l, r = e.ColorStyle.String[0], e.ColorStyle.String[1]
}

if len(value) == 0 {
e.WriteString(separator + `""`)
e.WriteString(separator + l + `""` + r)
} else if e.QuoteAlways ||
hasCommentAfter ||
needsQuotes.MatchString(value) ||
Expand All @@ -144,26 +155,27 @@ func (e *hjsonEncoder) quote(value string, separator string, isRootObject bool,
// sequences.

if !needsEscape.MatchString(value) {
e.WriteString(separator + `"` + value + `"`)

e.WriteString(separator + l + `"` + value + `"` + r)
} else if !needsEscapeML.MatchString(value) && !isRootObject {
e.mlString(value, separator, keyComment)
e.mlString(value, separator, keyComment, l, r)
} else {
e.WriteString(separator + `"` + e.quoteReplace(value) + `"`)
e.WriteString(separator + l + `"` + e.quoteReplace(value) + `"` + r)
}
} else {
// return without quotes
e.WriteString(separator + value)
e.WriteString(separator + l + value + r)
}
}

func (e *hjsonEncoder) mlString(value string, separator string, keyComment string) {
func (e *hjsonEncoder) mlString(value, separator, keyComment, lColor, rColor string) {
a := strings.Split(value, "\n")

if len(a) == 1 {
// The string contains only a single line. We still use the multiline
// format as it avoids escaping the \ character (e.g. when used in a
// regex).
e.WriteString(separator + "'''")
e.WriteString(separator + lColor + "'''")
e.WriteString(a[0])
} else {
if !strings.Contains(keyComment, "\n") {
Expand All @@ -176,11 +188,11 @@ func (e *hjsonEncoder) mlString(value string, separator string, keyComment strin
indent = 0
}
e.writeIndent(indent)
e.WriteString(v)
e.WriteString(lColor + v + rColor)
}
e.writeIndent(e.indent + 1)
}
e.WriteString("'''")
e.WriteString("'''" + rColor)
}

func (e *hjsonEncoder) quoteName(name string) string {
Expand Down Expand Up @@ -279,6 +291,14 @@ func (e *hjsonEncoder) unpackNode(value reflect.Value, cm Comments) (reflect.Val
return value, cm
}

func (e *hjsonEncoder) writeNull() {
l, r := "", ""
if e.EnableColor {
l, r = e.ColorStyle.Null[0], e.ColorStyle.Null[1]
}
e.WriteString(l + "null" + r)
}

// This function can often be called from within itself, so do not output
// anything from the upper half of it.
func (e *hjsonEncoder) str(
Expand Down Expand Up @@ -319,14 +339,14 @@ func (e *hjsonEncoder) str(

if !value.IsValid() {
e.WriteString(separator)
e.WriteString("null")
e.writeNull()
return nil
}

if kind == reflect.Interface || kind == reflect.Ptr {
if value.IsNil() {
e.WriteString(separator)
e.WriteString("null")
e.writeNull()
return nil
}
return e.str(value.Elem(), noIndent, separator, isRootObject, isObjElement, cm)
Expand Down Expand Up @@ -367,46 +387,72 @@ func (e *hjsonEncoder) str(
if n == "" {
n = "0"
}
e.WriteString(separator)

l, r := "", ""
if e.EnableColor {
l, r = e.ColorStyle.Number[0], e.ColorStyle.Number[1]
}
// without quotes
e.WriteString(separator + n)
e.WriteString(l + n + r)
} else {
e.quote(value.String(), separator, isRootObject, cm.Key,
e.quoteForComment(cm.After))
}

case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
e.WriteString(separator)
e.WriteString(strconv.FormatInt(value.Int(), 10))
l, r := "", ""
if e.EnableColor {
l, r = e.ColorStyle.Number[0], e.ColorStyle.Number[1]
}
e.WriteString(l + strconv.FormatInt(value.Int(), 10) + r)

case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Uintptr:
e.WriteString(separator)
e.WriteString(strconv.FormatUint(value.Uint(), 10))
l, r := "", ""
if e.EnableColor {
l, r = e.ColorStyle.Number[0], e.ColorStyle.Number[1]
}
e.WriteString(l + strconv.FormatUint(value.Uint(), 10) + r)

case reflect.Float32, reflect.Float64:
// JSON numbers must be finite. Encode non-finite numbers as null.
e.WriteString(separator)
number := value.Float()
l, r := "", ""
if e.EnableColor {
l, r = e.ColorStyle.Number[0], e.ColorStyle.Number[1]
}
if math.IsInf(number, 0) || math.IsNaN(number) {
e.WriteString("null")
e.writeNull()
} else if number == -0 {
e.WriteString("0")
e.WriteString(l + "0" + r)
} else {
// find shortest representation ('G' does not work)
val := strconv.FormatFloat(number, 'f', -1, 64)
exp := strconv.FormatFloat(number, 'E', -1, 64)
if len(exp) < len(val) {
val = strings.ToLower(exp)
}
e.WriteString(val)

e.WriteString(l + val + r)
}

case reflect.Bool:
e.WriteString(separator)
l, r := "", ""
if value.Bool() {
e.WriteString("true")
if e.EnableColor {
l, r = e.ColorStyle.True[0], e.ColorStyle.True[1]
}
e.WriteString(l + "true" + r)
} else {
e.WriteString("false")
if e.EnableColor {
l, r = e.ColorStyle.False[0], e.ColorStyle.False[1]
}
e.WriteString(l + "false" + r)
}

case reflect.Slice, reflect.Array:
Expand Down
12 changes: 10 additions & 2 deletions structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,15 +299,23 @@ func (e *hjsonEncoder) writeFields(
if len(fi.comment) > 0 {
for _, line := range strings.Split(fi.comment, e.Eol) {
e.writeIndentNoEOL(e.indent)
e.WriteString(fmt.Sprintf("# %s\n", line))
l, r := "", ""
if e.EnableColor {
l, r = e.ColorStyle.Remark[0], e.ColorStyle.Remark[1]
}
e.WriteString(fmt.Sprintf("%s# %s%s\n", l, line, r))
}
}
if elemCm.Before == "" {
e.writeIndentNoEOL(e.indent)
} else {
e.WriteString(elemCm.Before)
}
e.WriteString(e.quoteName(fi.name))
l, r := "", ""
if e.EnableColor {
l, r = e.ColorStyle.Key[0], e.ColorStyle.Key[1]
}
e.WriteString(l + e.quoteName(fi.name) + r)
e.WriteString(":")
e.WriteString(elemCm.Key)

Expand Down
0