func NewSubProcess(name string, arg ...string) (sp *SubProcess, err error) { sp = new(SubProcess) if sp.Term, err = pty.NewTerminal(); err != nil { return } sp.cmd = exec.Command(name, arg...) sp.DelayBeforeSend = 50 * time.Microsecond sp.CheckInterval = time.Microsecond if x, y, err := pty.GetWinSize(os.Stdout); err == nil { sp.Term.SetWinSize(x, y) } return }
func (sp *SubProcess) InteractTimeout(d time.Duration) (err error) { sp.Write(sp.After) sp.After = []byte{} oldState, _ := pty.Tcgetattr(os.Stdin) pty.SetRaw(os.Stdin) defer pty.Tcsetattr(os.Stdin, oldState) s := make(chan os.Signal, 1) signal.Notify(s, syscall.SIGINT, syscall.SIGWINCH, syscall.SIGTSTP) go func() { for sig := range s { switch sig { case syscall.SIGINT: sp.Term.SendIntr() case syscall.SIGWINCH: if x, y, err := pty.GetWinSize(os.Stdout); err == nil { sp.Term.SetWinSize(x, y) } default: continue } } }() execerr := make(chan error, 1) if d > 0 { go func() { time.Sleep(d) execerr <- TIMEOUT }() } go func() { execerr <- sp.cmd.Wait() }() in := make(chan byte, 1) stdin := bufio.NewReader(os.Stdin) go func() error { var b byte for { if b, err = stdin.ReadByte(); err != nil { if err == io.EOF { sp.Term.SendEOF() continue } else { return err } } in <- b } }() go func() { io.Copy(os.Stdout, sp) return }() for { select { case err := <-execerr: return err case b := <-in: _, err = sp.Write([]byte{b}) } } return }