From 38f6d60e6e699db24b7a850b5999823b9e36d5bb Mon Sep 17 00:00:00 2001
From: Felix Lange <fjl@twurst.com>
Date: Fri, 6 Mar 2015 03:38:19 +0100
Subject: [PATCH] cmd/ethereum: new JS repl with cross-platform line editing

---
 cmd/ethereum/js.go                          | 207 ++++++++++++++++++++
 cmd/ethereum/main.go                        |   5 +-
 cmd/ethereum/repl/console_colors_windows.go |  97 ---------
 cmd/ethereum/repl/repl.go                   | 201 -------------------
 cmd/ethereum/repl/repl_darwin.go            | 144 --------------
 cmd/ethereum/repl/repl_linux.go             |   1 -
 cmd/ethereum/repl/repl_windows.go           |  92 ---------
 7 files changed, 209 insertions(+), 538 deletions(-)
 delete mode 100644 cmd/ethereum/repl/console_colors_windows.go
 delete mode 100644 cmd/ethereum/repl/repl.go
 delete mode 100644 cmd/ethereum/repl/repl_darwin.go
 delete mode 120000 cmd/ethereum/repl/repl_linux.go
 delete mode 100644 cmd/ethereum/repl/repl_windows.go

diff --git a/cmd/ethereum/js.go b/cmd/ethereum/js.go
index f0aeb45f5..e16ee171e 100644
--- a/cmd/ethereum/js.go
+++ b/cmd/ethereum/js.go
@@ -18,13 +18,21 @@
 package main
 
 import (
+	"fmt"
 	"io/ioutil"
 	"os"
+	"path"
+	"strings"
 
 	"github.com/ethereum/go-ethereum/cmd/utils"
+	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/eth"
+	"github.com/ethereum/go-ethereum/ethutil"
 	"github.com/ethereum/go-ethereum/javascript"
+	"github.com/ethereum/go-ethereum/state"
 	"github.com/ethereum/go-ethereum/xeth"
+	"github.com/obscuren/otto"
+	"github.com/peterh/liner"
 )
 
 func execJsFile(ethereum *eth.Ethereum, filename string) {
@@ -41,3 +49,202 @@ func execJsFile(ethereum *eth.Ethereum, filename string) {
 		utils.Fatalf("Javascript Error: %v", err)
 	}
 }
+
+type repl struct {
+	re       *javascript.JSRE
+	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)
+	}
+	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()
+	}
+}
+
+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) parseInput(code string) {
+	defer func() {
+		if r := recover(); r != nil {
+			fmt.Println("[native] error", r)
+		}
+	}()
+	value, err := self.re.Run(code)
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+	self.printValue(value)
+}
+
+var indentCount = 0
+var str = ""
+
+func (self *repl) setIndent() {
+	open := strings.Count(str, "{")
+	open += strings.Count(str, "(")
+	closed := strings.Count(str, "}")
+	closed += strings.Count(str, ")")
+	indentCount = open - closed
+	if indentCount <= 0 {
+		self.prompt = "> "
+	} else {
+		self.prompt = strings.Join(make([]string, indentCount*2), "..")
+		self.prompt += " "
+	}
+}
+
+func (self *repl) read() {
+	for {
+		input, err := self.lr.Prompt(self.prompt)
+		if err != nil {
+			return
+		}
+		if input == "" {
+			continue
+		}
+		str += input + "\n"
+		self.setIndent()
+		if indentCount <= 0 {
+			if input == "exit" {
+				self.Stop()
+				return
+			}
+			hist := str[:len(str)-1]
+			self.lr.AppendHistory(hist)
+			self.parseInput(str)
+			str = ""
+		}
+	}
+}
+
+func (self *repl) printValue(v interface{}) {
+	method, _ := self.re.Vm.Get("prettyPrint")
+	v, err := self.re.Vm.ToValue(v)
+	if err == nil {
+		val, err := method.Call(method, v)
+		if err == nil {
+			fmt.Printf("%v", val)
+		}
+	}
+}
+
+func (self *repl) initStdFuncs() {
+	t, _ := self.re.Vm.Get("eth")
+	eth := t.Object()
+	eth.Set("connect", self.connect)
+	eth.Set("stopMining", self.stopMining)
+	eth.Set("startMining", self.startMining)
+	eth.Set("dump", self.dump)
+	eth.Set("export", self.export)
+}
+
+/*
+ * The following methods are natively implemented javascript functions.
+ */
+
+func (self *repl) dump(call otto.FunctionCall) otto.Value {
+	var block *types.Block
+
+	if len(call.ArgumentList) > 0 {
+		if call.Argument(0).IsNumber() {
+			num, _ := call.Argument(0).ToInteger()
+			block = self.ethereum.ChainManager().GetBlockByNumber(uint64(num))
+		} else if call.Argument(0).IsString() {
+			hash, _ := call.Argument(0).ToString()
+			block = self.ethereum.ChainManager().GetBlock(ethutil.Hex2Bytes(hash))
+		} else {
+			fmt.Println("invalid argument for dump. Either hex string or number")
+		}
+
+		if block == nil {
+			fmt.Println("block not found")
+
+			return otto.UndefinedValue()
+		}
+
+	} else {
+		block = self.ethereum.ChainManager().CurrentBlock()
+	}
+
+	statedb := state.New(block.Root(), self.ethereum.Db())
+
+	v, _ := self.re.Vm.ToValue(statedb.RawDump())
+
+	return v
+}
+
+func (self *repl) stopMining(call otto.FunctionCall) otto.Value {
+	self.xeth.Miner().Stop()
+	return otto.TrueValue()
+}
+
+func (self *repl) startMining(call otto.FunctionCall) otto.Value {
+	self.xeth.Miner().Start()
+	return otto.TrueValue()
+}
+
+func (self *repl) connect(call otto.FunctionCall) otto.Value {
+	nodeURL, err := call.Argument(0).ToString()
+	if err != nil {
+		return otto.FalseValue()
+	}
+	if err := self.ethereum.SuggestPeer(nodeURL); err != nil {
+		return otto.FalseValue()
+	}
+	return otto.TrueValue()
+}
+
+func (self *repl) export(call otto.FunctionCall) otto.Value {
+	if len(call.ArgumentList) == 0 {
+		fmt.Println("err: require file name")
+		return otto.FalseValue()
+	}
+
+	fn, err := call.Argument(0).ToString()
+	if err != nil {
+		fmt.Println(err)
+		return otto.FalseValue()
+	}
+
+	data := self.ethereum.ChainManager().Export()
+
+	if err := ethutil.WriteFile(fn, data); err != nil {
+		fmt.Println(err)
+		return otto.FalseValue()
+	}
+
+	return otto.TrueValue()
+}
diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go
index a38e012c2..c85caf229 100644
--- a/cmd/ethereum/main.go
+++ b/cmd/ethereum/main.go
@@ -28,7 +28,6 @@ import (
 	"time"
 
 	"github.com/codegangsta/cli"
-	"github.com/ethereum/go-ethereum/cmd/ethereum/repl"
 	"github.com/ethereum/go-ethereum/cmd/utils"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/eth"
@@ -145,9 +144,9 @@ func runjs(ctx *cli.Context) {
 	eth := utils.GetEthereum(ClientIdentifier, Version, ctx)
 	startEth(ctx, eth)
 	if len(ctx.Args()) == 0 {
-		repl := ethrepl.NewJSRepl(eth)
-		repl.Start()
+		repl := newREPL(eth)
 		utils.RegisterInterrupt(func(os.Signal) { repl.Stop() })
+		repl.Start()
 		eth.WaitForShutdown()
 	} else if len(ctx.Args()) == 1 {
 		execJsFile(eth, ctx.Args()[0])
diff --git a/cmd/ethereum/repl/console_colors_windows.go b/cmd/ethereum/repl/console_colors_windows.go
deleted file mode 100644
index 8062746fb..000000000
--- a/cmd/ethereum/repl/console_colors_windows.go
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-// MA 02110-1301  USA
-
-/* Inspired by https://github.com/xuyu/logging/blob/master/colorful_win.go */
-
-package ethrepl
-
-import (
-	"syscall"
-	"unsafe"
-)
-
-type color uint16
-
-const (
-	green  = color(0x0002)
-	red    = color(0x0004)
-	yellow = color(0x000E)
-)
-
-const (
-	mask = uint16(yellow | green | red)
-)
-
-var (
-	kernel32                       = syscall.NewLazyDLL("kernel32.dll")
-	procGetStdHandle               = kernel32.NewProc("GetStdHandle")
-	procSetConsoleTextAttribute    = kernel32.NewProc("SetConsoleTextAttribute")
-	procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
-	hStdout                        uintptr
-	initScreenInfo                 *consoleScreenBufferInfo
-)
-
-func setConsoleTextAttribute(hConsoleOutput uintptr, wAttributes uint16) bool {
-	ret, _, _ := procSetConsoleTextAttribute.Call(hConsoleOutput, uintptr(wAttributes))
-	return ret != 0
-}
-
-type coord struct {
-	X, Y int16
-}
-
-type smallRect struct {
-	Left, Top, Right, Bottom int16
-}
-
-type consoleScreenBufferInfo struct {
-	DwSize              coord
-	DwCursorPosition    coord
-	WAttributes         uint16
-	SrWindow            smallRect
-	DwMaximumWindowSize coord
-}
-
-func getConsoleScreenBufferInfo(hConsoleOutput uintptr) *consoleScreenBufferInfo {
-	var csbi consoleScreenBufferInfo
-	ret, _, _ := procGetConsoleScreenBufferInfo.Call(hConsoleOutput, uintptr(unsafe.Pointer(&csbi)))
-	if ret == 0 {
-		return nil
-	}
-	return &csbi
-}
-
-const (
-	stdOutputHandle = uint32(-11 & 0xFFFFFFFF)
-)
-
-func init() {
-	hStdout, _, _ = procGetStdHandle.Call(uintptr(stdOutputHandle))
-	initScreenInfo = getConsoleScreenBufferInfo(hStdout)
-}
-
-func resetColorful() {
-	if initScreenInfo == nil {
-		return
-	}
-	setConsoleTextAttribute(hStdout, initScreenInfo.WAttributes)
-}
-
-func changeColor(c color) {
-	attr := uint16(0) & ^mask | uint16(c)
-	setConsoleTextAttribute(hStdout, attr)
-}
diff --git a/cmd/ethereum/repl/repl.go b/cmd/ethereum/repl/repl.go
deleted file mode 100644
index 05ea71e79..000000000
--- a/cmd/ethereum/repl/repl.go
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-// MA 02110-1301  USA
-
-package ethrepl
-
-import (
-	"bufio"
-	"fmt"
-	"io"
-	"os"
-	"path"
-
-	"github.com/ethereum/go-ethereum/core/types"
-	"github.com/ethereum/go-ethereum/eth"
-	"github.com/ethereum/go-ethereum/ethutil"
-	"github.com/ethereum/go-ethereum/javascript"
-	"github.com/ethereum/go-ethereum/logger"
-	"github.com/ethereum/go-ethereum/state"
-	"github.com/ethereum/go-ethereum/xeth"
-	"github.com/obscuren/otto"
-)
-
-var repllogger = logger.NewLogger("REPL")
-
-type Repl interface {
-	Start()
-	Stop()
-}
-
-type JSRepl struct {
-	re       *javascript.JSRE
-	ethereum *eth.Ethereum
-	xeth     *xeth.XEth
-
-	prompt string
-
-	history *os.File
-
-	running bool
-}
-
-func NewJSRepl(ethereum *eth.Ethereum) *JSRepl {
-	hist, err := os.OpenFile(path.Join(ethereum.DataDir, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm)
-	if err != nil {
-		panic(err)
-	}
-
-	xeth := xeth.New(ethereum)
-	repl := &JSRepl{re: javascript.NewJSRE(xeth), xeth: xeth, ethereum: ethereum, prompt: "> ", history: hist}
-	repl.initStdFuncs()
-
-	return repl
-}
-
-func (self *JSRepl) Start() {
-	if !self.running {
-		self.running = true
-		repllogger.Infoln("init JS Console")
-
-		reader := bufio.NewReader(self.history)
-		for {
-			line, err := reader.ReadString('\n')
-			if err != nil && err == io.EOF {
-				break
-			} else if err != nil {
-				fmt.Println("error reading history", err)
-				break
-			}
-
-			addHistory(line[:len(line)-1])
-		}
-		self.read()
-	}
-}
-
-func (self *JSRepl) Stop() {
-	if self.running {
-		self.running = false
-		repllogger.Infoln("exit JS Console")
-		self.history.Close()
-	}
-}
-
-func (self *JSRepl) parseInput(code string) {
-	defer func() {
-		if r := recover(); r != nil {
-			fmt.Println("[native] error", r)
-		}
-	}()
-
-	value, err := self.re.Run(code)
-	if err != nil {
-		fmt.Println(err)
-		return
-	}
-
-	self.PrintValue(value)
-}
-
-func (self *JSRepl) initStdFuncs() {
-	t, _ := self.re.Vm.Get("eth")
-	eth := t.Object()
-	eth.Set("connect", self.connect)
-	eth.Set("stopMining", self.stopMining)
-	eth.Set("startMining", self.startMining)
-	eth.Set("dump", self.dump)
-	eth.Set("export", self.export)
-}
-
-/*
- * The following methods are natively implemented javascript functions
- */
-
-func (self *JSRepl) dump(call otto.FunctionCall) otto.Value {
-	var block *types.Block
-
-	if len(call.ArgumentList) > 0 {
-		if call.Argument(0).IsNumber() {
-			num, _ := call.Argument(0).ToInteger()
-			block = self.ethereum.ChainManager().GetBlockByNumber(uint64(num))
-		} else if call.Argument(0).IsString() {
-			hash, _ := call.Argument(0).ToString()
-			block = self.ethereum.ChainManager().GetBlock(ethutil.Hex2Bytes(hash))
-		} else {
-			fmt.Println("invalid argument for dump. Either hex string or number")
-		}
-
-		if block == nil {
-			fmt.Println("block not found")
-
-			return otto.UndefinedValue()
-		}
-
-	} else {
-		block = self.ethereum.ChainManager().CurrentBlock()
-	}
-
-	statedb := state.New(block.Root(), self.ethereum.Db())
-
-	v, _ := self.re.Vm.ToValue(statedb.RawDump())
-
-	return v
-}
-
-func (self *JSRepl) stopMining(call otto.FunctionCall) otto.Value {
-	self.xeth.Miner().Stop()
-
-	return otto.TrueValue()
-}
-
-func (self *JSRepl) startMining(call otto.FunctionCall) otto.Value {
-	self.xeth.Miner().Start()
-	return otto.TrueValue()
-}
-
-func (self *JSRepl) connect(call otto.FunctionCall) otto.Value {
-	nodeURL, err := call.Argument(0).ToString()
-	if err != nil {
-		return otto.FalseValue()
-	}
-	if err := self.ethereum.SuggestPeer(nodeURL); err != nil {
-		return otto.FalseValue()
-	}
-	return otto.TrueValue()
-}
-
-func (self *JSRepl) export(call otto.FunctionCall) otto.Value {
-	if len(call.ArgumentList) == 0 {
-		fmt.Println("err: require file name")
-		return otto.FalseValue()
-	}
-
-	fn, err := call.Argument(0).ToString()
-	if err != nil {
-		fmt.Println(err)
-		return otto.FalseValue()
-	}
-
-	data := self.ethereum.ChainManager().Export()
-
-	if err := ethutil.WriteFile(fn, data); err != nil {
-		fmt.Println(err)
-		return otto.FalseValue()
-	}
-
-	return otto.TrueValue()
-}
diff --git a/cmd/ethereum/repl/repl_darwin.go b/cmd/ethereum/repl/repl_darwin.go
deleted file mode 100644
index 3710150cc..000000000
--- a/cmd/ethereum/repl/repl_darwin.go
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-// MA 02110-1301  USA
-
-package ethrepl
-
-// #cgo darwin CFLAGS: -I/usr/local/opt/readline/include
-// #cgo darwin LDFLAGS: -L/usr/local/opt/readline/lib
-// #cgo LDFLAGS: -lreadline
-// #include <stdio.h>
-// #include <stdlib.h>
-// #include <readline/readline.h>
-// #include <readline/history.h>
-import "C"
-import (
-	"fmt"
-	"os"
-	"os/signal"
-	"strings"
-	"syscall"
-	"unsafe"
-)
-
-func initReadLine() {
-	C.rl_catch_sigwinch = 0
-	C.rl_catch_signals = 0
-	c := make(chan os.Signal, 1)
-	signal.Notify(c, syscall.SIGWINCH)
-	signal.Notify(c, os.Interrupt)
-	go func() {
-		for sig := range c {
-			switch sig {
-			case syscall.SIGWINCH:
-				C.rl_resize_terminal()
-
-			case os.Interrupt:
-				C.rl_cleanup_after_signal()
-			default:
-
-			}
-		}
-	}()
-}
-
-func readLine(prompt *string) *string {
-	var p *C.char
-
-	//readline allows an empty prompt(NULL)
-	if prompt != nil {
-		p = C.CString(*prompt)
-	}
-
-	ret := C.readline(p)
-
-	if p != nil {
-		C.free(unsafe.Pointer(p))
-	}
-
-	if ret == nil {
-		return nil
-	} //EOF
-
-	s := C.GoString(ret)
-	C.free(unsafe.Pointer(ret))
-	return &s
-}
-
-func addHistory(s string) {
-	p := C.CString(s)
-	C.add_history(p)
-	C.free(unsafe.Pointer(p))
-}
-
-var indentCount = 0
-var str = ""
-
-func (self *JSRepl) setIndent() {
-	open := strings.Count(str, "{")
-	open += strings.Count(str, "(")
-	closed := strings.Count(str, "}")
-	closed += strings.Count(str, ")")
-	indentCount = open - closed
-	if indentCount <= 0 {
-		self.prompt = "> "
-	} else {
-		self.prompt = strings.Join(make([]string, indentCount*2), "..")
-		self.prompt += " "
-	}
-}
-
-func (self *JSRepl) read() {
-	initReadLine()
-L:
-	for {
-		switch result := readLine(&self.prompt); true {
-		case result == nil:
-			break L
-
-		case *result != "":
-			str += *result + "\n"
-
-			self.setIndent()
-
-			if indentCount <= 0 {
-				if *result == "exit" {
-					self.Stop()
-					break L
-				}
-
-				hist := str[:len(str)-1]
-				addHistory(hist) //allow user to recall this line
-				self.history.WriteString(str)
-
-				self.parseInput(str)
-
-				str = ""
-			}
-		}
-	}
-}
-
-func (self *JSRepl) PrintValue(v interface{}) {
-	method, _ := self.re.Vm.Get("prettyPrint")
-	v, err := self.re.Vm.ToValue(v)
-	if err == nil {
-		val, err := method.Call(method, v)
-		if err == nil {
-			fmt.Printf("%v", val)
-		}
-	}
-}
diff --git a/cmd/ethereum/repl/repl_linux.go b/cmd/ethereum/repl/repl_linux.go
deleted file mode 120000
index 276f135d7..000000000
--- a/cmd/ethereum/repl/repl_linux.go
+++ /dev/null
@@ -1 +0,0 @@
-repl_darwin.go
\ No newline at end of file
diff --git a/cmd/ethereum/repl/repl_windows.go b/cmd/ethereum/repl/repl_windows.go
deleted file mode 100644
index d2c405ee9..000000000
--- a/cmd/ethereum/repl/repl_windows.go
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-// MA 02110-1301  USA
-
-package ethrepl
-
-import (
-	"bufio"
-	"fmt"
-	"os"
-	"strings"
-)
-
-func (self *JSRepl) read() {
-	reader := bufio.NewReader(os.Stdin)
-	for {
-		fmt.Printf(self.prompt)
-		str, _, err := reader.ReadLine()
-		if err != nil {
-			fmt.Println("Error reading input", err)
-		} else {
-			if string(str) == "exit" {
-				self.Stop()
-				break
-			} else {
-				self.parseInput(string(str))
-			}
-		}
-	}
-}
-
-func addHistory(s string) {
-}
-
-func printColored(outputVal string) {
-	for outputVal != "" {
-		codePart := ""
-		if strings.HasPrefix(outputVal, "\033[32m") {
-			codePart = "\033[32m"
-			changeColor(2)
-		}
-		if strings.HasPrefix(outputVal, "\033[1m\033[30m") {
-			codePart = "\033[1m\033[30m"
-			changeColor(8)
-		}
-		if strings.HasPrefix(outputVal, "\033[31m") {
-			codePart = "\033[31m"
-			changeColor(red)
-		}
-		if strings.HasPrefix(outputVal, "\033[35m") {
-			codePart = "\033[35m"
-			changeColor(5)
-		}
-		if strings.HasPrefix(outputVal, "\033[0m") {
-			codePart = "\033[0m"
-			resetColorful()
-		}
-		textPart := outputVal[len(codePart):len(outputVal)]
-		index := strings.Index(textPart, "\033")
-		if index == -1 {
-			outputVal = ""
-		} else {
-			outputVal = textPart[index:len(textPart)]
-			textPart = textPart[0:index]
-		}
-		fmt.Printf("%v", textPart)
-	}
-}
-
-func (self *JSRepl) PrintValue(v interface{}) {
-	method, _ := self.re.Vm.Get("prettyPrint")
-	v, err := self.re.Vm.ToValue(v)
-	if err == nil {
-		val, err := method.Call(method, v)
-		if err == nil {
-			printColored(fmt.Sprintf("%v", val))
-		}
-	}
-}
-- 
GitLab