Skip to content

Commit

Permalink
Use the new terminal to handle ^C (#200)
Browse files Browse the repository at this point in the history
* Use the new terminal to handle ^C

* Use the return value

* Use release version

* non ai comment
  • Loading branch information
ldemailly authored Aug 31, 2024
1 parent 5609c71 commit bee7902
Show file tree
Hide file tree
Showing 7 changed files with 34 additions and 32 deletions.
15 changes: 2 additions & 13 deletions extensions/extension.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ package extensions

import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
Expand All @@ -17,6 +16,7 @@ import (
"unicode/utf8"

"fortio.org/log"
"fortio.org/terminal"
"github.com/rivo/uniseg"
"grol.io/grol/eval"
"grol.io/grol/lexer"
Expand Down Expand Up @@ -390,7 +390,7 @@ func createMisc() {
}
durDur := time.Duration(durSec * 1e9)
log.Infof("Sleeping for %v", durDur)
return s.Error(SleepWithContext(s.Context, durDur))
return s.Error(terminal.SleepWithContext(s.Context, durDur))
},
})
MustCreate(object.Extension{
Expand Down Expand Up @@ -434,17 +434,6 @@ func createMisc() {

// --- implementation of the functions that aren't inlined in lambdas above.

func SleepWithContext(ctx context.Context, duration time.Duration) error {
select {
case <-time.After(duration):
// Completed the sleep duration
return nil
case <-ctx.Done():
// Context was canceled
return ctx.Err()
}
}

func pow(args []object.Object) object.Object {
// Arg len check already done through MinArgs and MaxArgs
// and so is type check through ArgTypes.
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
fortio.org/log v1.16.0
fortio.org/sets v1.2.0
fortio.org/struct2env v0.4.1
fortio.org/terminal v0.7.3
fortio.org/terminal v0.8.0
fortio.org/testscript v0.3.1 // only for tests
fortio.org/version v1.0.4
github.com/rivo/uniseg v0.4.7
Expand All @@ -17,7 +17,7 @@ require (
fortio.org/term v0.23.0-fortio-6 // indirect
github.com/kortschak/goroutine v1.1.2 // indirect
golang.org/x/crypto/x509roots/fallback v0.0.0-20240806160748-b2d3a6a4b4d3 // indirect
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/tools v0.24.0 // indirect
)
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ fortio.org/struct2env v0.4.1 h1:rJludAMO5eBvpWplWEQNqoVDFZr4RWMQX7RUapgZyc0=
fortio.org/struct2env v0.4.1/go.mod h1:lENUe70UwA1zDUCX+8AsO663QCFqYaprk5lnPhjD410=
fortio.org/term v0.23.0-fortio-6 h1:pKrUX0tKOxyEhkhLV50oJYucTVx94rzFrXc24lIuLvk=
fortio.org/term v0.23.0-fortio-6/go.mod h1:7buBfn81wEJUGWiVjFNiUE/vxWs5FdM9c7PyZpZRS30=
fortio.org/terminal v0.7.3 h1:tQV8YikqowjuIxk3Ayfglf/AQWs2ywlBWuggAzCY6Dc=
fortio.org/terminal v0.7.3/go.mod h1:hRs4ZM5C06GyfLRD6JHD96yjJGgm1mXQH75Ze8CMLjw=
fortio.org/terminal v0.8.0 h1:NSaa/JQZ4lIK08QEfBExwuzNY/bXfkzZzpfuPB7MlEA=
fortio.org/terminal v0.8.0/go.mod h1:hRs4ZM5C06GyfLRD6JHD96yjJGgm1mXQH75Ze8CMLjw=
fortio.org/testscript v0.3.1 h1:MmRO64AsmzaU1KlYMzAbotJIMKRGxD1XXssJnBRiMGQ=
fortio.org/testscript v0.3.1/go.mod h1:7OJ+U4avooRNqc7p/VHKJadYgj9fA6+N0SbGU8FVWGs=
fortio.org/version v1.0.4 h1:FWUMpJ+hVTNc4RhvvOJzb0xesrlRmG/a+D6bjbQ4+5U=
Expand All @@ -22,8 +22,8 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
golang.org/x/crypto/x509roots/fallback v0.0.0-20240806160748-b2d3a6a4b4d3 h1:oWb21rU9Q9XrRwXLB7jHc1rbp6EiiimZZv5MLxpu4T0=
golang.org/x/crypto/x509roots/fallback v0.0.0-20240806160748-b2d3a6a4b4d3/go.mod h1:kNa9WdvYnzFwC79zRpLRMJbdEFlhyM5RPFBBZp/wWH8=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA=
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
Expand Down
3 changes: 2 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
package main

import (
"context"
"flag"
"fmt"
"io"
Expand Down Expand Up @@ -123,7 +124,7 @@ func Main() (retcode int) {
return log.FErrf("Error initializing extensions: %v", err)
}
if *commandFlag != "" {
res, errs, _ := repl.EvalStringWithOption(options, *commandFlag)
res, errs, _ := repl.EvalStringWithOption(context.Background(), options, *commandFlag)
// Only parsing errors are already logged, eval errors aren't, we (re)log everything:
numErrs := len(errs)
if numErrs > 0 {
Expand Down
30 changes: 20 additions & 10 deletions repl/repl.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ func EvalAll(s *eval.State, in io.Reader, out io.Writer, options Options) []stri
if options.PreInput != nil {
options.PreInput(s)
}
_, _, errs, _ := EvalOne(s, what, out, options) //nolint:dogsled // as mentioned we should refactor EvalOne.
_, _, errs, _ := EvalOne(context.Background(), s, what, out, options) //nolint:dogsled // as mentioned we should refactor EvalOne.
return errs
}

Expand All @@ -162,7 +162,7 @@ func EvalStringOptions() Options {
// occurred.
// Default options are EvalStringOptions()'s.
func EvalString(what string) (string, []string, string) {
return EvalStringWithOption(EvalStringOptions(), what)
return EvalStringWithOption(context.Background(), EvalStringOptions(), what)
}

// EvalStringWithOption can be used from playground etc for single eval.
Expand All @@ -172,7 +172,7 @@ func EvalString(what string) (string, []string, string) {
// Following options should be set (starting from EvalStringOptions()) to
// additionally control the behavior:
// AutoLoad, AutoSave, Compact.
func EvalStringWithOption(o Options, what string) (res string, errs []string, formatted string) {
func EvalStringWithOption(ctx context.Context, o Options, what string) (res string, errs []string, formatted string) {
s := eval.NewState()
if o.MaxDepth > 0 {
s.MaxDepth = o.MaxDepth
Expand All @@ -188,7 +188,7 @@ func EvalStringWithOption(o Options, what string) (res string, errs []string, fo
}
panicked := false
incomplete := false
incomplete, panicked, errs, formatted = EvalOne(s, what, out, o)
incomplete, panicked, errs, formatted = EvalOne(ctx, s, what, out, o)
if incomplete && len(errs) == 0 {
errs = append(errs, "Incomplete input")
}
Expand All @@ -209,12 +209,13 @@ func extractHistoryNumber(input string) (int, bool) {
return 0, false
}

func Interactive(options Options) int {
func Interactive(options Options) int { //nolint:funlen // we do have quite a few cases.
options.NilAndErr = true
s := eval.NewState()
s.MaxDepth = options.MaxDepth
s.MaxValueLen = options.MaxValueLen // 0 is unlimited so ok to copy as is.
term, err := terminal.Open()
term, err := terminal.Open(context.Background())
ctx := term.Context
if err != nil {
return log.FErrf("Error creating readline: %v", err)
}
Expand Down Expand Up @@ -248,10 +249,15 @@ func Interactive(options Options) int {
for {
rd, err := term.ReadLine()
if errors.Is(err, io.EOF) {
log.Infof("Exit requested") // Don't say EOF as ^C comes through as EOF as well.
log.Infof("EOF, exiting")
_ = AutoSave(s, options)
return 0
}
if errors.Is(err, terminal.ErrInterrupted) {
log.Debugf("Interrupted error")
ctx, _ = term.ResetInterrupts(context.Background()) //nolint:fatcontext // we only get a new one after the previous one is done.
continue
}
if err != nil {
return log.FErrf("Error reading line: %v", err)
}
Expand Down Expand Up @@ -280,10 +286,14 @@ func Interactive(options Options) int {
fmt.Fprintln(term.Out,
"Type 'history' to see history, '!n' to repeat history n, 'info' for language builtins, use <tab> for completion.")
continue
case l == "exit":
log.Infof("Exit requested")
_ = AutoSave(s, options)
return 0
}
// normal errors are already logged but not the panic recoveries
// Note this is the only case that can get contNeeded (EOL instead of EOF mode)
contNeeded, _, _, formatted := EvalOne(s, l, term.Out, options)
contNeeded, _, _, formatted := EvalOne(ctx, s, l, term.Out, options)
if contNeeded {
prev = l + "\n"
term.SetPrompt(CONTINUATION)
Expand Down Expand Up @@ -347,7 +357,7 @@ func (g *Grol) Run(out io.Writer) error {
// errs is the list of errors, formatted is the normalized input.
// If a panic occurs, panicked is true and errs contains the one panic message.
// TODO: this one size fits 3 different calls (file, interactive, bot) is getting spaghetti.
func EvalOne(s *eval.State, what string, out io.Writer, options Options) (
func EvalOne(ctx context.Context, s *eval.State, what string, out io.Writer, options Options) (
continuation, panicked bool,
errs []string,
formatted string,
Expand All @@ -369,7 +379,7 @@ func EvalOne(s *eval.State, what string, out io.Writer, options Options) (
}
}()
}
s.SetContext(context.Background(), options.MaxDuration)
s.SetContext(ctx, options.MaxDuration)
continuation, errs, formatted = evalOne(s, what, out, options)
return
}
Expand Down
3 changes: 2 additions & 1 deletion repl/repl_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package repl_test

import (
"context"
"testing"

"grol.io/grol/eval"
Expand Down Expand Up @@ -165,7 +166,7 @@ func TestPreInputHook(t *testing.T) {
}
inp := `testHook()`
expected := "42\n"
res, errs, _ := repl.EvalStringWithOption(opts, inp)
res, errs, _ := repl.EvalStringWithOption(context.Background(), opts, inp)
if res != expected || len(errs) > 0 {
t.Errorf("EvalString() got %v\n---\n%s\n---want---\n%s\n---", errs, res, expected)
}
Expand Down
3 changes: 2 additions & 1 deletion wasm/wasm_main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Web assembly main for grol, exposing grol (repl.EvalString for now) to JS
package main

import (
"context"
"runtime"
"runtime/debug"
"strings"
Expand Down Expand Up @@ -53,7 +54,7 @@ func jsEval(this js.Value, args []js.Value) interface{} {
// as not exactly responsive to PRs nor issues folks (everyone trying their best yet...).
opts.MaxDepth = WasmMaxDepth
opts.MaxDuration = WasmMaxDuration
res, errs, formatted := repl.EvalStringWithOption(opts, input)
res, errs, formatted := repl.EvalStringWithOption(context.Background(), opts, input)
result := make(map[string]any)
result["result"] = strings.TrimSuffix(res, "\n")
// transfer errors to []any (!)
Expand Down

0 comments on commit bee7902

Please sign in to comment.