Skip to content

OpenEngineer/go-repl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

go-repl

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

Usage

Fetch this library with the following command:

$ go get -u github.com/openengineer/go-repl

In order to create your own REPL you have to define a type that implements the Handler interface:

type Handler interface {
  Prompt() string
  Tab(buffer string) string
  Eval(line string) 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"
)

var helpMessage = `help              display this message
add <int> <int>   add two numbers
quit              quit this program`

// implements repl.Handler interface
type MyHandler struct {
  r *repl.Repl
}

func main() {
  fmt.Println("Welcome, type \"help\" for more info")

  h := &MyHandler{}
  h.r = repl.NewRepl(h)

  // start the terminal loop
  if err := h.r.Loop(); err != nil {
    log.Fatal(err)
  }
}

func (h *MyHandler) Prompt() string {
  return "> " 
}

func (h *MyHandler) Tab(buffer string) string {
  return "" // do nothing
}

func (h *MyHandler) Eval(line string) string {
  fields := strings.Fields(line)

  if len(fields) == 0 {
    return ""
  } else {
    cmd, args := fields[0], fields[1:]

    switch cmd {
    case "help":
      return helpMessage
    case "add":
      if len(args) != 2 {
        return "\"add\" expects 2 args"
      } else {
        return add(args[0], args[1])
      }
    case "quit":
      h.r.Quit()
      return ""
    default:
      return fmt.Sprintf("unrecognized command \"%s\"", cmd)
    }
  }
}

func add(a_ string, b_ string) string {
  a, err := strconv.Atoi(a_)
  if err != nil {
    return "first arg is not an integer"
  }

  b, err := strconv.Atoi(b_)
  if err != nil {
    return "second arg is not an integer"
  }

  return strconv.Itoa(a + b)
}

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published