control-C handler

This commit is contained in:
John Kerl 2021-02-08 01:46:32 -05:00
parent f9a6be44f0
commit 5da3c2b426
5 changed files with 47 additions and 4 deletions

View file

@ -18,7 +18,6 @@ const ENV_SECONDARY_PROMPT = "MLR_REPL_PS2"
const DEFAULT_PRIMARY_PROMPT = "[mlr] "
const DEFAULT_SECONDARY_PROMPT = ""
func getInputIsTerminal() bool {
return term.IsTerminal(int(os.Stdin.Fd()))
}

View file

@ -22,7 +22,9 @@ import (
"fmt"
"io"
"os"
"os/signal"
"strings"
"syscall"
"miller/cliutil"
"miller/dsl/cst"
@ -63,6 +65,12 @@ func NewRepl(
// types.MlrvalFromVoid().
runtimeState.FilterExpression = types.MlrvalFromVoid()
// For control-C handling
sysToSignalHandlerChannel := make(chan os.Signal, 1) // Our signal handler reads system notification here
appSignalNotificationChannel := make(chan bool, 1) // Our signal handler writes this for our app to poll
signal.Notify(sysToSignalHandlerChannel, os.Interrupt, syscall.SIGTERM)
go controlCHandler(sysToSignalHandlerChannel, appSignalNotificationChannel)
return &Repl{
exeName: exeName,
replName: replName,
@ -80,10 +88,23 @@ func NewRepl(
recordReader: recordReader,
recordWriter: recordWriter,
runtimeState: runtimeState,
runtimeState: runtimeState,
sysToSignalHandlerChannel: sysToSignalHandlerChannel,
appSignalNotificationChannel: appSignalNotificationChannel,
}, nil
}
// When the user types control-C, immediately print something to the screen,
// then also write to a channel while long-running things like :skip and
// :process can check it.
func controlCHandler(sysToSignalHandlerChannel chan os.Signal, appSignalNotificationChannel chan bool) {
for {
<-sysToSignalHandlerChannel // Block until control-C notification is sent by system
fmt.Println("^C") // Acknowledge for user reassurance
appSignalNotificationChannel <- true // Let our app poll this
}
}
// ----------------------------------------------------------------
func (this *Repl) handleSession(istream *os.File) {
this.printStartupBanner()
@ -103,6 +124,14 @@ func (this *Repl) handleSession(istream *os.File) {
os.Exit(1)
}
// Acknowledge any control-C's, even if typed at a ready prompt
select {
case _ = <-this.appSignalNotificationChannel:
continue
default:
break
}
// This trims the trailing newline, as well as leading/trailing whitespace:
trimmedLine := strings.TrimSpace(line)

View file

@ -5,6 +5,8 @@
package repl
import (
"os"
"miller/cliutil"
"miller/dsl/cst"
"miller/input"
@ -47,4 +49,8 @@ type Repl struct {
recordWriter output.IRecordWriter
runtimeState *runtime.State
// For control-C handling
sysToSignalHandlerChannel chan os.Signal // Our signal handler reads system notification here
appSignalNotificationChannel chan bool // Our signal handler writes this for our app to poll
}

View file

@ -350,6 +350,8 @@ func handleSkipOrProcessN(this *Repl, n int, processingNotSkipping bool) {
break
case err = <-this.errorChannel:
break
case _ = <-this.appSignalNotificationChannel: // user typed control-C
break
}
if err != nil {
@ -398,11 +400,18 @@ func handleSkipOrProcessUntil(this *Repl, dslString string, processingNotSkippin
var recordAndContext *types.RecordAndContext = nil
for {
doubleBreak := false
select {
case recordAndContext = <-this.inputChannel:
break
case err = <-this.errorChannel:
break
case _ = <-this.appSignalNotificationChannel: // user typed control-C
doubleBreak = true
break
}
if doubleBreak {
break
}
if err != nil {
@ -715,7 +724,7 @@ func handleHelpSingle(this *Repl, arg string) {
func showREPLIntro(this *Repl) {
fmt.Printf(
`The Miller REPL is an interactive counterpart to record-processing using the
`The Miller REPL is an interactive counterpart to record-processing using the
put/filter DSL.
Using put and filter, you can do the following:

View file

@ -22,6 +22,7 @@
o make a README.md
- rlwrap note
! for ^C -- need a :skip xxx / :process xxx -- also online help
! output-specifier: write or append.
- applies to all record-writer stuff incl strings
- update ':help intro'
@ -35,7 +36,6 @@
o tilde-expand for load/open ...
- if '~' is in the string, run it though sh -c echo ...
? :continue / ^C -- ?!?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -