repl_darwin.go 2.92 KB
Newer Older
Felix Lange's avatar
Felix Lange committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// 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

18
package ethrepl
obscuren's avatar
obscuren committed
19

obscuren's avatar
obscuren committed
20 21
// #cgo darwin CFLAGS: -I/usr/local/opt/readline/include
// #cgo darwin LDFLAGS: -L/usr/local/opt/readline/lib
obscuren's avatar
obscuren committed
22 23 24 25 26 27
// #cgo LDFLAGS: -lreadline
// #include <stdio.h>
// #include <stdlib.h>
// #include <readline/readline.h>
// #include <readline/history.h>
import "C"
obscuren's avatar
obscuren committed
28
import (
obscuren's avatar
obscuren committed
29
	"fmt"
obscuren's avatar
obscuren committed
30 31
	"os"
	"os/signal"
obscuren's avatar
obscuren committed
32
	"strings"
obscuren's avatar
obscuren committed
33
	"syscall"
obscuren's avatar
obscuren committed
34 35
	"unsafe"
)
obscuren's avatar
obscuren committed
36

obscuren's avatar
obscuren committed
37 38
func initReadLine() {
	C.rl_catch_sigwinch = 0
obscuren's avatar
obscuren committed
39
	C.rl_catch_signals = 0
obscuren's avatar
obscuren committed
40 41
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGWINCH)
obscuren's avatar
obscuren committed
42
	signal.Notify(c, os.Interrupt)
obscuren's avatar
obscuren committed
43 44 45 46 47
	go func() {
		for sig := range c {
			switch sig {
			case syscall.SIGWINCH:
				C.rl_resize_terminal()
obscuren's avatar
obscuren committed
48 49 50

			case os.Interrupt:
				C.rl_cleanup_after_signal()
obscuren's avatar
obscuren committed
51 52 53 54 55 56 57
			default:

			}
		}
	}()
}

obscuren's avatar
obscuren committed
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
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))
}

obscuren's avatar
obscuren committed
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
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 += " "
	}
}
obscuren's avatar
obscuren committed
103

obscuren's avatar
obscuren committed
104
func (self *JSRepl) read() {
obscuren's avatar
obscuren committed
105
	initReadLine()
obscuren's avatar
obscuren committed
106 107
L:
	for {
obscuren's avatar
obscuren committed
108
		switch result := readLine(&self.prompt); true {
obscuren's avatar
obscuren committed
109
		case result == nil:
obscuren's avatar
obscuren committed
110
			break L
obscuren's avatar
obscuren committed
111

obscuren's avatar
obscuren committed
112
		case *result != "":
obscuren's avatar
obscuren committed
113 114 115 116 117
			str += *result + "\n"

			self.setIndent()

			if indentCount <= 0 {
obscuren's avatar
obscuren committed
118 119 120 121 122
				if *result == "exit" {
					self.Stop()
					break L
				}

123 124 125
				hist := str[:len(str)-1]
				addHistory(hist) //allow user to recall this line
				self.history.WriteString(str)
obscuren's avatar
obscuren committed
126

obscuren's avatar
obscuren committed
127
				self.parseInput(str)
obscuren's avatar
obscuren committed
128 129

				str = ""
obscuren's avatar
obscuren committed
130
			}
obscuren's avatar
obscuren committed
131 132 133
		}
	}
}
obscuren's avatar
obscuren committed
134

135
func (self *JSRepl) PrintValue(v interface{}) {
136 137
	method, _ := self.re.Vm.Get("prettyPrint")
	v, err := self.re.Vm.ToValue(v)
138
	if err == nil {
139 140 141 142
		val, err := method.Call(method, v)
		if err == nil {
			fmt.Printf("%v", val)
		}
143
	}
obscuren's avatar
obscuren committed
144
}