add func IsTerminal
Vladimir Bauer
5 years ago
| 0 | // +build darwin dragonfly freebsd netbsd openbsd | |
| 1 | ||
| 2 | package cwriter | |
| 3 | ||
| 4 | import "golang.org/x/sys/unix" | |
| 5 | ||
| 6 | const ioctlReadTermios = unix.TIOCGETA |
| 0 | // +build aix linux | |
| 1 | ||
| 2 | package cwriter | |
| 3 | ||
| 4 | import "golang.org/x/sys/unix" | |
| 5 | ||
| 6 | const ioctlReadTermios = unix.TCGETS |
| 0 | // +build solaris | |
| 1 | ||
| 2 | package cwriter | |
| 3 | ||
| 4 | import "golang.org/x/sys/unix" | |
| 5 | ||
| 6 | const ioctlReadTermios = unix.TCGETA |
| 5 | 5 | "io" |
| 6 | 6 | "os" |
| 7 | 7 | "strconv" |
| 8 | ||
| 9 | "github.com/mattn/go-isatty" | |
| 10 | 8 | ) |
| 11 | 9 | |
| 12 | 10 | // NotATTY not a TeleTYpewriter error. |
| 24 | 22 | out io.Writer |
| 25 | 23 | buf bytes.Buffer |
| 26 | 24 | lineCount int |
| 27 | fd uintptr | |
| 25 | fd int | |
| 28 | 26 | isTerminal bool |
| 29 | 27 | } |
| 30 | 28 | |
| 32 | 30 | func New(out io.Writer) *Writer { |
| 33 | 31 | w := &Writer{out: out} |
| 34 | 32 | if f, ok := out.(*os.File); ok { |
| 35 | w.fd = f.Fd() | |
| 36 | w.isTerminal = isatty.IsTerminal(w.fd) | |
| 33 | w.fd = int(f.Fd()) | |
| 34 | w.isTerminal = IsTerminal(w.fd) | |
| 37 | 35 | } |
| 38 | 36 | return w |
| 39 | 37 | } |
| 10 | 10 | } |
| 11 | 11 | |
| 12 | 12 | // GetSize returns the dimensions of the given terminal. |
| 13 | func GetSize(fd uintptr) (width, height int, err error) { | |
| 14 | ws, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ) | |
| 13 | func GetSize(fd int) (width, height int, err error) { | |
| 14 | ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ) | |
| 15 | 15 | if err != nil { |
| 16 | 16 | return -1, -1, err |
| 17 | 17 | } |
| 18 | 18 | return int(ws.Col), int(ws.Row), nil |
| 19 | 19 | } |
| 20 | ||
| 21 | // IsTerminal returns whether the given file descriptor is a terminal. | |
| 22 | func IsTerminal(fd int) bool { | |
| 23 | _, err := unix.IoctlGetTermios(fd, ioctlReadTermios) | |
| 24 | return err == nil | |
| 25 | } |
| 4 | 4 | import ( |
| 5 | 5 | "unsafe" |
| 6 | 6 | |
| 7 | "github.com/mattn/go-isatty" | |
| 8 | 7 | "golang.org/x/sys/windows" |
| 9 | 8 | ) |
| 10 | 9 | |
| 16 | 15 | ) |
| 17 | 16 | |
| 18 | 17 | func (w *Writer) clearLines() error { |
| 19 | if !w.isTerminal && isatty.IsCygwinTerminal(w.fd) { | |
| 18 | if !w.isTerminal { | |
| 19 | // hope it's cygwin or similar | |
| 20 | 20 | return w.ansiCuuAndEd() |
| 21 | 21 | } |
| 22 | 22 | |
| 30 | 30 | info.CursorPosition.Y = 0 |
| 31 | 31 | } |
| 32 | 32 | _, _, _ = procSetConsoleCursorPosition.Call( |
| 33 | w.fd, | |
| 33 | uintptr(w.fd), | |
| 34 | 34 | uintptr(uint32(uint16(info.CursorPosition.Y))<<16|uint32(uint16(info.CursorPosition.X))), |
| 35 | 35 | ) |
| 36 | 36 | |
| 41 | 41 | } |
| 42 | 42 | count := uint32(info.Size.X) * uint32(w.lineCount) |
| 43 | 43 | _, _, _ = procFillConsoleOutputCharacter.Call( |
| 44 | w.fd, | |
| 44 | uintptr(w.fd), | |
| 45 | 45 | uintptr(' '), |
| 46 | 46 | uintptr(count), |
| 47 | 47 | *(*uintptr)(unsafe.Pointer(cursor)), |
| 53 | 53 | // GetSize returns the visible dimensions of the given terminal. |
| 54 | 54 | // |
| 55 | 55 | // These dimensions don't include any scrollback buffer height. |
| 56 | func GetSize(fd uintptr) (width, height int, err error) { | |
| 56 | func GetSize(fd int) (width, height int, err error) { | |
| 57 | 57 | var info windows.ConsoleScreenBufferInfo |
| 58 | 58 | if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil { |
| 59 | 59 | return 0, 0, err |
| 63 | 63 | // but looks like this is a root cause of issue #66, so removing both "+ 1" have fixed it. |
| 64 | 64 | return int(info.Window.Right - info.Window.Left), int(info.Window.Bottom - info.Window.Top), nil |
| 65 | 65 | } |
| 66 | ||
| 67 | // IsTerminal returns whether the given file descriptor is a terminal. | |
| 68 | func IsTerminal(fd int) bool { | |
| 69 | var st uint32 | |
| 70 | err := windows.GetConsoleMode(windows.Handle(fd), &st) | |
| 71 | return err == nil | |
| 72 | } | |