From 93ccc548c8f8d79c94f797938415b6b47f85409a Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Sun, 7 Sep 2025 13:49:26 +0200 Subject: [PATCH] termstatus: move cursor handling to terminal package --- cmd/restic/global.go | 4 ++-- .../termstatus => terminal}/terminal_posix.go | 18 +++++++++--------- .../termstatus => terminal}/terminal_unix.go | 10 +++++----- .../terminal_windows.go | 10 +++++----- .../terminal_windows_test.go | 2 +- internal/ui/termstatus/status.go | 6 +++--- internal/ui/termstatus/status_test.go | 11 ++++++----- 7 files changed, 31 insertions(+), 30 deletions(-) rename internal/{ui/termstatus => terminal}/terminal_posix.go (54%) rename internal/{ui/termstatus => terminal}/terminal_unix.go (77%) rename internal/{ui/termstatus => terminal}/terminal_windows.go (94%) rename internal/{ui/termstatus => terminal}/terminal_windows_test.go (97%) diff --git a/cmd/restic/global.go b/cmd/restic/global.go index 6e58a0d73..56a3f5f18 100644 --- a/cmd/restic/global.go +++ b/cmd/restic/global.go @@ -33,8 +33,8 @@ import ( "github.com/restic/restic/internal/options" "github.com/restic/restic/internal/repository" "github.com/restic/restic/internal/restic" + "github.com/restic/restic/internal/terminal" "github.com/restic/restic/internal/textfile" - "github.com/restic/restic/internal/ui/termstatus" "github.com/spf13/pflag" "github.com/restic/restic/internal/errors" @@ -210,7 +210,7 @@ func stdoutIsTerminal() bool { } func stdoutCanUpdateStatus() bool { - return termstatus.CanUpdateStatus(os.Stdout.Fd()) + return terminal.CanUpdateStatus(os.Stdout.Fd()) } func stdoutTerminalWidth() int { diff --git a/internal/ui/termstatus/terminal_posix.go b/internal/terminal/terminal_posix.go similarity index 54% rename from internal/ui/termstatus/terminal_posix.go rename to internal/terminal/terminal_posix.go index ca5468f45..cd9820f10 100644 --- a/internal/ui/termstatus/terminal_posix.go +++ b/internal/terminal/terminal_posix.go @@ -1,4 +1,4 @@ -package termstatus +package terminal import ( "bytes" @@ -8,16 +8,16 @@ import ( ) const ( - posixControlMoveCursorHome = "\r" - posixControlMoveCursorUp = "\x1b[1A" - posixControlClearLine = "\x1b[2K" + PosixControlMoveCursorHome = "\r" + PosixControlMoveCursorUp = "\x1b[1A" + PosixControlClearLine = "\x1b[2K" ) // posixClearCurrentLine removes all characters from the current line and resets the // cursor position to the first column. -func posixClearCurrentLine(wr io.Writer, _ uintptr) { +func PosixClearCurrentLine(wr io.Writer, _ uintptr) { // clear current line - _, err := wr.Write([]byte(posixControlMoveCursorHome + posixControlClearLine)) + _, err := wr.Write([]byte(PosixControlMoveCursorHome + PosixControlClearLine)) if err != nil { fmt.Fprintf(os.Stderr, "write failed: %v\n", err) return @@ -25,9 +25,9 @@ func posixClearCurrentLine(wr io.Writer, _ uintptr) { } // posixMoveCursorUp moves the cursor to the line n lines above the current one. -func posixMoveCursorUp(wr io.Writer, _ uintptr, n int) { - data := []byte(posixControlMoveCursorHome) - data = append(data, bytes.Repeat([]byte(posixControlMoveCursorUp), n)...) +func PosixMoveCursorUp(wr io.Writer, _ uintptr, n int) { + data := []byte(PosixControlMoveCursorHome) + data = append(data, bytes.Repeat([]byte(PosixControlMoveCursorUp), n)...) _, err := wr.Write(data) if err != nil { fmt.Fprintf(os.Stderr, "write failed: %v\n", err) diff --git a/internal/ui/termstatus/terminal_unix.go b/internal/terminal/terminal_unix.go similarity index 77% rename from internal/ui/termstatus/terminal_unix.go rename to internal/terminal/terminal_unix.go index e112be233..8893d21e9 100644 --- a/internal/ui/termstatus/terminal_unix.go +++ b/internal/terminal/terminal_unix.go @@ -1,7 +1,7 @@ //go:build !windows // +build !windows -package termstatus +package terminal import ( "io" @@ -12,13 +12,13 @@ import ( // clearCurrentLine removes all characters from the current line and resets the // cursor position to the first column. -func clearCurrentLine(_ uintptr) func(io.Writer, uintptr) { - return posixClearCurrentLine +func ClearCurrentLine(_ uintptr) func(io.Writer, uintptr) { + return PosixClearCurrentLine } // moveCursorUp moves the cursor to the line n lines above the current one. -func moveCursorUp(_ uintptr) func(io.Writer, uintptr, int) { - return posixMoveCursorUp +func MoveCursorUp(_ uintptr) func(io.Writer, uintptr, int) { + return PosixMoveCursorUp } // CanUpdateStatus returns true if status lines can be printed, the process diff --git a/internal/ui/termstatus/terminal_windows.go b/internal/terminal/terminal_windows.go similarity index 94% rename from internal/ui/termstatus/terminal_windows.go rename to internal/terminal/terminal_windows.go index 3603f16a3..d68d0197e 100644 --- a/internal/ui/termstatus/terminal_windows.go +++ b/internal/terminal/terminal_windows.go @@ -1,7 +1,7 @@ //go:build windows // +build windows -package termstatus +package terminal import ( "io" @@ -15,25 +15,25 @@ import ( // clearCurrentLine removes all characters from the current line and resets the // cursor position to the first column. -func clearCurrentLine(fd uintptr) func(io.Writer, uintptr) { +func ClearCurrentLine(fd uintptr) func(io.Writer, uintptr) { // easy case, the terminal is cmd or psh, without redirection if isWindowsTerminal(fd) { return windowsClearCurrentLine } // assume we're running in mintty/cygwin - return posixClearCurrentLine + return PosixClearCurrentLine } // moveCursorUp moves the cursor to the line n lines above the current one. -func moveCursorUp(fd uintptr) func(io.Writer, uintptr, int) { +func MoveCursorUp(fd uintptr) func(io.Writer, uintptr, int) { // easy case, the terminal is cmd or psh, without redirection if isWindowsTerminal(fd) { return windowsMoveCursorUp } // assume we're running in mintty/cygwin - return posixMoveCursorUp + return PosixMoveCursorUp } var kernel32 = syscall.NewLazyDLL("kernel32.dll") diff --git a/internal/ui/termstatus/terminal_windows_test.go b/internal/terminal/terminal_windows_test.go similarity index 97% rename from internal/ui/termstatus/terminal_windows_test.go rename to internal/terminal/terminal_windows_test.go index e6eb39dd5..a6b853bae 100644 --- a/internal/ui/termstatus/terminal_windows_test.go +++ b/internal/terminal/terminal_windows_test.go @@ -1,4 +1,4 @@ -package termstatus +package terminal import ( "syscall" diff --git a/internal/ui/termstatus/status.go b/internal/ui/termstatus/status.go index 1e105b65f..e4d9f19bf 100644 --- a/internal/ui/termstatus/status.go +++ b/internal/ui/termstatus/status.go @@ -69,12 +69,12 @@ func New(wr io.Writer, errWriter io.Writer, disableStatus bool) *Terminal { return t } - if d, ok := wr.(fder); ok && CanUpdateStatus(d.Fd()) { + if d, ok := wr.(fder); ok && terminal.CanUpdateStatus(d.Fd()) { // only use the fancy status code when we're running on a real terminal. t.canUpdateStatus = true t.fd = d.Fd() - t.clearCurrentLine = clearCurrentLine(t.fd) - t.moveCursorUp = moveCursorUp(t.fd) + t.clearCurrentLine = terminal.ClearCurrentLine(t.fd) + t.moveCursorUp = terminal.MoveCursorUp(t.fd) } return t diff --git a/internal/ui/termstatus/status_test.go b/internal/ui/termstatus/status_test.go index b4e9be5b0..8e5414686 100644 --- a/internal/ui/termstatus/status_test.go +++ b/internal/ui/termstatus/status_test.go @@ -8,6 +8,7 @@ import ( "strconv" "testing" + "github.com/restic/restic/internal/terminal" rtest "github.com/restic/restic/internal/test" ) @@ -17,16 +18,16 @@ func TestSetStatus(t *testing.T) { term.canUpdateStatus = true term.fd = ^uintptr(0) - term.clearCurrentLine = posixClearCurrentLine - term.moveCursorUp = posixMoveCursorUp + term.clearCurrentLine = terminal.PosixClearCurrentLine + term.moveCursorUp = terminal.PosixMoveCursorUp ctx, cancel := context.WithCancel(context.Background()) go term.Run(ctx) const ( - cl = posixControlClearLine - home = posixControlMoveCursorHome - up = posixControlMoveCursorUp + cl = terminal.PosixControlClearLine + home = terminal.PosixControlMoveCursorHome + up = terminal.PosixControlMoveCursorUp ) term.SetStatus([]string{"first"})