// RunWithPromptAndPrelude runs a REPL with the given prompt and prelude. func RunWithPromptAndPrelude(l *loop.Loop, prompt, prelude string) error { if prompt == "" { prompt = ">" } prompt = strings.Trim(prompt, " ") prompt += " " rl, err := readline.New(prompt) if err != nil { return err } l.VM().Set("console", map[string]interface{}{ "log": func(c otto.FunctionCall) otto.Value { s := make([]string, len(c.ArgumentList)) for i := 0; i < len(c.ArgumentList); i++ { s[i] = c.Argument(i).String() } rl.Stdout().Write([]byte(strings.Join(s, " ") + "\n")) rl.Refresh() return otto.UndefinedValue() }, "warn": func(c otto.FunctionCall) otto.Value { s := make([]string, len(c.ArgumentList)) for i := 0; i < len(c.ArgumentList); i++ { s[i] = c.Argument(i).String() } rl.Stderr().Write([]byte(strings.Join(s, " ") + "\n")) rl.Refresh() return otto.UndefinedValue() }, }) if prelude != "" { if _, err := io.Copy(rl.Stderr(), strings.NewReader(prelude+"\n")); err != nil { return err } rl.Refresh() } var d []string for { ll, err := rl.Readline() if err != nil { if err == readline.ErrInterrupt { if d != nil { d = nil rl.SetPrompt(prompt) rl.Refresh() continue } break } return err } if len(d) == 0 && ll == "" { continue } d = append(d, ll) s := strings.Join(d, "\n") if _, err := parser.ParseFile(nil, "repl", s, 0); err != nil { rl.SetPrompt(strings.Repeat(" ", len(prompt))) } else { rl.SetPrompt(prompt) d = nil t := looptask.NewEvalTask(s) // don't report errors to the loop - this lets us handle them and // resume normal operation t.SoftError = true l.Add(t) l.Ready(t) v, err := <-t.Value, <-t.Error if err != nil { if oerr, ok := err.(*otto.Error); ok { io.Copy(rl.Stdout(), strings.NewReader(oerr.String())) } else { io.Copy(rl.Stdout(), strings.NewReader(err.Error())) } } else { f, err := format(v, 80, 2, 5) if err != nil { panic(err) } rl.Stdout().Write([]byte(f + "\n")) } } rl.Refresh() } return rl.Close() }
func main() { flag.Parse() vm := otto.New() if *debugger { vm.SetDebuggerHandler(repl.DebuggerHandler) } l := loop.New(vm) if err := timers.Define(vm, l); err != nil { panic(err) } if err := promise.Define(vm, l); err != nil { panic(err) } if err := fetch.Define(vm, l); err != nil { panic(err) } if err := process.Define(vm, flag.Args()); err != nil { panic(err) } blockingTask := looptask.NewEvalTask("") if len(flag.Args()) == 0 || *openRepl { l.Add(blockingTask) } if len(flag.Args()) > 0 { d, err := ioutil.ReadFile(flag.Arg(0)) if err != nil { panic(err) } // this is a very cheap way of "supporting" shebang lines if d[0] == '#' { d = []byte("// " + string(d)) } s, err := vm.Compile(flag.Arg(0), string(d)) if err != nil { panic(err) } if err := l.Eval(s); err != nil { panic(err) } } if len(flag.Args()) == 0 || *openRepl { go func() { if err := erepl.Run(l); err != nil && err != io.EOF { panic(err) } l.Ready(blockingTask) }() } if err := l.Run(); err != nil { panic(err) } }