mirror of
https://github.com/restic/restic.git
synced 2025-10-11 03:12:38 +00:00
Merge pull request #2608 from greatroar/simplify-termstatus
Simplify termstatus
This commit is contained in:
@@ -8,6 +8,8 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
// Terminal is used to write messages and display status lines which can be
|
||||
@@ -310,7 +312,7 @@ func (t *Terminal) SetStatus(lines []string) {
|
||||
return
|
||||
}
|
||||
|
||||
width, _, err := getTermSize(t.fd)
|
||||
width, _, err := terminal.GetSize(int(t.fd))
|
||||
if err != nil || width <= 0 {
|
||||
// use 80 columns by default
|
||||
width = 80
|
||||
|
@@ -6,9 +6,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
isatty "github.com/mattn/go-isatty"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
// clearCurrentLine removes all characters from the current line and resets the
|
||||
@@ -25,7 +23,7 @@ func moveCursorUp(wr io.Writer, fd uintptr) func(io.Writer, uintptr, int) {
|
||||
// canUpdateStatus returns true if status lines can be printed, the process
|
||||
// output is not redirected to a file or pipe.
|
||||
func canUpdateStatus(fd uintptr) bool {
|
||||
if !isatty.IsTerminal(fd) {
|
||||
if !terminal.IsTerminal(int(fd)) {
|
||||
return false
|
||||
}
|
||||
term := os.Getenv("TERM")
|
||||
@@ -35,13 +33,3 @@ func canUpdateStatus(fd uintptr) bool {
|
||||
// TODO actually read termcap db and detect if terminal supports what we need
|
||||
return term != "dumb"
|
||||
}
|
||||
|
||||
// getTermSize returns the dimensions of the given terminal.
|
||||
// the code is taken from "golang.org/x/crypto/ssh/terminal"
|
||||
func getTermSize(fd uintptr) (width, height int, err error) {
|
||||
ws, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ)
|
||||
if err != nil {
|
||||
return -1, -1, err
|
||||
}
|
||||
return int(ws.Col), int(ws.Row), nil
|
||||
}
|
||||
|
@@ -6,6 +6,9 @@ import (
|
||||
"io"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// clearCurrentLine removes all characters from the current line and resets the
|
||||
@@ -16,12 +19,6 @@ func clearCurrentLine(wr io.Writer, fd uintptr) func(io.Writer, uintptr) {
|
||||
return windowsClearCurrentLine
|
||||
}
|
||||
|
||||
// check if the output file type is a pipe (0x0003)
|
||||
if getFileType(fd) != fileTypePipe {
|
||||
// return empty func, update state is not possible on this terminal
|
||||
return func(io.Writer, uintptr) {}
|
||||
}
|
||||
|
||||
// assume we're running in mintty/cygwin
|
||||
return posixClearCurrentLine
|
||||
}
|
||||
@@ -33,12 +30,6 @@ func moveCursorUp(wr io.Writer, fd uintptr) func(io.Writer, uintptr, int) {
|
||||
return windowsMoveCursorUp
|
||||
}
|
||||
|
||||
// check if the output file type is a pipe (0x0003)
|
||||
if getFileType(fd) != fileTypePipe {
|
||||
// return empty func, update state is not possible on this terminal
|
||||
return func(io.Writer, uintptr, int) {}
|
||||
}
|
||||
|
||||
// assume we're running in mintty/cygwin
|
||||
return posixMoveCursorUp
|
||||
}
|
||||
@@ -46,94 +37,47 @@ func moveCursorUp(wr io.Writer, fd uintptr) func(io.Writer, uintptr, int) {
|
||||
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
|
||||
var (
|
||||
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
|
||||
procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
|
||||
procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
|
||||
procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute")
|
||||
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
||||
procGetFileType = kernel32.NewProc("GetFileType")
|
||||
)
|
||||
|
||||
type (
|
||||
short int16
|
||||
word uint16
|
||||
dword uint32
|
||||
|
||||
coord struct {
|
||||
x short
|
||||
y short
|
||||
}
|
||||
smallRect struct {
|
||||
left short
|
||||
top short
|
||||
right short
|
||||
bottom short
|
||||
}
|
||||
consoleScreenBufferInfo struct {
|
||||
size coord
|
||||
cursorPosition coord
|
||||
attributes word
|
||||
window smallRect
|
||||
maximumWindowSize coord
|
||||
}
|
||||
)
|
||||
|
||||
// windowsClearCurrentLine removes all characters from the current line and
|
||||
// resets the cursor position to the first column.
|
||||
func windowsClearCurrentLine(wr io.Writer, fd uintptr) {
|
||||
var info consoleScreenBufferInfo
|
||||
procGetConsoleScreenBufferInfo.Call(fd, uintptr(unsafe.Pointer(&info)))
|
||||
var info windows.ConsoleScreenBufferInfo
|
||||
windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info)
|
||||
|
||||
// clear the line
|
||||
cursor := coord{
|
||||
x: info.window.left,
|
||||
y: info.cursorPosition.y,
|
||||
cursor := windows.Coord{
|
||||
X: info.Window.Left,
|
||||
Y: info.CursorPosition.Y,
|
||||
}
|
||||
var count, w dword
|
||||
count = dword(info.size.x)
|
||||
procFillConsoleOutputAttribute.Call(fd, uintptr(info.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&w)))
|
||||
var count, w uint32
|
||||
count = uint32(info.Size.X)
|
||||
procFillConsoleOutputAttribute.Call(fd, uintptr(info.Attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&w)))
|
||||
procFillConsoleOutputCharacter.Call(fd, uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&w)))
|
||||
}
|
||||
|
||||
// windowsMoveCursorUp moves the cursor to the line n lines above the current one.
|
||||
func windowsMoveCursorUp(wr io.Writer, fd uintptr, n int) {
|
||||
var info consoleScreenBufferInfo
|
||||
procGetConsoleScreenBufferInfo.Call(fd, uintptr(unsafe.Pointer(&info)))
|
||||
var info windows.ConsoleScreenBufferInfo
|
||||
windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info)
|
||||
|
||||
// move cursor up by n lines and to the first column
|
||||
info.cursorPosition.y -= short(n)
|
||||
info.cursorPosition.x = 0
|
||||
procSetConsoleCursorPosition.Call(fd, uintptr(*(*int32)(unsafe.Pointer(&info.cursorPosition))))
|
||||
}
|
||||
|
||||
// getTermSize returns the dimensions of the given terminal.
|
||||
// the code is taken from "golang.org/x/crypto/ssh/terminal"
|
||||
func getTermSize(fd uintptr) (width, height int, err error) {
|
||||
var info consoleScreenBufferInfo
|
||||
_, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, fd, uintptr(unsafe.Pointer(&info)), 0)
|
||||
if e != 0 {
|
||||
return 0, 0, error(e)
|
||||
}
|
||||
return int(info.size.x), int(info.size.y), nil
|
||||
info.CursorPosition.Y -= int16(n)
|
||||
info.CursorPosition.X = 0
|
||||
procSetConsoleCursorPosition.Call(fd, uintptr(*(*int32)(unsafe.Pointer(&info.CursorPosition))))
|
||||
}
|
||||
|
||||
// isWindowsTerminal return true if the file descriptor is a windows terminal (cmd, psh).
|
||||
func isWindowsTerminal(fd uintptr) bool {
|
||||
var st uint32
|
||||
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
|
||||
return r != 0 && e == 0
|
||||
return terminal.IsTerminal(int(fd))
|
||||
}
|
||||
|
||||
const fileTypePipe = 0x0003
|
||||
|
||||
// getFileType returns the file type for the given fd.
|
||||
// https://msdn.microsoft.com/de-de/library/windows/desktop/aa364960(v=vs.85).aspx
|
||||
func getFileType(fd uintptr) int {
|
||||
r, _, e := syscall.Syscall(procGetFileType.Addr(), 1, fd, 0, 0)
|
||||
if e != 0 {
|
||||
return 0
|
||||
}
|
||||
return int(r)
|
||||
func isPipe(fd uintptr) bool {
|
||||
typ, err := windows.GetFileType(windows.Handle(fd))
|
||||
return err == nil && typ == windows.FILE_TYPE_PIPE
|
||||
}
|
||||
|
||||
// canUpdateStatus returns true if status lines can be printed, the process
|
||||
@@ -145,7 +89,7 @@ func canUpdateStatus(fd uintptr) bool {
|
||||
}
|
||||
|
||||
// check if the output file type is a pipe (0x0003)
|
||||
if getFileType(fd) != fileTypePipe {
|
||||
if isPipe(fd) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user