1
1
mirror of https://github.com/wader/fq.git synced 2024-11-27 14:14:58 +03:00
fq/pkg/interp/decorator.go
Mattias Wadman 7c5215347d bitio,decode: Refactor bitio usage and make buffer slicing more correct
Remove bitio.Buffer layer. bitio.Buffer was a kitchen sink layer with helpers
now it's just a buffer and most functions have been moved to decode instead.

bitio package now only have primitive types and functions simialar to standard
library io and bytes packages.

Make nearly eveything internally use bitio.Bit* interfaces so that slicing work
correctly this will also make it possible to start experimenting with more
complicated silcing helpers, ex things like:
breplace(.header.bitrate; 123) to get a new buffer with bitrate changed.
2022-02-04 21:41:53 +01:00

176 lines
3.9 KiB
Go

package interp
import (
"log"
"math/big"
"strconv"
"strings"
"github.com/wader/fq/internal/ansi"
"github.com/wader/fq/pkg/bitio"
)
type stringRanges struct {
rs [][2]int
s string
}
func atoi(s string) int {
n, _ := strconv.ParseUint(s, 0, 64)
return int(n)
}
// 0-255=brightwhite,0=brightblack,32-126:9-13=white
func parseCSVRangeMap(s string) []stringRanges {
var srs []stringRanges
for _, stringRangesStr := range strings.Split(s, ",") {
stringRangesStr = strings.TrimSpace(stringRangesStr)
var rs [][2]int
stringRangesParts := strings.Split(stringRangesStr, "=")
if len(stringRangesParts) != 2 {
continue
}
for _, rangeStr := range strings.Split(stringRangesParts[0], ":") {
rangeStr = strings.TrimSpace(rangeStr)
rangeStrParts := strings.SplitN(rangeStr, "-", 2)
var start int
var stop int
if len(rangeStrParts) == 1 {
start = atoi(rangeStrParts[0])
stop = start
} else {
start = atoi(rangeStrParts[0])
stop = atoi(rangeStrParts[1])
}
rs = append(rs, [2]int{start, stop})
}
srs = append(srs, stringRanges{rs: rs, s: stringRangesParts[1]})
}
return srs
}
// key=value,a=b,.. -> {"key": "value", "a": "b", ...}
func parseCSVStringMap(s string) map[string]string {
m := map[string]string{}
for _, stringKVStr := range strings.Split(s, ",") {
stringKVStr = strings.TrimSpace(stringKVStr)
stringKVParts := strings.Split(stringKVStr, "=")
if len(stringKVParts) != 2 {
continue
}
m[strings.TrimSpace(stringKVParts[0])] = strings.TrimSpace(stringKVParts[1])
}
return m
}
var PlainDecorator = Decorator{
Column: "|",
ValueColor: func(v interface{}) ansi.Code { return ansi.None },
ByteColor: func(b byte) ansi.Code { return ansi.None },
}
func decoratorFromOptions(opts Options) Decorator {
d := PlainDecorator
if opts.Unicode {
// U+2502 Box Drawings Light Vertical
d.Column = "│"
}
if opts.Color {
colors := parseCSVStringMap(opts.Colors)
d.Null = ansi.FromString(colors["null"])
d.False = ansi.FromString(colors["false"])
d.True = ansi.FromString(colors["true"])
d.Number = ansi.FromString(colors["number"])
d.String = ansi.FromString(colors["string"])
d.ObjectKey = ansi.FromString(colors["objectkey"])
d.Array = ansi.FromString(colors["array"])
d.Object = ansi.FromString(colors["object"])
d.Index = ansi.FromString(colors["index"])
d.Value = ansi.FromString(colors["value"])
d.DumpHeader = ansi.FromString(colors["dumpheader"])
d.DumpAddr = ansi.FromString(colors["dumpaddr"])
d.Error = ansi.FromString(colors["error"])
d.ValueColor = func(v interface{}) ansi.Code {
switch vv := v.(type) {
case bool:
if vv {
return d.True
}
return d.False
case string, bitio.Reader:
return d.String
case nil:
return d.Null
case int, float64, int64, uint64:
// TODO: clean up number types
return d.Number
case *big.Int:
return d.Number
default:
log.Printf("v: %#+v\n", v)
panic("unreachable")
}
}
byteDefaultColor := ansi.FromString("")
byteColors := map[byte]ansi.Code{}
for i := 0; i < 256; i++ {
byteColors[byte(i)] = byteDefaultColor
}
for _, sr := range parseCSVRangeMap(opts.ByteColors) {
c := ansi.FromString(sr.s)
for _, r := range sr.rs {
for i := r[0]; i <= r[1]; i++ {
byteColors[byte(i)] = c
}
}
}
d.ByteColor = func(b byte) ansi.Code { return byteColors[b] }
} else {
d.ValueColor = func(v interface{}) ansi.Code { return ansi.None }
d.ByteColor = func(b byte) ansi.Code { return ansi.None }
}
return d
}
type Decorator struct {
Null ansi.Code
False ansi.Code
True ansi.Code
Number ansi.Code
String ansi.Code
ObjectKey ansi.Code
Array ansi.Code
Object ansi.Code
Index ansi.Code
Value ansi.Code
DumpHeader ansi.Code
DumpAddr ansi.Code
Error ansi.Code
ValueColor func(v interface{}) ansi.Code
ByteColor func(b byte) ansi.Code
Column string
}