Skip to content

Commit

Permalink
Merge pull request #8 from Brookke/proposal-add-windows-support
Browse files Browse the repository at this point in the history
  • Loading branch information
MarvinJWendt committed Jun 4, 2022
2 parents b809a13 + d46366e commit 5b50ff4
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 86 deletions.
8 changes: 8 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
coverage:
status:
project:
default:
informational: true
patch:
default:
informational: true
5 changes: 2 additions & 3 deletions cursor.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ package cursor

import (
"fmt"
"io"
"os"
)

var target io.Writer = os.Stdout
var target Writer = os.Stdout

// SetTarget allows for any arbitrary io.Writer to be used
// for cursor movement (will not work on Windows).
func SetTarget(w io.Writer) {
func SetTarget(w Writer) {
target = w
}

Expand Down
74 changes: 0 additions & 74 deletions cursor_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package cursor

import (
"bytes"
"fmt"
"runtime"
"testing"
)

Expand All @@ -27,75 +25,3 @@ func TestHeightCannotBeNegative(t *testing.T) {
t.Errorf("height is negative: %d", height)
}
}

func TestCustomIOWriter(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("skipping these tests on windows")
}

var w bytes.Buffer
SetTarget(&w)

Up(2)
expected := "\x1b[2A"
actual := w.String()
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}

w.Reset()
Down(2)
expected = "\x1b[2B"
actual = w.String()
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}

w.Reset()
Right(2)
expected = "\x1b[2C"
actual = w.String()
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}

w.Reset()
Left(2)
expected = "\x1b[2D"
actual = w.String()
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}

w.Reset()
Hide()
expected = "\x1b[?25l"
actual = w.String()
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}

w.Reset()
Show()
expected = "\x1b[?25h"
actual = w.String()
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}

w.Reset()
ClearLine()
expected = "\x1b[2K"
actual = w.String()
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}

w.Reset()
HorizontalAbsolute(3)
expected = "\x1b[4G"
actual = w.String()
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}
}
109 changes: 109 additions & 0 deletions cursor_test_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package cursor

import (
"log"
"os"
"testing"
)

func TestCustomIOWriter(t *testing.T) {
tmpFile, err := os.CreateTemp("", "testingTmpFile-")
if err != nil {
log.Fatal(err)
}
defer os.Remove(tmpFile.Name())

w := tmpFile
SetTarget(w)

Up(2)
expected := "\x1b[2A"
actual := getFileContent(t, w.Name())
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}

clearFile(t, w)
Down(2)
expected = "\x1b[2B"
actual = getFileContent(t, w.Name())
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}

clearFile(t, w)
Right(2)
expected = "\x1b[2C"
actual = getFileContent(t, w.Name())
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}

clearFile(t, w)
Left(2)
expected = "\x1b[2D"
actual = getFileContent(t, w.Name())
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}

clearFile(t, w)
Hide()
expected = "\x1b[?25l"
actual = getFileContent(t, w.Name())
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}

clearFile(t, w)
Show()
expected = "\x1b[?25h"
actual = getFileContent(t, w.Name())
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}

clearFile(t, w)
ClearLine()
expected = "\x1b[2K"
actual = getFileContent(t, w.Name())
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}

clearFile(t, w)
HorizontalAbsolute(3)
expected = "\x1b[4G"
actual = getFileContent(t, w.Name())
if expected != actual {
t.Errorf("wanted: %v, got %v", expected, actual)
}
}

func getFileContent(t *testing.T, fileName string) string {
t.Helper()
content, err := os.ReadFile(fileName)
if err != nil {
t.Errorf("failed to read file contents: %s", err)

return ""
}

return string(content)
}

func clearFile(t *testing.T, file *os.File) {
t.Helper()
err := file.Truncate(0)
if err != nil {
t.Errorf("failed to clear file")

return
}
_, err = file.Seek(0, 0)
if err != nil {
t.Errorf("failed to clear file")

return
}
}
19 changes: 10 additions & 9 deletions cursor_windows.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package cursor

import (
"io"
"os"
"syscall"
"unsafe"
)

// SetTarget allows for any arbitrary io.Writer to be used
// for cursor movement (will not work on Windows).
func SetTarget(w io.Writer) {
var target Writer = os.Stdout

// SetTarget allows for any arbitrary Writer to be used
func SetTarget(w Writer) {
target = w
}

// Up moves the cursor n lines up relative to the current position.
Expand Down Expand Up @@ -39,7 +40,7 @@ func Left(n int) {
}

func move(x int, y int) {
handle := syscall.Handle(os.Stdout.Fd())
handle := syscall.Handle(target.Fd())

var csbi consoleScreenBufferInfo
_, _, _ = procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
Expand All @@ -54,7 +55,7 @@ func move(x int, y int) {
// HorizontalAbsolute moves the cursor to n horizontally.
// The position n is absolute to the start of the line.
func HorizontalAbsolute(n int) {
handle := syscall.Handle(os.Stdout.Fd())
handle := syscall.Handle(target.Fd())

var csbi consoleScreenBufferInfo
_, _, _ = procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
Expand All @@ -74,7 +75,7 @@ func HorizontalAbsolute(n int) {
// Don't forget to show the cursor at least at the end of your application.
// Otherwise the user might have a terminal with a permanently hidden cursor, until he reopens the terminal.
func Show() {
handle := syscall.Handle(os.Stdout.Fd())
handle := syscall.Handle(target.Fd())

var cci consoleCursorInfo
_, _, _ = procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci)))
Expand All @@ -87,7 +88,7 @@ func Show() {
// Don't forget to show the cursor at least at the end of your application with Show.
// Otherwise the user might have a terminal with a permanently hidden cursor, until he reopens the terminal.
func Hide() {
handle := syscall.Handle(os.Stdout.Fd())
handle := syscall.Handle(target.Fd())

var cci consoleCursorInfo
_, _, _ = procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci)))
Expand All @@ -98,7 +99,7 @@ func Hide() {

// ClearLine clears the current line and moves the cursor to it's start position.
func ClearLine() {
handle := syscall.Handle(os.Stdout.Fd())
handle := syscall.Handle(target.Fd())

var csbi consoleScreenBufferInfo
_, _, _ = procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
Expand Down
7 changes: 7 additions & 0 deletions utils.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package cursor

import "io"

var height int

// Bottom moves the cursor to the bottom of the terminal.
Expand Down Expand Up @@ -71,3 +73,8 @@ func ClearLinesDown(n int) {
DownAndClear(1)
}
}

type Writer interface {
io.Writer
Fd() uintptr
}

0 comments on commit 5b50ff4

Please sign in to comment.