diff --git a/pkg/terminal/out.go b/pkg/terminal/out.go index 7b0cab83..79dd73f9 100644 --- a/pkg/terminal/out.go +++ b/pkg/terminal/out.go @@ -100,6 +100,8 @@ type pagingWriter struct { pager string lastnl bool cancel func() + + lines, columns int } type pagingWriterMode uint8 @@ -108,9 +110,6 @@ const ( pagingWriterNormal pagingWriterMode = iota pagingWriterMaybe pagingWriterPaging - - pagingWriterMaxLines = 30 - pagingWriterColsPerLine = 100 ) func (w *pagingWriter) Write(p []byte) (nn int, err error) { @@ -141,7 +140,7 @@ func (w *pagingWriter) Write(p []byte) (nn int, err error) { w.cmdStdin.Write(w.buf) w.buf = nil w.mode = pagingWriterPaging - return w.cmdStdin.Write(p) + return len(p), nil } else { if len(p) > 0 { w.lastnl = p[len(p)-1] == '\n' @@ -202,17 +201,17 @@ func (w *pagingWriter) PageMaybe(cancel func()) { } w.lastnl = true w.cancel = cancel + w.getWindowSize() } func (w *pagingWriter) largeOutput() bool { - if len(w.buf) > pagingWriterMaxLines*pagingWriterColsPerLine { - return true - } - nl := 0 + lines := 0 + lineStart := 0 for i := range w.buf { - if w.buf[i] == '\n' { - nl++ - if nl > pagingWriterMaxLines { + if i-lineStart > w.columns || w.buf[i] == '\n' { + lineStart = i + lines++ + if lines > w.lines { return true } } diff --git a/pkg/terminal/out_unix.go b/pkg/terminal/out_unix.go new file mode 100644 index 00000000..7b55f632 --- /dev/null +++ b/pkg/terminal/out_unix.go @@ -0,0 +1,25 @@ +//go:build linux || darwin || freebsd +// +build linux darwin freebsd + +package terminal + +import ( + "syscall" + "unsafe" +) + +type winSize struct { + row, col uint16 + xpixel, ypixel uint16 +} + +func (w *pagingWriter) getWindowSize() { + var ws winSize + ok, _, _ := syscall.Syscall(syscall.SYS_IOCTL, uintptr(syscall.Stdout), syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&ws))) + if int(ok) < 0 { + w.mode = pagingWriterNormal + return + } + w.lines = int(ws.row) + w.columns = int(ws.col) +} diff --git a/pkg/terminal/out_windows.go b/pkg/terminal/out_windows.go new file mode 100644 index 00000000..f8c6077f --- /dev/null +++ b/pkg/terminal/out_windows.go @@ -0,0 +1,44 @@ +package terminal + +import ( + "syscall" + "unsafe" +) + +var ( + kernel32 = syscall.NewLazyDLL("kernel32.dll") + procGetStdHandle = kernel32.NewProc("GetStdHandle") + procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") +) + +type coord struct { + x, y int16 +} + +type smallRect struct { + left, top, right, bottom int16 +} + +type consoleScreenBufferInfo struct { + dwSize coord + dwCursorPosition coord + wAttributes int16 + srWindow smallRect + dwMaximumWindowSize coord +} + +func (w *pagingWriter) getWindowSize() { + hout, _, err := procGetStdHandle.Call(uintptr(uint32(-12 & 0xFFFFFFFF))) // stdout handle + if err != syscall.Errno(0) { + w.mode = pagingWriterNormal + return + } + var sbi consoleScreenBufferInfo + _, _, err = procGetConsoleScreenBufferInfo.Call(uintptr(hout), uintptr(unsafe.Pointer(&sbi))) + if err != syscall.Errno(0) { + w.mode = pagingWriterNormal + return + } + w.columns = int(sbi.srWindow.right - sbi.srWindow.left + 1) + w.lines = int(sbi.srWindow.bottom - sbi.srWindow.top + 1) +}