aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Lange <fjl@twurst.com>2015-03-06 19:18:44 +0800
committerFelix Lange <fjl@twurst.com>2015-03-06 20:08:11 +0800
commitde86403f330e68df8fc4aee00df98374b7842d0d (patch)
treea4e5c54734e671d9f0701641d68348d2c17748e5
parent2393de5d6b535a850e8b5d510aa2ae4f940f3d23 (diff)
downloadgo-tangerine-de86403f330e68df8fc4aee00df98374b7842d0d.tar.gz
go-tangerine-de86403f330e68df8fc4aee00df98374b7842d0d.tar.zst
go-tangerine-de86403f330e68df8fc4aee00df98374b7842d0d.zip
cmd/ethereum: fix JS REPL exit and add support for dumb terminals
It is now possible to exit the REPL using Ctrl-C, Ctrl-D or by typing "exit".
-rw-r--r--cmd/ethereum/js.go84
-rw-r--r--cmd/ethereum/main.go7
2 files changed, 60 insertions, 31 deletions
diff --git a/cmd/ethereum/js.go b/cmd/ethereum/js.go
index e16ee171e..9125ccbba 100644
--- a/cmd/ethereum/js.go
+++ b/cmd/ethereum/js.go
@@ -18,9 +18,11 @@
package main
import (
+ "bufio"
"fmt"
"io/ioutil"
"os"
+ "os/signal"
"path"
"strings"
@@ -55,44 +57,38 @@ type repl struct {
ethereum *eth.Ethereum
xeth *xeth.XEth
prompt string
- histfile *os.File
lr *liner.State
- running bool
}
-func newREPL(ethereum *eth.Ethereum) *repl {
- hist, err := os.OpenFile(path.Join(ethereum.DataDir, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm)
- if err != nil {
- panic(err)
- }
+func runREPL(ethereum *eth.Ethereum) {
xeth := xeth.New(ethereum)
repl := &repl{
re: javascript.NewJSRE(xeth),
xeth: xeth,
ethereum: ethereum,
prompt: "> ",
- histfile: hist,
- lr: liner.NewLiner(),
}
repl.initStdFuncs()
- return repl
-}
-
-func (self *repl) Start() {
- if !self.running {
- self.running = true
- self.lr.ReadHistory(self.histfile)
- go self.read()
+ if !liner.TerminalSupported() {
+ repl.dumbRead()
+ } else {
+ lr := liner.NewLiner()
+ defer lr.Close()
+ lr.SetCtrlCAborts(true)
+ repl.withHistory(func(hist *os.File) { lr.ReadHistory(hist) })
+ repl.read(lr)
+ repl.withHistory(func(hist *os.File) { hist.Truncate(0); lr.WriteHistory(hist) })
}
}
-func (self *repl) Stop() {
- if self.running {
- self.running = false
- self.histfile.Truncate(0)
- self.lr.WriteHistory(self.histfile)
- self.histfile.Close()
+func (self *repl) withHistory(op func(*os.File)) {
+ hist, err := os.OpenFile(path.Join(self.ethereum.DataDir, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm)
+ if err != nil {
+ fmt.Printf("unable to open history file: %v\n", err)
+ return
}
+ op(hist)
+ hist.Close()
}
func (self *repl) parseInput(code string) {
@@ -126,9 +122,9 @@ func (self *repl) setIndent() {
}
}
-func (self *repl) read() {
+func (self *repl) read(lr *liner.State) {
for {
- input, err := self.lr.Prompt(self.prompt)
+ input, err := lr.Prompt(self.prompt)
if err != nil {
return
}
@@ -139,17 +135,51 @@ func (self *repl) read() {
self.setIndent()
if indentCount <= 0 {
if input == "exit" {
- self.Stop()
return
}
hist := str[:len(str)-1]
- self.lr.AppendHistory(hist)
+ lr.AppendHistory(hist)
self.parseInput(str)
str = ""
}
}
}
+func (self *repl) dumbRead() {
+ fmt.Println("Unsupported terminal, line editing will not work.")
+
+ // process lines
+ readDone := make(chan struct{})
+ go func() {
+ r := bufio.NewReader(os.Stdin)
+ loop:
+ for {
+ fmt.Print(self.prompt)
+ line, err := r.ReadString('\n')
+ switch {
+ case err != nil || line == "exit":
+ break loop
+ case line == "":
+ continue
+ default:
+ self.parseInput(line + "\n")
+ }
+ }
+ close(readDone)
+ }()
+
+ // wait for Ctrl-C
+ sigc := make(chan os.Signal, 1)
+ signal.Notify(sigc, os.Interrupt, os.Kill)
+ defer signal.Stop(sigc)
+
+ select {
+ case <-readDone:
+ case <-sigc:
+ os.Stdin.Close() // terminate read
+ }
+}
+
func (self *repl) printValue(v interface{}) {
method, _ := self.re.Vm.Get("prettyPrint")
v, err := self.re.Vm.ToValue(v)
diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go
index c85caf229..1133bd6f7 100644
--- a/cmd/ethereum/main.go
+++ b/cmd/ethereum/main.go
@@ -125,7 +125,6 @@ runtime will execute the file and exit.
func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
defer logger.Flush()
- utils.HandleInterrupt()
if err := app.Run(os.Args); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
@@ -134,6 +133,7 @@ func main() {
func run(ctx *cli.Context) {
fmt.Printf("Welcome to the FRONTIER\n")
+ utils.HandleInterrupt()
eth := utils.GetEthereum(ClientIdentifier, Version, ctx)
startEth(ctx, eth)
// this blocks the thread
@@ -144,9 +144,8 @@ func runjs(ctx *cli.Context) {
eth := utils.GetEthereum(ClientIdentifier, Version, ctx)
startEth(ctx, eth)
if len(ctx.Args()) == 0 {
- repl := newREPL(eth)
- utils.RegisterInterrupt(func(os.Signal) { repl.Stop() })
- repl.Start()
+ runREPL(eth)
+ eth.Stop()
eth.WaitForShutdown()
} else if len(ctx.Args()) == 1 {
execJsFile(eth, ctx.Args()[0])