github.com/noxiouz/docker@v0.7.3-0.20160629055221-3d231c78e8c5/pkg/term/term.go (about) 1 // +build !windows 2 3 // Package term provides provides structures and helper functions to work with 4 // terminal (state, sizes). 5 package term 6 7 import ( 8 "errors" 9 "io" 10 "os" 11 "os/signal" 12 "syscall" 13 ) 14 15 var ( 16 // ErrInvalidState is returned if the state of the terminal is invalid. 17 ErrInvalidState = errors.New("Invalid terminal state") 18 ) 19 20 // State represents the state of the terminal. 21 type State struct { 22 termios Termios 23 } 24 25 // Winsize represents the size of the terminal window. 26 type Winsize struct { 27 Height uint16 28 Width uint16 29 x uint16 30 y uint16 31 } 32 33 // StdStreams returns the standard streams (stdin, stdout, stedrr). 34 func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) { 35 return os.Stdin, os.Stdout, os.Stderr 36 } 37 38 // GetFdInfo returns the file descriptor for an os.File and indicates whether the file represents a terminal. 39 func GetFdInfo(in interface{}) (uintptr, bool) { 40 var inFd uintptr 41 var isTerminalIn bool 42 if file, ok := in.(*os.File); ok { 43 inFd = file.Fd() 44 isTerminalIn = IsTerminal(inFd) 45 } 46 return inFd, isTerminalIn 47 } 48 49 // IsTerminal returns true if the given file descriptor is a terminal. 50 func IsTerminal(fd uintptr) bool { 51 var termios Termios 52 return tcget(fd, &termios) == 0 53 } 54 55 // RestoreTerminal restores the terminal connected to the given file descriptor 56 // to a previous state. 57 func RestoreTerminal(fd uintptr, state *State) error { 58 if state == nil { 59 return ErrInvalidState 60 } 61 if err := tcset(fd, &state.termios); err != 0 { 62 return err 63 } 64 return nil 65 } 66 67 // SaveState saves the state of the terminal connected to the given file descriptor. 68 func SaveState(fd uintptr) (*State, error) { 69 var oldState State 70 if err := tcget(fd, &oldState.termios); err != 0 { 71 return nil, err 72 } 73 74 return &oldState, nil 75 } 76 77 // DisableEcho applies the specified state to the terminal connected to the file 78 // descriptor, with echo disabled. 79 func DisableEcho(fd uintptr, state *State) error { 80 newState := state.termios 81 newState.Lflag &^= syscall.ECHO 82 83 if err := tcset(fd, &newState); err != 0 { 84 return err 85 } 86 handleInterrupt(fd, state) 87 return nil 88 } 89 90 // SetRawTerminal puts the terminal connected to the given file descriptor into 91 // raw mode and returns the previous state. 92 func SetRawTerminal(fd uintptr) (*State, error) { 93 oldState, err := MakeRaw(fd) 94 if err != nil { 95 return nil, err 96 } 97 handleInterrupt(fd, oldState) 98 return oldState, err 99 } 100 101 func handleInterrupt(fd uintptr, state *State) { 102 sigchan := make(chan os.Signal, 1) 103 signal.Notify(sigchan, os.Interrupt) 104 105 go func() { 106 _ = <-sigchan 107 RestoreTerminal(fd, state) 108 }() 109 }