1
1
mirror of https://github.com/wader/fq.git synced 2024-12-23 05:13:30 +03:00

interp: Don't print context cancel

This commit is contained in:
Mattias Wadman 2021-11-01 12:57:55 +01:00
parent 80b5d66c7a
commit 13fae09172
7 changed files with 28 additions and 17 deletions

View File

@ -13,6 +13,7 @@
- `echo '{} {} {}' | jq` vs `echo '{} {} {}' | fq` works differently. fq currently decodes one root format and might add unknown fields etc. Maybe should work differently for `json` format?
- `format/0` overlap with jq builtin `format/1`. What to rename it to? `decode_format`?
- repl expression returning a value that produced lots of output can't be interrupted. This is becaus ctrl-C currently only interrupts the evaluation of the expression, outputted value is printed (`display`) by parent.
- Rework cli/repl user interrupt (context cancel via ctrl-c), see comment in Interp.Main
### TODO and ideas

View File

@ -26,11 +26,11 @@ type fuzzTestOutput struct {
func (o fuzzTestOutput) Size() (int, int) { return 120, 25 }
func (o fuzzTestOutput) IsTerminal() bool { return false }
func (ft *fuzzTest) Stdin() io.Reader { return bytes.NewBuffer(ft.b) } // TODO: special file?
func (ft *fuzzTest) Stdout() interp.Output { return fuzzTestOutput{os.Stdout} }
func (ft *fuzzTest) Stderr() io.Writer { return os.Stderr }
func (ft *fuzzTest) Interrupt() chan struct{} { return nil }
func (ft *fuzzTest) Environ() []string { return nil }
func (ft *fuzzTest) Stdin() io.Reader { return bytes.NewBuffer(ft.b) } // TODO: special file?
func (ft *fuzzTest) Stdout() interp.Output { return fuzzTestOutput{os.Stdout} }
func (ft *fuzzTest) Stderr() io.Writer { return os.Stderr }
func (ft *fuzzTest) InterruptChan() chan struct{} { return nil }
func (ft *fuzzTest) Environ() []string { return nil }
func (ft *fuzzTest) Args() []string {
return []string{}
}

View File

@ -105,7 +105,7 @@ func (cr *CaseRun) Stderr() interp.Output {
return CaseRunOutput{Writer: cr.ActualStderrBuf}
}
func (cr *CaseRun) Interrupt() chan struct{} { return nil }
func (cr *CaseRun) InterruptChan() chan struct{} { return nil }
func (cr *CaseRun) Environ() []string {
env := []string{

View File

@ -34,9 +34,8 @@ func (a autoCompleterFn) Do(line []rune, pos int) (newLine [][]rune, length int)
}
type stdOS struct {
rl *readline.Instance
interruptSignalChan chan os.Signal
interruptChan chan struct{}
rl *readline.Instance
interruptChan chan struct{}
}
func newStandardOS() *stdOS {
@ -44,7 +43,10 @@ func newStandardOS() *stdOS {
interruptSignalChan := make(chan os.Signal, 1)
signal.Notify(interruptSignalChan, os.Interrupt)
go func() {
defer signal.Stop(interruptSignalChan)
defer func() {
signal.Stop(interruptSignalChan)
close(interruptSignalChan)
}()
for range interruptSignalChan {
select {
case interruptChan <- struct{}{}:
@ -54,8 +56,7 @@ func newStandardOS() *stdOS {
}()
return &stdOS{
interruptSignalChan: interruptSignalChan,
interruptChan: interruptChan,
interruptChan: interruptChan,
}
}
@ -114,7 +115,7 @@ func (o stderrOutput) Write(p []byte) (n int, err error) { return os.Stderr.Writ
func (o *stdOS) Stderr() interp.Output { return stderrOutput{fdTerminal: fdTerminal(os.Stderr.Fd())} }
func (o *stdOS) Interrupt() chan struct{} { return o.interruptChan }
func (o *stdOS) InterruptChan() chan struct{} { return o.interruptChan }
func (*stdOS) Args() []string { return os.Args }
@ -204,7 +205,7 @@ func (o *stdOS) Close() error {
if o.rl != nil {
o.rl.Close()
}
close(o.interruptSignalChan)
close(o.interruptChan)
return nil
}

View File

@ -121,5 +121,7 @@ def _decode_value(f):
else _expected_decode_value
end;
def _is_context_canceled_error: . == "context canceled";
def _error_str: "error: \(.)";
def _errorln: ., "\n" | stderr;

View File

@ -106,7 +106,7 @@ type OS interface {
Stdin() Input
Stdout() Output
Stderr() Output
Interrupt() chan struct{}
InterruptChan() chan struct{}
Args() []string
Environ() []string
ConfigDir() (string, error)
@ -446,7 +446,7 @@ func New(os OS, registry *registry.Registry) (*Interp, error) {
select {
case <-stopCh:
return
case <-os.Interrupt():
case <-os.InterruptChan():
return
}
})
@ -486,6 +486,10 @@ func (i *Interp) Main(ctx context.Context, output Output, version string) error
case error:
if emptyErr, ok := v.(IsEmptyErrorer); ok && emptyErr.IsEmptyError() { //nolint:errorlint
// no output
} else if errors.Is(v, context.Canceled) {
// ignore context cancel here for now, which means user somehow interrupted the interpreter
// TODO: handle this inside interp.jq instead but then we probably have to do nested
// eval and or also use different contexts for the interpreter and reading/decoding
} else {
fmt.Fprintln(i.os.Stderr(), v)
}

View File

@ -155,7 +155,10 @@ def _prompt:
def _repl_display: _display({depth: 1});
def _repl_on_error:
( if _eval_is_compile_error then _eval_compile_error_tostring end
( if _eval_is_compile_error then _eval_compile_error_tostring
# was interrupte by user, just ignore
elif _is_context_canceled_error then empty
end
| (_error_str | println)
);
def _repl_on_compile_error: _repl_on_error;