package tty import ( "os" "strings" "unicode" ) var linefeed = []byte{'\n'} func Open() (*TTY, error) { return open("/dev/tty") } func OpenDevice(path string) (*TTY, error) { return open(path) } func (tty *TTY) Raw() (func() error, error) { return tty.raw() } func (tty *TTY) MustRaw() func() error { f, err := tty.raw() if err != nil { panic(err.Error()) } return f } func (tty *TTY) Buffered() bool { return tty.buffered() } func (tty *TTY) ReadRune() (rune, error) { return tty.readRune() } func (tty *TTY) Close() error { return tty.close() } func (tty *TTY) Size() (int, int, error) { return tty.size() } func (tty *TTY) SizePixel() (int, int, int, int, error) { return tty.sizePixel() } func (tty *TTY) Input() *os.File { return tty.input() } func (tty *TTY) Output() *os.File { return tty.output() } // Display types. const ( displayNone = iota displayRune displayMask ) func (tty *TTY) readString(displayType int) (string, error) { rs := []rune{} loop: for { r, err := tty.readRune() if err != nil { return "", err } switch r { case 13: break loop case 8, 127: if len(rs) > 0 { rs = rs[:len(rs)-1] if displayType != displayNone { tty.Output().Write([]byte("\b \b")) } } default: if unicode.IsPrint(r) { rs = append(rs, r) switch displayType { case displayRune: tty.Output().Write([]byte(string(r))) case displayMask: tty.Output().Write([]byte{'*'}) } } } } return string(rs), nil } func (tty *TTY) ReadString() (string, error) { defer tty.Output().Write(linefeed) return tty.readString(displayRune) } func (tty *TTY) ReadPassword() (string, error) { defer tty.Output().Write(linefeed) return tty.readString(displayMask) } func (tty *TTY) ReadPasswordNoEcho() (string, error) { defer tty.Output().Write(linefeed) return tty.readString(displayNone) } func (tty *TTY) ReadPasswordClear() (string, error) { s, err := tty.readString(displayMask) tty.Output().Write([]byte( strings.Repeat("\b", len(s)) + strings.Repeat(" ", len(s)) + strings.Repeat("\b", len(s)))) return s, err } type WINSIZE struct { W int H int } func (tty *TTY) SIGWINCH() <-chan WINSIZE { return tty.sigwinch() }