2014-07-15 21:34:25 +03:00
|
|
|
package ethrepl
|
2014-05-17 16:15:46 +03:00
|
|
|
|
2014-05-22 00:36:55 +03:00
|
|
|
// #cgo darwin CFLAGS: -I/usr/local/opt/readline/include
|
|
|
|
// #cgo darwin LDFLAGS: -L/usr/local/opt/readline/lib
|
2014-05-17 16:15:46 +03:00
|
|
|
// #cgo LDFLAGS: -lreadline
|
|
|
|
// #include <stdio.h>
|
|
|
|
// #include <stdlib.h>
|
|
|
|
// #include <readline/readline.h>
|
|
|
|
// #include <readline/history.h>
|
|
|
|
import "C"
|
2014-05-19 14:04:31 +03:00
|
|
|
import (
|
2014-05-22 00:36:55 +03:00
|
|
|
"os"
|
|
|
|
"os/signal"
|
2014-05-19 14:04:31 +03:00
|
|
|
"strings"
|
2014-05-22 00:36:55 +03:00
|
|
|
"syscall"
|
2014-05-19 14:04:31 +03:00
|
|
|
"unsafe"
|
|
|
|
)
|
2014-05-17 16:15:46 +03:00
|
|
|
|
2014-05-22 00:36:55 +03:00
|
|
|
func initReadLine() {
|
|
|
|
C.rl_catch_sigwinch = 0
|
2014-05-22 00:46:16 +03:00
|
|
|
C.rl_catch_signals = 0
|
2014-05-22 00:36:55 +03:00
|
|
|
c := make(chan os.Signal, 1)
|
|
|
|
signal.Notify(c, syscall.SIGWINCH)
|
2014-05-22 00:46:16 +03:00
|
|
|
signal.Notify(c, os.Interrupt)
|
2014-05-22 00:36:55 +03:00
|
|
|
go func() {
|
|
|
|
for sig := range c {
|
|
|
|
switch sig {
|
|
|
|
case syscall.SIGWINCH:
|
|
|
|
C.rl_resize_terminal()
|
2014-05-22 00:46:16 +03:00
|
|
|
|
|
|
|
case os.Interrupt:
|
|
|
|
C.rl_cleanup_after_signal()
|
2014-05-22 00:36:55 +03:00
|
|
|
default:
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
2014-05-17 16:15:46 +03:00
|
|
|
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))
|
|
|
|
}
|
|
|
|
|
2014-05-19 14:04:31 +03:00
|
|
|
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 += " "
|
|
|
|
}
|
|
|
|
}
|
2014-05-17 16:15:46 +03:00
|
|
|
|
2014-05-19 14:04:31 +03:00
|
|
|
func (self *JSRepl) read() {
|
2014-05-22 00:36:55 +03:00
|
|
|
initReadLine()
|
2014-05-17 16:15:46 +03:00
|
|
|
L:
|
|
|
|
for {
|
2014-05-19 14:04:31 +03:00
|
|
|
switch result := readLine(&self.prompt); true {
|
2014-05-17 16:15:46 +03:00
|
|
|
case result == nil:
|
2014-05-19 17:32:45 +03:00
|
|
|
break L
|
2014-05-17 16:15:46 +03:00
|
|
|
|
2014-05-19 17:32:45 +03:00
|
|
|
case *result != "":
|
2014-05-19 14:04:31 +03:00
|
|
|
str += *result + "\n"
|
|
|
|
|
|
|
|
self.setIndent()
|
|
|
|
|
|
|
|
if indentCount <= 0 {
|
2014-05-19 17:32:45 +03:00
|
|
|
if *result == "exit" {
|
|
|
|
self.Stop()
|
|
|
|
break L
|
|
|
|
}
|
|
|
|
|
2014-06-24 11:09:02 +03:00
|
|
|
hist := str[:len(str)-1]
|
|
|
|
addHistory(hist) //allow user to recall this line
|
|
|
|
self.history.WriteString(str)
|
2014-05-17 16:15:46 +03:00
|
|
|
|
2014-05-19 14:04:31 +03:00
|
|
|
self.parseInput(str)
|
2014-05-19 17:32:45 +03:00
|
|
|
|
|
|
|
str = ""
|
2014-05-19 14:04:31 +03:00
|
|
|
}
|
2014-05-17 16:15:46 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-05-19 17:32:45 +03:00
|
|
|
|
2014-05-20 20:28:48 +03:00
|
|
|
func (self *JSRepl) PrintValue(v interface{}) {
|
2014-05-19 17:32:45 +03:00
|
|
|
method, _ := self.re.vm.Get("prettyPrint")
|
2014-05-20 20:28:48 +03:00
|
|
|
v, err := self.re.vm.ToValue(v)
|
|
|
|
if err == nil {
|
|
|
|
method.Call(method, v)
|
|
|
|
}
|
2014-05-19 17:32:45 +03:00
|
|
|
}
|