Lightweight Golang REPL library, inspired by GNU Readline. You provide the Eval function, and go-repl does the rest.
Your REPLs that use this library will enjoy the following features:
- Session history with reverse-search
- Ctrl-R to start reverse-search
- Most edit commands, except the most basic ones, exit the reverse-search mode
- Use Up/Down to cycle through a filtered list of history entries
- The input buffer is redrawn when a resize is detected
- Status bar at bottom with current working dir and other info
- Truncation of very long inputs (status bar displays info about cursor position)
- Common edit and movement commands:
- Right/Left: move cursor one character at a time
- Ctrl-Right/Left: move cursor one word at a time
- Up/Down: cycle through history
- Backspace/Delete: works as expected
- Shift-Enter: insert newline into buffer without invoking
Eval - Ctrl-A or Home: move to start of buffer
- Ctrl-E or End: move to end of buffer
- Ctrl-W: delete preceding word
- Ctrl-Q: delete following word
- Ctrl-C or Esc: ignore current input and reset buffer
- Ctrl-D: quit REPL
- Ctrl-U: clear buffer to start
- Ctrl-K: clear buffer to end
- Ctrl-L: reset prompt at top and redraw buffer
- Ctrl-Y: insert previous deletion (from Ctrl-K, Ctrl-U, Ctrl-Q or Ctrl-W)
Notes:
- Doesn't depend on ncurses
- Performance hasn't yet been optimized and I haven't yet tested all corner cases exhaustively
- Might not work in Windows command prompt (keystroke codes could differ, ANSI escape sequences might not be supported, the method that sets terminal to raw mode might not work)
- No vi edit mode
- No support for clipboards yet
Fetch this library with the following command:
$ go get -u github.com/openengineer/go-replIn order to create your own REPL you have to define a type that implements the Handler interface:
typeHandlerinterface {
Prompt() stringTab(bufferstring) stringEval(linestring) string
}Here is a complete example (can also be found in ./examples/basic_repl.go):
package main
import (
"fmt""log""strconv""strings"
repl "github.com/openengineer/go-repl"
)
varhelpMessage=`help display this messageadd <int> <int> add two numbersquit quit this program`// implements repl.Handler interfacetypeMyHandlerstruct {
r*repl.Repl
}
funcmain() {
fmt.Println("Welcome, type \"help\" for more info")
h:=&MyHandler{}
h.r=repl.NewRepl(h)
// start the terminal loopiferr:=h.r.Loop(); err!=nil {
log.Fatal(err)
}
}
func (h*MyHandler) Prompt() string {
return"> " }
func (h*MyHandler) Tab(bufferstring) string {
return""// do nothing
}
func (h*MyHandler) Eval(linestring) string {
fields:=strings.Fields(line)
iflen(fields) ==0 {
return""
} else {
cmd, args:=fields[0], fields[1:]
switchcmd {
case"help":
returnhelpMessagecase"add":
iflen(args) !=2 {
return"\"add\" expects 2 args"
} else {
returnadd(args[0], args[1])
}
case"quit":
h.r.Quit()
return""default:
returnfmt.Sprintf("unrecognized command \"%s\"", cmd)
}
}
}
funcadd(a_string, b_string) string {
a, err:=strconv.Atoi(a_)
iferr!=nil {
return"first arg is not an integer"
}
b, err:=strconv.Atoi(b_)
iferr!=nil {
return"second arg is not an integer"
}
returnstrconv.Itoa(a+b)
}