浏览代码

cmd/geth: exit the console cleanly when interrupted

This fix applies mostly to unsupported terminals that do not trigger the
special interrupt handling in liner. Supported terminals were covered
because liner.Prompt returns an error if Ctrl-C is pressed.
Felix Lange 10 年之前
父节点
当前提交
9253fc337e
共有 1 个文件被更改,包括 44 次插入20 次删除
  1. 44 20
      cmd/geth/js.go

+ 44 - 20
cmd/geth/js.go

@@ -22,6 +22,7 @@ import (
 	"fmt"
 	"math/big"
 	"os"
+	"os/signal"
 	"path/filepath"
 	"strings"
 
@@ -47,7 +48,8 @@ type dumbterm struct{ r *bufio.Reader }
 
 func (r dumbterm) Prompt(p string) (string, error) {
 	fmt.Print(p)
-	return r.r.ReadString('\n')
+	line, err := r.r.ReadString('\n')
+	return strings.TrimSuffix(line, "\n"), err
 }
 
 func (r dumbterm) PasswordPrompt(p string) (string, error) {
@@ -182,30 +184,52 @@ func (self *jsre) exec(filename string) error {
 }
 
 func (self *jsre) interactive() {
-	for {
-		input, err := self.Prompt(self.ps1)
-		if err != nil {
-			break
+	// Read input lines.
+	prompt := make(chan string)
+	inputln := make(chan string)
+	go func() {
+		defer close(inputln)
+		for {
+			line, err := self.Prompt(<-prompt)
+			if err != nil {
+				return
+			}
+			inputln <- line
 		}
-		if input == "" {
-			continue
+	}()
+	// Wait for Ctrl-C, too.
+	sig := make(chan os.Signal, 1)
+	signal.Notify(sig, os.Interrupt)
+
+	defer func() {
+		if self.atexit != nil {
+			self.atexit()
 		}
-		str += input + "\n"
-		self.setIndent()
-		if indentCount <= 0 {
-			if input == "exit" {
-				break
+		self.re.Stop(false)
+	}()
+	for {
+		prompt <- self.ps1
+		select {
+		case <-sig:
+			fmt.Println("caught interrupt, exiting")
+			return
+		case input, ok := <-inputln:
+			if !ok || indentCount <= 0 && input == "exit" {
+				return
+			}
+			if input == "" {
+				continue
+			}
+			str += input + "\n"
+			self.setIndent()
+			if indentCount <= 0 {
+				hist := str[:len(str)-1]
+				self.AppendHistory(hist)
+				self.parseInput(str)
+				str = ""
 			}
-			hist := str[:len(str)-1]
-			self.AppendHistory(hist)
-			self.parseInput(str)
-			str = ""
 		}
 	}
-	if self.atexit != nil {
-		self.atexit()
-	}
-	self.re.Stop(false)
 }
 
 func (self *jsre) withHistory(op func(*os.File)) {