on master help sign in
Thunk
commitfa103b1de4e966b9896b6d72f0839378a4136aac authorRob Blanckaert <basicer@basicer.com> dateFri 12 Oct 2018, 18:12 (8 years ago) parent93b201f
8 files changed+209−7
Dockerfile+13 src/language.go+15−2 src/languages/python3/main.go+3−3 src/languages/ruby/main.go+16 src/languages/tcl/main.go+83 src/linenoise-helper.c+11 src/linenoise.go+52−1 src/main.go+16−1
Dockerfilenew file+13
@@ -0,0 +1,13 @@
1+FROM ubuntu:bionic
2+
3+RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential wget golang python-dev python3-dev liblua5.2-dev ruby2.5-dev tcl-dev libnspr4-dev libffi-dev
4+
5+RUN wget http://launchpadlibrarian.net/309343864/libmozjs185-dev_1.8.5-1.0.0+dfsg-7_amd64.deb && wget http://launchpadlibrarian.net/309343863/libmozjs185-1.0_1.8.5-1.0.0+dfsg-7_amd64.deb && dpkg -i libmozjs185*.deb && rm libmozjs185*.deb
6+
7+ADD . /prybar
8+RUN cd /prybar && make
9+
10+WORKDIR /prybar
11+
12+# ENTRYPOINT ['/prybar/prybar']
13+# CMD ['/prybar/prybar', '-h']
src/language.go+15−2
@@ -5,6 +5,7 @@ import(
55 "plugin"
66 "fmt"
77 "runtime"
8+ "path/filepath"
89)
910
1011type PluginBase interface {
@@ -46,8 +47,20 @@ func finalizer(f *Langauge) {
4647 fmt.Println("a finalizer has run.")
4748}
4849
49−func GetLanguage(name string) *Langauge {
50− plug, err := plugin.Open("./plugins/" + name + ".so")
50+func GetLanguage(name string) *Langauge {
51+ base := "."
52+ exe, err := os.Executable()
53+ for {
54+ o, err := os.Readlink(exe)
55+ if err == nil {
56+ exe = o
57+ } else {
58+ break
59+ }
60+ }
61+
62+ base = filepath.Dir(exe)
63+ plug, err := plugin.Open(base + "/plugins/" + name + ".so")
5164
5265 if err != nil {
5366 fmt.Println(err)
src/languages/python3/main.go+3−3
@@ -1,14 +1,14 @@
11package main
22
33/*
4−#cgo pkg-config: python2
4+#cgo pkg-config: python3
55#include <Python.h>
66
77void pry_eval_file(FILE* f, const char* file, int argn, const char *argv) {
8− const char* xargv[argn+1];
8+ const wchar_t* xargv[argn+1];
99 const char* ptr = argv;
1010 for (int i = 0; i < argn; ++i) {
11− xargv[i] = ptr;
11+ xargv[i] = Py_DecodeLocale(ptr, NULL);
1212 ptr += strlen(ptr) + 1;
1313 }
1414 xargv[argn] = NULL;
src/languages/ruby/main.go+16
@@ -39,6 +39,16 @@ char * pry_eval(const char* code) {
3939
4040}
4141
42+void pry_eval_file(const char* file ) {
43+ char* options[] = { "ruby", file };
44+ void* node = ruby_options(2, options);
45+
46+ int state;
47+ if (ruby_executable_node(node, &state))
48+ {
49+ state = ruby_exec_node(node);
50+ }
51+}
4252
4353*/
4454import "C"
@@ -71,6 +81,12 @@ func (p Ruby) EvalExpression(code string) string {
7181 return C.GoString(res);
7282}
7383
84+func (p Ruby) EvalFile(file string, args []string) {
85+ cfile := C.CString(file)
86+ defer C.free(unsafe.Pointer(cfile))
87+ C.pry_eval_file(cfile)
88+}
89+
7490func (p Ruby) REPL() {
7591 p.Eval("require 'irb'\nbinding.irb")
7692}
src/languages/tcl/main.gonew file+83
@@ -0,0 +1,83 @@
1+package main
2+
3+/*
4+#cgo pkg-config: tcl
5+#include <stdlib.h>
6+#include <tcl.h>
7+
8+Tcl_Interp *interp;
9+int ExtendTcl (Tcl_Interp *interp) {
10+
11+ return TCL_OK;
12+}
13+
14+void pry_open() {
15+ interp = Tcl_CreateInterp();
16+ if (Tcl_Init(interp) != TCL_OK) {
17+ exit(8);
18+ }
19+}
20+
21+void pry_close() {
22+ Tcl_Finalize();
23+}
24+
25+char * pry_version() {
26+ char *result = malloc(100);
27+ int a, b, c;
28+ Tcl_GetVersion(&a, &b, &c, NULL);
29+ sprintf(result, "%d.%d.%d",a,b,c);
30+ return result;
31+}
32+
33+char * pry_eval(const char* code) {
34+ if ( Tcl_Eval(interp, code) == TCL_OK ) {
35+ return Tcl_GetStringResult(interp);
36+ } else {
37+ fprintf(stderr, "error: %s\n", Tcl_GetStringResult (interp));
38+ return "";
39+ }
40+}
41+
42+*/
43+import "C"
44+
45+import (
46+ "unsafe"
47+)
48+
49+
50+type Python struct {
51+
52+}
53+
54+func (p Python) Open() {
55+ C.pry_open()
56+}
57+
58+func (p Python) Version() string {
59+ cver := C.pry_version()
60+ ver := C.GoString(cver)
61+ C.free(unsafe.Pointer(cver))
62+ return "TCL " + ver
63+}
64+
65+func (p Python) Eval(code string) {
66+ ccode := C.CString(code)
67+ defer C.free(unsafe.Pointer(ccode))
68+ C.pry_eval(ccode)
69+}
70+
71+func (p Python) EvalExpression(code string) string {
72+ ccode := C.CString(code)
73+ defer C.free(unsafe.Pointer(ccode))
74+ return C.GoString(C.pry_eval(ccode))
75+}
76+
77+
78+func (p Python) Close() {
79+ C.pry_close()
80+}
81+
82+// exported
83+var Instance Python
src/linenoise-helper.cnew file+11
@@ -0,0 +1,11 @@
1+#include <stdlib.h>
2+#include <linenoise.h>
3+
4+void linenoiseCompletionStub(const char *, linenoiseCompletions *);
5+void linenoiseHintsStub(const char *, int *color, int *bold);
6+
7+
8+void linenoise_setup() {
9+ linenoiseSetCompletionCallback(linenoiseCompletionStub);
10+ linenoiseSetHintsCallback(linenoiseHintsStub);
11+}
src/linenoise.go+52−1
@@ -3,6 +3,10 @@ package main
33/*
44#include <stdlib.h>
55#include <linenoise.h>
6+
7+void linenoise_setup();
8+
9+
610*/
711import "C"
812
@@ -11,7 +15,45 @@ import (
1115 "fmt"
1216)
1317
18+type Completer func(line string) []string
19+type Hinter func(line string) string
20+
21+
22+var completer Completer
23+var hinter Hinter
24+
25+//export linenoiseCompletionStub
26+func linenoiseCompletionStub(input *C.char, completions *C.linenoiseCompletions) {
27+ if completer == nil {
28+ return
29+ }
30+ completionsSlice := completer(C.GoString(input))
31+ completionsLen := len(completionsSlice)
32+ completions.len = C.size_t(completionsLen)
33+
34+ if completionsLen > 0 {
35+ cvec := C.malloc(C.size_t(int(unsafe.Sizeof(*(**C.char)(nil))) * completionsLen))
36+ cvecSlice := (*(*[999999]*C.char)(cvec))[:completionsLen]
37+
38+ for i, str := range completionsSlice {
39+ cvecSlice[i] = C.CString(str)
40+ }
41+ completions.cvec = (**C.char)(cvec)
42+ }
43+}
44+
45+//export linenoiseHintsStub
46+func linenoiseHintsStub(input *C.char, color *C.int, bold *C.int) *C.char {
47+ if hinter == nil {
48+ return nil
49+ }
50+ *color = 37
51+ *bold = 0
52+ return C.CString(hinter(C.GoString(input)))
53+}
54+
1455func Linenoise(prompt string) (string,error) {
56+ C.linenoise_setup()
1557 cprompt := C.CString(prompt)
1658 defer C.free(unsafe.Pointer(cprompt))
1759 cresult := C.linenoise(cprompt)
@@ -27,4 +69,13 @@ func LinenoiseHistoryAdd(line string) {
2769 data := C.CString(line)
2870 defer C.free(unsafe.Pointer(data))
2971 C.linenoiseHistoryAdd(data)
30−}
72+}
73+
74+func LinenoiseSetCompleter(newCompleter Completer) {
75+ completer = newCompleter
76+}
77+
78+func LinenoiseSetHinter(newHinter Hinter) {
79+ hinter = newHinter
80+}
81+
src/main.go+16−1
@@ -3,6 +3,8 @@ package main
33import (
44 "fmt"
55 "flag"
6+ "os"
7+ "strings"
68)
79
810var ps1, ps2 string
@@ -14,8 +16,12 @@ func main() {
1416 var quiet bool
1517 var exp string
1618
19+ defaultLangague := os.Args[0]
20+ if defaultLangague == "prybar" || strings.ContainsAny(defaultLangague,"./") {
21+ defaultLangague = "python2"
22+ }
1723
18− flag.StringVar(&language, "l", "python2", "langauge")
24+ flag.StringVar(&language, "l", defaultLangague, "langauge")
1925 flag.StringVar(&code, "c", "", "code to run")
2026 flag.StringVar(&exp, "e", "", "expression to print")
2127
@@ -29,6 +35,12 @@ func main() {
2935
3036 args := flag.Args()
3137
38+ switch language {
39+ case "python":
40+ language = "python3"
41+ case "javascript":
42+ language = "spidermonkey"
43+ }
3244
3345 lang := GetLanguage(language)
3446 if !quiet {
@@ -46,6 +58,9 @@ func main() {
4658 if interactive {
4759 lang.REPL()
4860 } else if ourInteractive {
61+ LinenoiseSetCompleter(func(s string) []string {
62+ return []string { s+"A", s+"B", s+"B"}
63+ })
4964 lang.InternalREPL()
5065 }
5166