github.com/xyproto/u-root@v6.0.1-0.20200302025726-5528e0c77a3c+incompatible/cmds/core/elvish/program/shell/interact.go (about) 1 package shell 2 3 import ( 4 "bufio" 5 "fmt" 6 "io" 7 "os" 8 "os/signal" 9 "path/filepath" 10 "syscall" 11 "time" 12 13 "github.com/u-root/u-root/cmds/core/elvish/edit" 14 "github.com/u-root/u-root/cmds/core/elvish/eval" 15 "github.com/u-root/u-root/cmds/core/elvish/sys" 16 "github.com/u-root/u-root/cmds/core/elvish/util" 17 ) 18 19 func interact(ev *eval.Evaler, dataDir string) { 20 // Build Editor. 21 var ed editor 22 if sys.IsATTY(os.Stdin) { 23 sigch := make(chan os.Signal) 24 signal.Notify(sigch, syscall.SIGHUP, syscall.SIGINT, sys.SIGWINCH) 25 ed = edit.NewEditor(os.Stdin, os.Stderr, sigch, ev) 26 } else { 27 ed = newMinEditor(os.Stdin, os.Stderr) 28 } 29 defer ed.Close() 30 31 // Source rc.elv. 32 if dataDir != "" { 33 err := sourceRC(ev, dataDir) 34 if err != nil { 35 util.PprintError(err) 36 } 37 } 38 39 // Build readLine function. 40 readLine := func() (string, error) { 41 return ed.ReadLine() 42 } 43 44 cooldown := time.Second 45 usingBasic := false 46 cmdNum := 0 47 48 for { 49 cmdNum++ 50 51 line, err := readLine() 52 53 if err == io.EOF { 54 break 55 } else if err != nil { 56 fmt.Println("Editor error:", err) 57 if !usingBasic { 58 fmt.Println("Falling back to basic line editor") 59 readLine = basicReadLine 60 usingBasic = true 61 } else { 62 fmt.Println("Don't know what to do, pid is", os.Getpid()) 63 fmt.Println("Restarting editor in", cooldown) 64 time.Sleep(cooldown) 65 if cooldown < time.Minute { 66 cooldown *= 2 67 } 68 } 69 continue 70 } 71 72 // No error; reset cooldown. 73 cooldown = time.Second 74 75 err = ev.EvalSource(eval.NewInteractiveSource(line)) 76 if err != nil { 77 util.PprintError(err) 78 } 79 } 80 } 81 82 func sourceRC(ev *eval.Evaler, dataDir string) error { 83 absPath, err := filepath.Abs(filepath.Join(dataDir, "rc.elv")) 84 if err != nil { 85 return fmt.Errorf("cannot get full path of rc.elv: %v", err) 86 } 87 code, err := readFileUTF8(absPath) 88 if os.IsNotExist(err) { 89 return nil 90 } 91 if err != nil { 92 return err 93 } 94 95 return ev.SourceRC(eval.NewScriptSource("rc.elv", absPath, code)) 96 } 97 98 func basicReadLine() (string, error) { 99 stdin := bufio.NewReaderSize(os.Stdin, 0) 100 return stdin.ReadString('\n') 101 }