blob: 6641cb8960b394fdf0882614307b40cd230e2559 [file] [log] [blame]
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
// STOLEN SHAMELESSLY FROM THE TERRAFORM REPO BECAUSE VENDORING OUT
// WRAPPEDREADLINE AND WRAPPEDSTREAMS FELT LIKE TOO MUCH WORK.
//
// "a little copying is better than a lot of dependency"
//
// wrappedreadline is a package that has helpers for interacting with
// readline from a panicwrap executable.
//
// panicwrap overrides the standard file descriptors so that the child process
// no longer looks like a TTY. The helpers here access the extra file descriptors
// passed by panicwrap to fix that.
//
// panicwrap should be checked for with panicwrap.Wrapped before using this
// librar, since this library won't adapt if the binary is not wrapped.
package wrappedreadline
import (
"runtime"
"github.com/chzyer/readline"
"github.com/hashicorp/packer/helper/wrappedstreams"
)
// Override overrides the values in readline.Config that need to be
// set with wrapped values.
func Override(cfg *readline.Config) *readline.Config {
cfg.Stdin = wrappedstreams.Stdin()
cfg.Stdout = wrappedstreams.Stdout()
cfg.Stderr = wrappedstreams.Stderr()
cfg.FuncGetWidth = TerminalWidth
cfg.FuncIsTerminal = IsTerminal
rm := RawMode{StdinFd: int(wrappedstreams.Stdin().Fd())}
cfg.FuncMakeRaw = rm.Enter
cfg.FuncExitRaw = rm.Exit
return cfg
}
// IsTerminal determines if this process is attached to a TTY.
func IsTerminal() bool {
// Windows is always a terminal
if runtime.GOOS == "windows" {
return true
}
// Same implementation as readline but with our custom fds
return readline.IsTerminal(int(wrappedstreams.Stdin().Fd())) &&
(readline.IsTerminal(int(wrappedstreams.Stdout().Fd())) ||
readline.IsTerminal(int(wrappedstreams.Stderr().Fd())))
}
// TerminalWidth gets the terminal width in characters.
func TerminalWidth() int {
if runtime.GOOS == "windows" {
return readline.GetScreenWidth()
}
return getWidth()
}
// RawMode is a helper for entering and exiting raw mode.
type RawMode struct {
StdinFd int
state *readline.State
}
func (r *RawMode) Enter() (err error) {
r.state, err = readline.MakeRaw(r.StdinFd)
return err
}
func (r *RawMode) Exit() error {
if r.state == nil {
return nil
}
return readline.Restore(r.StdinFd, r.state)
}