| 19 | 19 |
procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute")
|
| 20 | 20 |
)
|
| 21 | 21 |
|
| 22 | |
type short int16
|
| 23 | |
type dword uint32
|
| 24 | |
type word uint16
|
|
22 |
type (
|
|
23 |
short int16
|
|
24 |
word uint16
|
|
25 |
dword uint32
|
| 25 | 26 |
|
| 26 | |
type coord struct {
|
| 27 | |
x short
|
| 28 | |
y short
|
| 29 | |
}
|
| 30 | |
|
| 31 | |
type smallRect struct {
|
| 32 | |
left short
|
| 33 | |
top short
|
| 34 | |
right short
|
| 35 | |
bottom short
|
| 36 | |
}
|
| 37 | |
|
| 38 | |
type consoleScreenBufferInfo struct {
|
| 39 | |
size coord
|
| 40 | |
cursorPosition coord
|
| 41 | |
attributes word
|
| 42 | |
window smallRect
|
| 43 | |
maximumWindowSize coord
|
| 44 | |
}
|
|
27 |
coord struct {
|
|
28 |
x short
|
|
29 |
y short
|
|
30 |
}
|
|
31 |
smallRect struct {
|
|
32 |
left short
|
|
33 |
top short
|
|
34 |
right short
|
|
35 |
bottom short
|
|
36 |
}
|
|
37 |
consoleScreenBufferInfo struct {
|
|
38 |
size coord
|
|
39 |
cursorPosition coord
|
|
40 |
attributes word
|
|
41 |
window smallRect
|
|
42 |
maximumWindowSize coord
|
|
43 |
}
|
|
44 |
)
|
| 45 | 45 |
|
| 46 | 46 |
// FdWriter is a writer with a file descriptor.
|
| 47 | 47 |
type FdWriter interface {
|
|
| 53 | 53 |
f, ok := w.out.(FdWriter)
|
| 54 | 54 |
if ok && !isatty.IsTerminal(f.Fd()) {
|
| 55 | 55 |
for i := 0; i < w.lineCount; i++ {
|
| 56 | |
fmt.Fprintf(w.out, "%c[%dA", ESC, 0) // move the cursor up
|
|
56 |
fmt.Fprintf(w.out, "%c[%dA", ESC, 1) // move the cursor up
|
| 57 | 57 |
fmt.Fprintf(w.out, "%c[2K\r", ESC) // clear the line
|
| 58 | 58 |
}
|
| 59 | 59 |
return
|
| 60 | 60 |
}
|
| 61 | 61 |
fd := f.Fd()
|
| 62 | |
var csbi consoleScreenBufferInfo
|
| 63 | |
procGetConsoleScreenBufferInfo.Call(fd, uintptr(unsafe.Pointer(&csbi)))
|
|
62 |
var info consoleScreenBufferInfo
|
|
63 |
procGetConsoleScreenBufferInfo.Call(fd, uintptr(unsafe.Pointer(&info)))
|
| 64 | 64 |
|
| 65 | 65 |
for i := 0; i < w.lineCount; i++ {
|
| 66 | 66 |
// move the cursor up
|
| 67 | |
csbi.cursorPosition.y--
|
| 68 | |
procSetConsoleCursorPosition.Call(fd, uintptr(*(*int32)(unsafe.Pointer(&csbi.cursorPosition))))
|
|
67 |
info.cursorPosition.y--
|
|
68 |
procSetConsoleCursorPosition.Call(fd, uintptr(*(*int32)(unsafe.Pointer(&info.cursorPosition))))
|
| 69 | 69 |
// clear the line
|
| 70 | 70 |
cursor := coord{
|
| 71 | |
x: csbi.window.left,
|
| 72 | |
y: csbi.window.top + csbi.cursorPosition.y,
|
|
71 |
x: info.window.left,
|
|
72 |
y: info.window.top + info.cursorPosition.y,
|
| 73 | 73 |
}
|
| 74 | 74 |
var count, w dword
|
| 75 | |
count = dword(csbi.size.x)
|
|
75 |
count = dword(info.size.x)
|
| 76 | 76 |
procFillConsoleOutputCharacter.Call(fd, uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&w)))
|
| 77 | 77 |
}
|
| 78 | 78 |
}
|
| 79 | 79 |
|
| 80 | |
// TerminalWidth returns width of the terminal.
|
| 81 | |
func TerminalWidth() (int, error) {
|
|
80 |
// GetTermSize returns the dimensions of the given terminal.
|
|
81 |
// the code is stolen from "golang.org/x/crypto/ssh/terminal"
|
|
82 |
func GetTermSize() (width, height int, err error) {
|
| 82 | 83 |
var info consoleScreenBufferInfo
|
| 83 | |
_, _, errno := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(syscall.Stdout), uintptr(unsafe.Pointer(&info)), 0)
|
| 84 | |
if errno != 0 {
|
| 85 | |
return 0, errno
|
|
84 |
_, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(syscall.Stdout), uintptr(unsafe.Pointer(&info)), 0)
|
|
85 |
if e != 0 {
|
|
86 |
return 0, 0, error(e)
|
| 86 | 87 |
}
|
| 87 | |
return int(info.size.x) - 1, nil
|
|
88 |
return int(info.size.x), int(info.size.y), nil
|
| 88 | 89 |
}
|