func interact(ev *eval.Evaler, st *store.Store) { // Build Editor. sigch := make(chan os.Signal) signal.Notify(sigch) ed := edit.NewEditor(os.Stdin, sigch, ev, st) // Source rc.elv. datadir, err := store.EnsureDataDir() if err != nil { fmt.Fprintln(os.Stderr, err) } else { source(ev, datadir+"/rc.elv", true) } // Build readLine function. readLine := func() (string, error) { return ed.ReadLine() } cooldown := time.Second usingBasic := false cmdNum := 0 for { cmdNum++ // name := fmt.Sprintf("<tty %d>", cmdNum) line, err := readLine() if err == io.EOF { break } else if err != nil { fmt.Println("Editor error:", err) if !usingBasic { fmt.Println("Falling back to basic line editor") readLine = basicReadLine usingBasic = true } else { fmt.Println("Don't know what to do, pid is", os.Getpid()) fmt.Println("Restarting editor in", cooldown) time.Sleep(cooldown) if cooldown < time.Minute { cooldown *= 2 } } continue } // No error; reset cooldown. cooldown = time.Second n, err := parse.Parse(line) printError(err, "<interact>", "parse error", line) if err == nil { err := ev.EvalInteractive(line, n) printError(err, "<interact>", "eval error", line) } } }
// getIsExternal finds a set of all external commands and puts it on the result // channel. func getIsExternal(ev *eval.Evaler, result chan<- map[string]bool) { names := make(chan string, 32) go func() { ev.AllExecutables(names) close(names) }() isExternal := make(map[string]bool) for name := range names { isExternal[name] = true } result <- isExternal }
// NewEditor creates an Editor. func NewEditor(file *os.File, sigs chan os.Signal, ev *eval.Evaler, st *store.Store) *Editor { seq := -1 if st != nil { var err error seq, err = st.NextCmdSeq() if err != nil { // TODO(xiaq): Also report the error seq = -1 } } prompt, rprompt := defaultPrompts() ed := &Editor{ file: file, writer: newWriter(file), reader: NewReader(file), sigs: sigs, store: st, evaler: ev, cmdSeq: seq, ps1: eval.NewPtrVariableWithValidator(prompt, MustBeFn), rps1: eval.NewPtrVariableWithValidator(rprompt, MustBeFn), abbreviations: make(map[string]string), beforeReadLine: eval.NewPtrVariableWithValidator( eval.NewList(), eval.IsListOfFnValue), afterReadLine: eval.NewPtrVariableWithValidator( eval.NewList(), eval.IsListOfFnValue), } ev.Editor = ed ev.Modules["le"] = makeModule(ed) return ed }
func source(ev *eval.Evaler, fname string, notexistok bool) error { src, err := readFileUTF8(fname) if err != nil { if notexistok && os.IsNotExist(err) { return nil } fmt.Fprintln(os.Stderr, err) return err } err = ev.SourceText(src) if err != nil { printError(err, fname, "error", src) } return err }
// evalText is like eval.Evaler.SourceText except that it reports errors. func evalText(ev *eval.Evaler, name, src string) bool { n, err := parse.Parse(name, src) if err != nil { printError(err, "Parse error") return false } op, err := ev.Compile(n, name, src) if err != nil { printError(err, "Compile error") return false } err = ev.Eval(op, name, src) if err != nil { printError(err, "Exception") return false } return true }
// NewEditor creates an Editor. func NewEditor(file *os.File, sigs chan os.Signal, ev *eval.Evaler, st *store.Store) *Editor { seq := -1 if st != nil { var err error seq, err = st.NextCmdSeq() if err != nil { // TODO(xiaq): Also report the error seq = -1 } } ed := &Editor{ file: file, writer: newWriter(file), reader: NewReader(file), sigs: sigs, store: st, evaler: ev, cmdSeq: seq, } ev.AddModule("le", makeModule(ed)) return ed }