// Safe invokes the provided function and will attempt to ensure that when the // function returns (or a termination signal is sent) that the terminal state // is reset to the condition it was in prior to the function being invoked. If // t.Raw is true the terminal will be put into raw mode prior to calling the function. // If the input file descriptor is not a TTY and TryDev is true, the /dev/tty file // will be opened (if available). func (t TTY) Safe(fn SafeFunc) error { in := t.In var hasFd bool var inFd uintptr if desc, ok := in.(fd); ok && in != nil { inFd = desc.Fd() hasFd = true } if t.TryDev && (!hasFd || !term.IsTerminal(inFd)) { if f, err := os.Open("/dev/tty"); err == nil { defer f.Close() inFd = f.Fd() hasFd = true } } if !hasFd || !term.IsTerminal(inFd) { return fn() } var state *term.State var err error if t.Raw { state, err = term.MakeRaw(inFd) } else { state, err = term.SaveState(inFd) } if err != nil { return err } return interrupt.Chain(t.Parent, func() { term.RestoreTerminal(inFd, state) }).Run(fn) }
// Safe invokes the provided function and will attempt to ensure that when the // function returns (or a termination signal is sent) that the terminal state // is reset to the condition it was in prior to the function being invoked. If // t.Raw is true the terminal will be put into raw mode prior to calling the function. // If the input file descriptor is not a TTY and TryDev is true, the /dev/tty file // will be opened (if available). func (t TTY) Safe(fn SafeFunc) error { inFd, isTerminal := term.GetFdInfo(t.In) if !isTerminal && t.TryDev { if f, err := os.Open("/dev/tty"); err == nil { defer f.Close() inFd = f.Fd() isTerminal = term.IsTerminal(inFd) } } if !isTerminal { return fn() } var state *term.State var err error if t.Raw { state, err = term.MakeRaw(inFd) } else { state, err = term.SaveState(inFd) } if err != nil { return err } return interrupt.Chain(t.Parent, func() { if t.sizeQueue != nil { t.sizeQueue.stop() } term.RestoreTerminal(inFd, state) }).Run(fn) }