1
1
mirror of https://github.com/wader/fq.git synced 2024-11-23 09:56:07 +03:00

interp: Cleanup, use BufferRange for _open, progress for all decode

This commit is contained in:
Mattias Wadman 2021-10-30 01:17:14 +02:00
parent 08142063b3
commit 67898cb44a
10 changed files with 91 additions and 97 deletions

View File

@ -1,8 +1,5 @@
package flac
// TODO: 24 bit picture length truncate warning
// TODO: Cuesheet
import (
"fmt"

View File

@ -20,7 +20,7 @@ type BufferRange struct {
unit int
}
func bufferViewFromBuffer(bb *bitio.Buffer, unit int) BufferRange {
func newBufferRangeFromBuffer(bb *bitio.Buffer, unit int) BufferRange {
return BufferRange{
bb: bb,
r: ranges.Range{Start: 0, Len: bb.Len()},

View File

@ -4,8 +4,8 @@
| to_entries[]
# TODO: nicer way to skip "all" which also would override builtin all/*
| select(.key != "all")
| "def \(.key)($opts): _decode(\(.key | tojson); $opts);"
, "def \(.key): _decode(\(.key | tojson); {});"
| "def \(.key)($opts): decode(\(.key | tojson); $opts);"
, "def \(.key): decode(\(.key | tojson); {});"
)
, ( _registry.formats[]
| select(.files)

View File

@ -124,7 +124,7 @@ func makeStringBitBufTransformFn(
}
outBB := bitio.NewBufferFromBytes(buf.Bytes(), -1)
return bufferViewFromBuffer(outBB, 8)
return newBufferRangeFromBuffer(outBB, 8)
default:
bb, err := toBuffer(c)
if err != nil {
@ -170,7 +170,7 @@ func makeBitBufTransformFn(fn func(r io.Reader) (io.Reader, error)) func(c inter
outBB := bitio.NewBufferFromBytes(outBuf.Bytes(), -1)
return bufferViewFromBuffer(outBB, 8)
return newBufferRangeFromBuffer(outBB, 8)
}
}
@ -192,7 +192,7 @@ func makeHashFn(fn func() (hash.Hash, error)) func(c interface{}, a []interface{
outBB := bitio.NewBufferFromBytes(h.Sum(nil), -1)
return bufferViewFromBuffer(outBB, 8)
return newBufferRangeFromBuffer(outBB, 8)
}
}
@ -473,24 +473,21 @@ func (i *Interp) history(c interface{}, a []interface{}) interface{} {
return vs
}
type bitBufFile struct {
gojq.JQValue
bb *bitio.Buffer
filename string
type openFile struct {
BufferRange
filename string
progressFn progressreadseeker.ProgressFn
}
var _ ToBufferView = (*bitBufFile)(nil)
var _ ToBufferView = (*openFile)(nil)
func (bbf *bitBufFile) Display(w io.Writer, opts Options) error {
_, err := fmt.Fprintln(w, bbf.JQValue.JQValueToString())
func (of *openFile) Display(w io.Writer, opts Options) error {
_, err := fmt.Fprintf(w, "<openFile %q>\n", of.filename)
return err
}
func (bbf *bitBufFile) ToBufferView() (BufferRange, error) {
return bufferViewFromBuffer(bbf.bb, 8), nil
func (of *openFile) ToBufferView() (BufferRange, error) {
return newBufferRangeFromBuffer(of.bb, 8), nil
}
// def open: #:: string| => buffer
@ -541,8 +538,7 @@ func (i *Interp) _open(c interface{}, a []interface{}) interface{} {
bEnd = int64(len(buf))
}
bbf := &bitBufFile{
JQValue: gojqextra.String(fmt.Sprintf("<bitBufFile %s>", path)),
bbf := &openFile{
filename: path,
}
@ -581,7 +577,7 @@ func (i *Interp) _decode(c interface{}, a []interface{}) interface{} {
// would be nice to move all progress code into decode but it might be
// tricky to keep track of absolute positions in the underlaying readers
// when it uses BitBuf slices, maybe only in Pos()?
if bbf, ok := c.(*bitBufFile); ok {
if bbf, ok := c.(*openFile); ok {
opts.Filename = bbf.filename
if opts.Progress != "" {
@ -732,7 +728,7 @@ func (i *Interp) _toBitsRange(c interface{}, a []interface{}) interface{} {
if !r {
bb, _ := bv.toBuffer()
return bufferViewFromBuffer(bb, unit)
return newBufferRangeFromBuffer(bb, unit)
}
return bv

View File

@ -16,6 +16,45 @@ def help:
, "^D Exit REPL"
) | println;
# null input means done, otherwise {approx_read_bytes: 123, total_size: 123}
# TODO: decode provide even more detailed progress, post-process sort etc?
def _decode_progress:
# _input_filenames is remaning files to read
( (_input_filenames | length) as $inputs_len
| ( options.filenames | length) as $filenames_len
| _ansi.clear_line
, "\r"
, if . != null then
( if $filenames_len > 1 then
"\($filenames_len - $inputs_len)/\($filenames_len) \(_input_filename) "
else empty
end
, "\((.approx_read_bytes / .total_size * 100 | _numbertostring(1)))%"
)
else empty
end
| stderr
);
def decode($name; $opts):
( options as $opts
| (null | stdout) as $stdout
| _decode(
$name;
$opts + {
_progress: (
if $opts.decode_progress and $opts.repl and $stdout.is_terminal then
"_decode_progress"
else null
end
)
}
)
);
def decode($name): decode($name; {});
def decode: decode(options.decode_format; {});
def display($opts): _display($opts);
def display: _display({});
def d($opts): _display($opts);
@ -66,34 +105,7 @@ def match($regex; $flags): if _is_buffer then _bits_match($regex; $flags) else _
def formats:
_registry.formats;
# integer division
# inspried by https://github.com/itchyny/gojq/issues/63#issuecomment-765066351
def intdiv($a; $b):
( ($a | _to_int) as $a
| ($b | _to_int) as $b
| ($a - ($a % $b)) / $b
);
def _esc: "\u001b";
def _ansi:
{
clear_line: "\(_esc)[2K",
};
# valid jq identifier, start with alpha or underscore then zero or more alpha, num or underscore
def _is_ident: type == "string" and test("^[a-zA-Z_][a-zA-Z_0-9]*$");
# escape " and \
def _escape_ident: gsub("(?<g>[\\\\\"])"; "\\\(.g)");
# format number with fixed number of decimals
def _numbertostring($decimals):
( . as $n
| [ (. % (. + 1)) # truncate to integer
, "."
, foreach range($decimals) as $_ (1; . * 10; ($n * .) % 10)
]
| join("")
);
def intdiv(a; b): _intdiv(a; b);
# TODO: escape for safe key names
# path ["a", 1, "b"] -> "a[1].b"

View File

@ -45,6 +45,35 @@ def _finally(f; fin):
# TODO: figure out a saner way to force int
def _to_int: (. % (. + 1));
# integer division
# inspried by https://github.com/itchyny/gojq/issues/63#issuecomment-765066351
def _intdiv($a; $b):
( ($a | _to_int) as $a
| ($b | _to_int) as $b
| ($a - ($a % $b)) / $b
);
def _esc: "\u001b";
def _ansi:
{
clear_line: "\(_esc)[2K",
};
# valid jq identifier, start with alpha or underscore then zero or more alpha, num or underscore
def _is_ident: type == "string" and test("^[a-zA-Z_][a-zA-Z_0-9]*$");
# escape " and \
def _escape_ident: gsub("(?<g>[\\\\\"])"; "\\\(.g)");
# format number with fixed number of decimals
def _numbertostring($decimals):
( . as $n
| [ (. % (. + 1)) # truncate to integer
, "."
, foreach range($decimals) as $_ (1; . * 10; ($n * .) % 10)
]
| join("")
);
def _repeat_break(f):
try repeat(f)
catch

View File

@ -358,7 +358,7 @@ func toBufferView(v interface{}) (BufferRange, error) {
if err != nil {
return BufferRange{}, err
}
return bufferViewFromBuffer(bb, 8), nil
return newBufferRangeFromBuffer(bb, 8), nil
}
}
@ -546,7 +546,6 @@ func (i *Interp) Eval(ctx context.Context, c interface{}, src string, srcFilenam
return []*gojq.Query{i.initFqQuery}, nil
},
load: func(name string) (*gojq.Query, error) {
// log.Printf("name: %#+v\n", name)
if err := ctx.Err(); err != nil {
return nil, err
}

View File

@ -1,7 +1,7 @@
include "internal";
include "options";
include "funcs";
include "grep";
include "options";
include "args";
include "repl";
# generated decode functions per format and format helpers
@ -24,45 +24,6 @@ def _exit_code_compile_error: 3;
def _exit_code_input_decode_error: 4;
def _exit_code_expr_error: 5;
# null input means done, otherwise {approx_read_bytes: 123, total_size: 123}
# TODO: decode provide even more detailed progress, post-process sort etc?
def _decode_progress:
# _input_filenames is remaning files to read
( (_input_filenames | length) as $inputs_len
| ( options.filenames | length) as $filenames_len
| _ansi.clear_line
, "\r"
, if . != null then
( if $filenames_len > 1 then
"\($filenames_len - $inputs_len)/\($filenames_len) \(_input_filename) "
else empty
end
, "\((.approx_read_bytes / .total_size * 100 | _numbertostring(1)))%"
)
else empty
end
| stderr
);
def decode($name; $opts):
( options as $opts
| (null | stdout) as $stdout
| _decode(
$name;
$opts + {
_progress: (
if $opts.decode_progress and $opts.repl and $stdout.is_terminal then
"_decode_progress"
else null
end
)
}
)
);
def decode($name): decode($name; {});
def decode: decode(options.decode_format; {});
# next valid input
def input:
def _input($opts; f):

View File

@ -58,8 +58,8 @@ def _build_default_dynamic_options:
( (null | stdout) as $stdout
| {
# TODO: intdiv 2 * 2 to get even number, nice or maybe not needed?
display_bytes: (if $stdout.is_terminal then [intdiv(intdiv($stdout.width; 8); 2) * 2, 4] | max else 16 end),
line_bytes: (if $stdout.is_terminal then [intdiv(intdiv($stdout.width; 8); 2) * 2, 4] | max else 16 end),
display_bytes: (if $stdout.is_terminal then [_intdiv(_intdiv($stdout.width; 8); 2) * 2, 4] | max else 16 end),
line_bytes: (if $stdout.is_terminal then [_intdiv(_intdiv($stdout.width; 8); 2) * 2, 4] | max else 16 end),
}
);

View File

@ -108,7 +108,7 @@ func makeDecodeValue(dv *decode.Value) interface{} {
case []byte:
// TODO: not sure about this
// TODO: only synthentic value without range?
return bufferViewFromBuffer(bitio.NewBufferFromBytes(vv, -1), 8)
return newBufferRangeFromBuffer(bitio.NewBufferFromBytes(vv, -1), 8)
case []interface{}:
return decodeValue{
JQValue: gojqextra.Array(vv),