aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-10-09 18:27:47 -0500
committerJoel Martin <github@martintribe.org>2014-10-09 18:27:47 -0500
commitad7e866ea1d4d035d876e58bca681a72099449af (patch)
treecbd73a7cda5adc4aba7293231ab0efa3f107edb0
parentd667a1bb2e7294f8722bb31f1e6e8207b971c913 (diff)
downloadmal-ad7e866ea1d4d035d876e58bca681a72099449af.tar.gz
mal-ad7e866ea1d4d035d876e58bca681a72099449af.zip
go: add readline.go that wraps libreadline/libedit
-rw-r--r--go/Makefile3
-rw-r--r--go/src/core/core.go3
-rw-r--r--go/src/readline/readline.go70
-rw-r--r--go/src/step0_repl/step0_repl.go10
-rw-r--r--go/src/step1_read_print/step1_read_print.go8
-rw-r--r--go/src/step2_eval/step2_eval.go8
-rw-r--r--go/src/step3_env/step3_env.go8
-rw-r--r--go/src/step4_if_fn_do/step4_if_fn_do.go8
-rw-r--r--go/src/step5_tco/step5_tco.go8
-rw-r--r--go/src/step6_file/step6_file.go9
-rw-r--r--go/src/step7_quote/step7_quote.go9
-rw-r--r--go/src/step8_macros/step8_macros.go9
-rw-r--r--go/src/stepA_more/stepA_more.go9
13 files changed, 102 insertions, 60 deletions
diff --git a/go/Makefile b/go/Makefile
index 729d2cc..18faa4f 100644
--- a/go/Makefile
+++ b/go/Makefile
@@ -2,7 +2,8 @@ export GOPATH := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
#####################
-SOURCES_BASE = src/types/types.go src/reader/reader.go src/printer/printer.go \
+SOURCES_BASE = src/types/types.go src/readline/readline.go \
+ src/reader/reader.go src/printer/printer.go \
src/env/env.go src/core/core.go
SOURCES_LISP = src/stepA_more/stepA_more.go
SOURCES = $(SOURCES_BASE) $(SOURCES_LISP)
diff --git a/go/src/core/core.go b/go/src/core/core.go
index b3961e1..cd63930 100644
--- a/go/src/core/core.go
+++ b/go/src/core/core.go
@@ -10,6 +10,7 @@ import (
. "types"
"reader"
"printer"
+ "readline"
)
// Errors/Exceptions
@@ -150,6 +151,8 @@ var NS = map[string]MalType{
"read-string": func(a []MalType) (MalType, error) {
return reader.Read_str(a[0].(string)) },
"slurp": slurp,
+ "readline": func(a []MalType) (MalType, error) {
+ return readline.Readline(a[0].(string)) },
"<": func(a []MalType) (MalType, error) {
return a[0].(int) < a[1].(int), nil },
diff --git a/go/src/readline/readline.go b/go/src/readline/readline.go
new file mode 100644
index 0000000..2777cb4
--- /dev/null
+++ b/go/src/readline/readline.go
@@ -0,0 +1,70 @@
+package readline
+
+/*
+// IMPORTANT: choose one
+#cgo LDFLAGS: -ledit
+//#cgo LDFLAGS: -lreadline // NOTE: libreadline is GPL
+
+// free()
+#include <stdlib.h>
+// readline()
+#include <readline/readline.h>
+// add_history()
+#include <readline/history.h>
+*/
+import "C"
+
+import (
+ "errors"
+ "unsafe"
+ "strings"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "fmt"
+)
+
+var HISTORY_FILE = ".mal-history"
+
+var rl_history_loaded = false
+
+func Readline(prompt string) (string, error) {
+ history_path := filepath.Join(os.Getenv("HOME"), "/", HISTORY_FILE)
+
+ if !rl_history_loaded {
+ rl_history_loaded = true
+ content, e := ioutil.ReadFile(history_path)
+ if e != nil { return "", e }
+
+ for _, add_line := range strings.Split(string(content), "\n") {
+ if add_line == "" { continue }
+ c_add_line := C.CString(add_line)
+ C.add_history(c_add_line)
+ C.free(unsafe.Pointer(c_add_line))
+ }
+ }
+
+
+ c_prompt := C.CString(prompt)
+ defer C.free(unsafe.Pointer(c_prompt))
+
+ c_line := C.readline(c_prompt)
+ defer C.free(unsafe.Pointer(c_line))
+ line := C.GoString(c_line)
+
+ if c_line == nil {
+ return "", errors.New("C.readline call failed")
+ }
+ C.add_history(c_line)
+
+ // append to file
+ f, e := os.OpenFile(history_path, os.O_APPEND|os.O_WRONLY, 0600)
+ if e == nil {
+ defer f.Close()
+
+ _, e = f.WriteString(line+"\n")
+ if e != nil { fmt.Printf("error writing to history") }
+ }
+
+ return line, nil
+}
diff --git a/go/src/step0_repl/step0_repl.go b/go/src/step0_repl/step0_repl.go
index 1203213..2e4c47c 100644
--- a/go/src/step0_repl/step0_repl.go
+++ b/go/src/step0_repl/step0_repl.go
@@ -1,12 +1,14 @@
package main
import (
- "bufio"
"fmt"
- "os"
"strings"
)
+import (
+ "readline"
+)
+
// read
func READ(str string) string {
return str
@@ -28,11 +30,9 @@ func rep(str string) string {
}
func main() {
- reader := bufio.NewReader(os.Stdin);
// repl loop
for {
- fmt.Print("user> ");
- text, err := reader.ReadString('\n');
+ text, err := readline.Readline("user> ")
text = strings.TrimRight(text, "\n");
if (err != nil) {
return
diff --git a/go/src/step1_read_print/step1_read_print.go b/go/src/step1_read_print/step1_read_print.go
index edd8c42..e008ed5 100644
--- a/go/src/step1_read_print/step1_read_print.go
+++ b/go/src/step1_read_print/step1_read_print.go
@@ -1,14 +1,12 @@
package main
import (
- "bufio"
- //"io"
"fmt"
- "os"
"strings"
)
import (
+ "readline"
. "types"
"reader"
"printer"
@@ -41,11 +39,9 @@ func rep(str string) (MalType, error) {
}
func main() {
- rdr := bufio.NewReader(os.Stdin);
// repl loop
for {
- fmt.Print("user> ");
- text, err := rdr.ReadString('\n');
+ text, err := readline.Readline("user> ")
text = strings.TrimRight(text, "\n");
if (err != nil) {
return
diff --git a/go/src/step2_eval/step2_eval.go b/go/src/step2_eval/step2_eval.go
index 3ab35ed..9b3aa28 100644
--- a/go/src/step2_eval/step2_eval.go
+++ b/go/src/step2_eval/step2_eval.go
@@ -1,15 +1,13 @@
package main
import (
- "bufio"
- //"io"
"fmt"
- "os"
"strings"
"errors"
)
import (
+ "readline"
. "types"
"reader"
"printer"
@@ -110,11 +108,9 @@ func rep(str string) (MalType, error) {
}
func main() {
- rdr := bufio.NewReader(os.Stdin);
// repl loop
for {
- fmt.Print("user> ");
- text, err := rdr.ReadString('\n');
+ text, err := readline.Readline("user> ")
text = strings.TrimRight(text, "\n");
if (err != nil) {
return
diff --git a/go/src/step3_env/step3_env.go b/go/src/step3_env/step3_env.go
index 68a8f0c..7e45a39 100644
--- a/go/src/step3_env/step3_env.go
+++ b/go/src/step3_env/step3_env.go
@@ -1,15 +1,13 @@
package main
import (
- "bufio"
- //"io"
"fmt"
- "os"
"strings"
"errors"
)
import (
+ "readline"
. "types"
"reader"
"printer"
@@ -138,11 +136,9 @@ func main() {
repl_env.Set("/", func(a []MalType) (MalType, error) {
return a[0].(int) / a[1].(int), nil })
- rdr := bufio.NewReader(os.Stdin);
// repl loop
for {
- fmt.Print("user> ");
- text, err := rdr.ReadString('\n');
+ text, err := readline.Readline("user> ")
text = strings.TrimRight(text, "\n");
if (err != nil) {
return
diff --git a/go/src/step4_if_fn_do/step4_if_fn_do.go b/go/src/step4_if_fn_do/step4_if_fn_do.go
index 7a91a2b..760919b 100644
--- a/go/src/step4_if_fn_do/step4_if_fn_do.go
+++ b/go/src/step4_if_fn_do/step4_if_fn_do.go
@@ -1,15 +1,13 @@
package main
import (
- "bufio"
- //"io"
"fmt"
- "os"
"strings"
"errors"
)
import (
+ "readline"
. "types"
"reader"
"printer"
@@ -162,11 +160,9 @@ func main() {
// core.mal: defined using the language itself
rep("(def! not (fn* (a) (if a false true)))")
- rdr := bufio.NewReader(os.Stdin);
// repl loop
for {
- fmt.Print("user> ");
- text, err := rdr.ReadString('\n');
+ text, err := readline.Readline("user> ")
text = strings.TrimRight(text, "\n");
if (err != nil) {
return
diff --git a/go/src/step5_tco/step5_tco.go b/go/src/step5_tco/step5_tco.go
index a15d9e5..c7c2ab5 100644
--- a/go/src/step5_tco/step5_tco.go
+++ b/go/src/step5_tco/step5_tco.go
@@ -1,15 +1,13 @@
package main
import (
- "bufio"
- //"io"
"fmt"
- "os"
"strings"
"errors"
)
import (
+ "readline"
. "types"
"reader"
"printer"
@@ -172,11 +170,9 @@ func main() {
// core.mal: defined using the language itself
rep("(def! not (fn* (a) (if a false true)))")
- rdr := bufio.NewReader(os.Stdin);
// repl loop
for {
- fmt.Print("user> ");
- text, err := rdr.ReadString('\n');
+ text, err := readline.Readline("user> ")
text = strings.TrimRight(text, "\n");
if (err != nil) {
return
diff --git a/go/src/step6_file/step6_file.go b/go/src/step6_file/step6_file.go
index 205b597..056fe39 100644
--- a/go/src/step6_file/step6_file.go
+++ b/go/src/step6_file/step6_file.go
@@ -1,15 +1,14 @@
package main
import (
- "bufio"
- //"io"
"fmt"
- "os"
"strings"
"errors"
+ "os"
)
import (
+ "readline"
. "types"
"reader"
"printer"
@@ -187,11 +186,9 @@ func main() {
os.Exit(0)
}
- rdr := bufio.NewReader(os.Stdin);
// repl loop
for {
- fmt.Print("user> ");
- text, err := rdr.ReadString('\n');
+ text, err := readline.Readline("user> ")
text = strings.TrimRight(text, "\n");
if (err != nil) {
return
diff --git a/go/src/step7_quote/step7_quote.go b/go/src/step7_quote/step7_quote.go
index 4083354..68c2a85 100644
--- a/go/src/step7_quote/step7_quote.go
+++ b/go/src/step7_quote/step7_quote.go
@@ -1,15 +1,14 @@
package main
import (
- "bufio"
- //"io"
"fmt"
- "os"
"strings"
"errors"
+ "os"
)
import (
+ "readline"
. "types"
"reader"
"printer"
@@ -220,11 +219,9 @@ func main() {
os.Exit(0)
}
- rdr := bufio.NewReader(os.Stdin);
// repl loop
for {
- fmt.Print("user> ");
- text, err := rdr.ReadString('\n');
+ text, err := readline.Readline("user> ")
text = strings.TrimRight(text, "\n");
if (err != nil) {
return
diff --git a/go/src/step8_macros/step8_macros.go b/go/src/step8_macros/step8_macros.go
index 6735275..82572d3 100644
--- a/go/src/step8_macros/step8_macros.go
+++ b/go/src/step8_macros/step8_macros.go
@@ -1,15 +1,14 @@
package main
import (
- "bufio"
- //"io"
"fmt"
- "os"
"strings"
"errors"
+ "os"
)
import (
+ "readline"
. "types"
"reader"
"printer"
@@ -259,11 +258,9 @@ func main() {
os.Exit(0)
}
- rdr := bufio.NewReader(os.Stdin);
// repl loop
for {
- fmt.Print("user> ");
- text, err := rdr.ReadString('\n');
+ text, err := readline.Readline("user> ")
text = strings.TrimRight(text, "\n");
if (err != nil) {
return
diff --git a/go/src/stepA_more/stepA_more.go b/go/src/stepA_more/stepA_more.go
index 2532cfe..be693f6 100644
--- a/go/src/stepA_more/stepA_more.go
+++ b/go/src/stepA_more/stepA_more.go
@@ -1,15 +1,14 @@
package main
import (
- "bufio"
- //"io"
"fmt"
- "os"
"strings"
"errors"
+ "os"
)
import (
+ "readline"
. "types"
"reader"
"printer"
@@ -281,11 +280,9 @@ func main() {
os.Exit(0)
}
- rdr := bufio.NewReader(os.Stdin);
// repl loop
for {
- fmt.Print("user> ");
- text, err := rdr.ReadString('\n');
+ text, err := readline.Readline("user> ")
text = strings.TrimRight(text, "\n");
if (err != nil) {
return