From 376f0ebb245c0b87e6398456bddbdebd5fc2cd98 Mon Sep 17 00:00:00 2001 From: Mattias Wadman Date: Wed, 28 Sep 2022 15:44:16 +0200 Subject: [PATCH] gojq: Update rebased fq fork Also sync colorjson encoder with gojq encoder --- go.mod | 6 +- go.sum | 12 +- internal/colorjson/encoder.go | 205 ++++++++++++++++------------------ 3 files changed, 107 insertions(+), 116 deletions(-) diff --git a/go.mod b/go.mod index b39e920d..94374f62 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( // fork of github.com/itchyny/gojq, see github.com/wader/gojq fq branch - github.com/wader/gojq v0.12.1-0.20220822132002-64fe65a68424 + github.com/wader/gojq v0.12.1-0.20220928130353-e72ca4fd7c40 // fork of github.com/chzyer/readline, see github.com/wader/readline fq branch github.com/wader/readline v0.0.0-20220928125628-732951d41240 ) @@ -74,9 +74,9 @@ require ( ) require ( - github.com/itchyny/timefmt-go v0.1.3 // indirect + github.com/itchyny/timefmt-go v0.1.4 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect - golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect + golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect ) diff --git a/go.sum b/go.sum index 8c456ab5..25737e41 100644 --- a/go.sum +++ b/go.sum @@ -8,8 +8,8 @@ github.com/gomarkdown/markdown v0.0.0-20220627144906-e9a81102ebeb h1:5b/eFaSaKPF github.com/gomarkdown/markdown v0.0.0-20220627144906-e9a81102ebeb/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= github.com/gopacket/gopacket v0.0.0-20220819214934-ee81b8c880da h1:AAwDU9N39fQNYUtg270aiU6N7U2ZVsGZKiRwsCMsWEo= github.com/gopacket/gopacket v0.0.0-20220819214934-ee81b8c880da/go.mod h1:DlRRfaM/QjAu2ADqraIure1Eif0HpNL8hmyVQ+qci5Y= -github.com/itchyny/timefmt-go v0.1.3 h1:7M3LGVDsqcd0VZH2U+x393obrzZisp7C0uEe921iRkU= -github.com/itchyny/timefmt-go v0.1.3/go.mod h1:0osSSCQSASBJMsIZnhAaF1C2fCBTJZXrnj37mG8/c+A= +github.com/itchyny/timefmt-go v0.1.4 h1:hFEfWVdwsEi+CY8xY2FtgWHGQaBaC3JeHd+cve0ynVM= +github.com/itchyny/timefmt-go v0.1.4/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -23,8 +23,8 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWb github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/wader/gojq v0.12.1-0.20220822132002-64fe65a68424 h1:4SZxNA1ti22+TemKXy5H2qyFPPqi5X55vtyjmOnLsqk= -github.com/wader/gojq v0.12.1-0.20220822132002-64fe65a68424/go.mod h1:HM2cB+ANeJ4kBhxQp/4cNKewKjvYHACuCpBneQBgHkg= +github.com/wader/gojq v0.12.1-0.20220928130353-e72ca4fd7c40 h1:Njp3KQtQX2QBkCRA0OdnJl5wj0r9fQAVV6q3h1TOT4U= +github.com/wader/gojq v0.12.1-0.20220928130353-e72ca4fd7c40/go.mod h1:/+WKHSfP8sgyJDXeD9VjxlGjExGfjPUy0zm/Zy3Ind0= github.com/wader/readline v0.0.0-20220928125628-732951d41240 h1:fqNaldd6kVsMNGXLXH4TtB1kJtaPQOzGwqNYgswIM94= github.com/wader/readline v0.0.0-20220928125628-732951d41240/go.mod h1:Zgz8IJWvJoe7NK23CCPpC109XMCqJCpUhpHcnnA4XaM= golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 h1:GIAS/yBem/gq2MUqgNIzUHW7cJMmx3TGZOrnyYaNQ6c= @@ -34,8 +34,8 @@ golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2F golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E= golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/internal/colorjson/encoder.go b/internal/colorjson/encoder.go index 7535aa7f..7e628a78 100644 --- a/internal/colorjson/encoder.go +++ b/internal/colorjson/encoder.go @@ -1,8 +1,8 @@ -// This is gojq:s cli/encoder.go extract to be reusable and non-global color config +// Package colorjson is gojq:s cli/encoder.go extract to be reusable and have non-global color config // TODO: possible gojq can export it? // // The MIT License (MIT) -// Copyright (c) 2019-2021 itchyny +// Copyright (c) 2019-2022 itchyny // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -21,23 +21,17 @@ // 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. -// - -// skip errcheck to keep code similar to gojq version -// -//nolint:errcheck package colorjson import ( - "bufio" + "bytes" "fmt" "io" "math" "math/big" + "sort" "strconv" "unicode/utf8" - - "golang.org/x/exp/slices" ) type Colors struct { @@ -53,13 +47,14 @@ type Colors struct { } type Encoder struct { - w *bufio.Writer - wErr error + out io.Writer + w *bytes.Buffer + tab bool + indent int + depth int + buf [64]byte + color bool - tab bool - indent int - depth int - buf [64]byte valueFn func(v any) any colors Colors } @@ -67,6 +62,7 @@ type Encoder struct { func NewEncoder(color bool, tab bool, indent int, valueFn func(v any) any, colors Colors) *Encoder { // reuse the buffer in multiple calls of marshal return &Encoder{ + w: new(bytes.Buffer), color: color, tab: tab, indent: indent, @@ -75,16 +71,22 @@ func NewEncoder(color bool, tab bool, indent int, valueFn func(v any) any, color } } -func (e *Encoder) Marshal(v any, w io.Writer) error { - e.w = bufio.NewWriter(w) - e.encode(v) - if e.wErr != nil { - return e.wErr - } - return e.w.Flush() +func (e *Encoder) flush() error { + _, err := e.out.Write(e.w.Bytes()) + e.w.Reset() + return err } -func (e *Encoder) encode(v any) { +func (e *Encoder) Marshal(v interface{}, w io.Writer) error { + e.out = w + err := e.encode(v) + if ferr := e.flush(); ferr != nil && err == nil { + err = ferr + } + return err +} + +func (e *Encoder) encode(v interface{}) error { switch v := v.(type) { case nil: e.write([]byte("null"), e.colors.Null) @@ -102,18 +104,26 @@ func (e *Encoder) encode(v any) { e.write(v.Append(e.buf[:0], 10), e.colors.Number) case string: e.encodeString(v, e.colors.String) - case []any: - e.encodeArray(v) - case map[string]any: - e.encodeMap(v) + case []interface{}: + if err := e.encodeArray(v); err != nil { + return err + } + case map[string]interface{}: + if err := e.encodeMap(v); err != nil { + return err + } default: if e.valueFn != nil { v = e.valueFn(v) } else { - panic(fmt.Sprintf("invalid value: %#+v", v)) + panic(fmt.Sprintf("invalid type: %[1]T (%[1]v)", v)) } - e.encode(v) + return e.encode(v) } + if e.w.Len() > 8*1024 { + return e.flush() + } + return nil } // ref: floatEncoder in encoding/json @@ -144,37 +154,38 @@ func (e *Encoder) encodeFloat64(f float64) { // ref: encodeState#string in encoding/json func (e *Encoder) encodeString(s string, color []byte) { - if e.color { - e.w.Write(color) + if color != nil { + e.setColor(e.w, color) } e.w.WriteByte('"') start := 0 for i := 0; i < len(s); { if b := s[i]; b < utf8.RuneSelf { - if ']' <= b && b <= '~' || '#' <= b && b <= '[' || b == ' ' || b == '!' { + if ' ' <= b && b <= '~' && b != '"' && b != '\\' { i++ continue } if start < i { e.w.WriteString(s[start:i]) } - e.w.WriteByte('\\') switch b { - case '\\', '"': - e.w.WriteByte(b) + case '"': + e.w.WriteString(`\"`) + case '\\': + e.w.WriteString(`\\`) case '\b': - e.w.WriteByte('b') + e.w.WriteString(`\b`) case '\f': - e.w.WriteByte('f') + e.w.WriteString(`\f`) case '\n': - e.w.WriteByte('n') + e.w.WriteString(`\n`) case '\r': - e.w.WriteByte('r') + e.w.WriteString(`\r`) case '\t': - e.w.WriteByte('t') + e.w.WriteString(`\t`) default: const hex = "0123456789abcdef" - e.w.WriteString("u00") + e.w.WriteString(`\u00`) e.w.WriteByte(hex[b>>4]) e.w.WriteByte(hex[b&0xF]) } @@ -198,40 +209,39 @@ func (e *Encoder) encodeString(s string, color []byte) { e.w.WriteString(s[start:]) } e.w.WriteByte('"') - if e.color { - e.w.Write(e.colors.Reset) + if color != nil { + e.setColor(e.w, e.colors.Reset) } } -func (e *Encoder) encodeArray(vs []any) { +func (e *Encoder) encodeArray(vs []interface{}) error { e.writeByte('[', e.colors.Array) e.depth += e.indent for i, v := range vs { - if e.wErr != nil { - return - } - if i > 0 { e.writeByte(',', e.colors.Array) } if e.indent != 0 { e.writeIndent() } - e.encode(v) + if err := e.encode(v); err != nil { + return err + } } e.depth -= e.indent if len(vs) > 0 && e.indent != 0 { e.writeIndent() } e.writeByte(']', e.colors.Array) + return nil } -func (e *Encoder) encodeMap(vs map[string]any) { +func (e *Encoder) encodeMap(vs map[string]interface{}) error { e.writeByte('{', e.colors.Object) e.depth += e.indent type keyVal struct { key string - val any + val interface{} } kvs := make([]keyVal, len(vs)) var i int @@ -239,12 +249,10 @@ func (e *Encoder) encodeMap(vs map[string]any) { kvs[i] = keyVal{k, v} i++ } - slices.SortFunc(kvs, func(a, b keyVal) bool { return a.key < b.key }) + sort.Slice(kvs, func(i, j int) bool { + return kvs[i].key < kvs[j].key + }) for i, kv := range kvs { - if e.wErr != nil { - return - } - if i > 0 { e.writeByte(',', e.colors.Object) } @@ -256,82 +264,65 @@ func (e *Encoder) encodeMap(vs map[string]any) { if e.indent != 0 { e.w.WriteByte(' ') } - e.encode(kv.val) + if err := e.encode(kv.val); err != nil { + return err + } } e.depth -= e.indent if len(vs) > 0 && e.indent != 0 { e.writeIndent() } e.writeByte('}', e.colors.Object) + return nil } func (e *Encoder) writeIndent() { e.w.WriteByte('\n') if n := e.depth; n > 0 { if e.tab { - const tabs = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" - for n > len(tabs) { - e.w.Write([]byte(tabs)) - n -= len(tabs) - } - e.w.Write([]byte(tabs)[:n]) + e.writeIndentInternal(n, "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t") } else { - const spaces = " " - for n > len(spaces) { - e.w.Write([]byte(spaces)) - n -= len(spaces) + e.writeIndentInternal(n, " ") + } + } +} + +func (e *Encoder) writeIndentInternal(n int, spaces string) { + if l := len(spaces); n <= l { + e.w.WriteString(spaces[:n]) + } else { + e.w.WriteString(spaces) + for n -= l; n > 0; n, l = n-l, l*2 { + if n < l { + l = n } - e.w.Write([]byte(spaces)[:n]) + e.w.Write(e.w.Bytes()[e.w.Len()-l:]) } } } func (e *Encoder) writeByte(b byte, color []byte) { - if e.wErr != nil { - return - } if color == nil { - if err := e.w.WriteByte(b); err != nil { - e.wErr = err - } + e.w.WriteByte(b) } else { - if e.color { - if _, err := e.w.Write(color); err != nil { - e.wErr = err - } - } - if err := e.w.WriteByte(b); err != nil { - e.wErr = err - } - if e.color { - if _, err := e.w.Write(e.colors.Reset); err != nil { - e.wErr = err - } - } + e.setColor(e.w, color) + e.w.WriteByte(b) + e.setColor(e.w, e.colors.Reset) } } func (e *Encoder) write(bs []byte, color []byte) { - if e.wErr != nil { - return - } if color == nil { - if _, err := e.w.Write(bs); err != nil { - e.wErr = err - } + e.w.Write(bs) } else { - if e.color { - if _, err := e.w.Write(color); err != nil { - e.wErr = err - } - } - if _, err := e.w.Write(bs); err != nil { - e.wErr = err - } - if e.color { - if _, err := e.w.Write(e.colors.Reset); err != nil { - e.wErr = err - } - } + e.setColor(e.w, color) + e.w.Write(bs) + e.setColor(e.w, e.colors.Reset) + } +} + +func (e *Encoder) setColor(buf *bytes.Buffer, color []byte) { + if e.color { + buf.Write(color) } }