// Package repl Basic UI for the user package repl import ( "bufio" "fmt" "io" "os" "strings" ) var DefaultCfg = REPLCfg{ PS1: "\r> ", } type REPLCfg struct { PS1 string } type REPL struct { Stop bool Cfg REPLCfg Commands map[string]Command } func NewREPL(cfg REPLCfg) *REPL { return &REPL{ Cfg: cfg, Commands: map[string]Command{ helpCmd.Name: helpCmd, clearCmd.Name: clearCmd, exitCmd.Name: exitCmd, }, } } func (r *REPL) Close() { // Do whatever cleanup we have to do } func (r *REPL) RegisterCMD(newCMD Command) { // Add a verification to check that the command doesn't exist. Fatal if it does r.Commands[newCMD.Name] = newCMD } func (r *REPL) printPrompt() { _, _ = os.Stdout.Write([]byte(r.Cfg.PS1)) } func (r *REPL) SetPS1(s string) { r.Cfg.PS1 = s } func (r *REPL) mainLoop() { reader := bufio.NewReader(os.Stdin) for { r.printPrompt() line, err := reader.ReadString('\n') if err != nil { if err == io.EOF { break } fmt.Println("error: ", err) continue } args := parseInput(strings.TrimSpace(line)) if args[0] == "" { continue } command, exists := r.Commands[args[0]] if exists { _ = command.Action(r, args[1:]) } else { fmt.Printf("No such command `%s`\n", args[0]) } if r.Stop { break } } } func (r *REPL) Start() { // Setup handlers and whatnot r.mainLoop() }