Skip to content

Commit

Permalink
Improve TTY detection
Browse files Browse the repository at this point in the history
Prior to this commit there was no TTY detection in the manager or tput
package. The result was that during non-interactive executions escape
sequences would also be written to the output stream. Additionally each
frame would also be written.

For example, running the following would result in a messy log file:

```
go run examples/advanced/main.go |& tee log.log
```

This introduces changes that do the following:

* If a TTY is not detected, do not render any spinner frames
* If a TTY is not detected, do not write escape sequences

It is also possible to override the above by setting the environment
variable `YSMRR_FORCE_TTY` to `true`. This will make ysmrr ignore tty
detection and render frames and write escape sequences.

An example of the above override can be seen in the `tput_test.go` file.
  • Loading branch information
chelnak committed Aug 14, 2022
1 parent e96d882 commit 9b447b0
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 8 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ go 1.18
require (
github.com/fatih/color v1.13.0
github.com/mattn/go-colorable v0.1.12
github.com/mattn/go-isatty v0.0.14
github.com/stretchr/testify v1.8.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
12 changes: 11 additions & 1 deletion manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/chelnak/ysmrr/pkg/colors"
"github.com/chelnak/ysmrr/pkg/tput"
"github.com/mattn/go-colorable"
"github.com/mattn/go-isatty"
)

// SpinnerManager manages spinners
Expand Down Expand Up @@ -42,6 +43,7 @@ type spinnerManager struct {
done chan bool
ticks *time.Ticker
frame int
tty bool
}

// AddSpinner adds a new spinner to the manager.
Expand Down Expand Up @@ -156,7 +158,10 @@ func (sm *spinnerManager) render() {
case <-sm.done:
return
case <-sm.ticks.C:
sm.renderFrame()
// Only render the frame if we are in a terminal.
if sm.tty {
sm.renderFrame()
}
}

tput.Rc(sm.writer)
Expand Down Expand Up @@ -208,6 +213,7 @@ func NewSpinnerManager(options ...managerOption) SpinnerManager {
messageColor: colors.NoColor,
writer: getWriter(),
done: make(chan bool),
tty: tty(),
}

for _, option := range options {
Expand All @@ -217,6 +223,10 @@ func NewSpinnerManager(options ...managerOption) SpinnerManager {
return sm
}

func tty() bool {
return isatty.IsTerminal(os.Stdout.Fd()) || os.Getenv("YSMRR_FORCE_TTY") == "true"
}

func getWriter() io.Writer {
// Windows support conveniently provided by github.com/mattn/go-colorable <3.
if runtime.GOOS == "windows" {
Expand Down
31 changes: 25 additions & 6 deletions pkg/tput/tput.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,55 @@ package tput
import (
"fmt"
"io"
"os"
"strings"

"github.com/mattn/go-isatty"
)

// Sc saves the current position of the cursor.
func Sc(w io.Writer) {
fmt.Fprint(w, "\u001b7")
write(w, "\u001b7")
}

// Rc restores the cursor to the saved position.
func Rc(w io.Writer) {
fmt.Fprint(w, "\u001b8")
write(w, "\u001b8")
}

// Civis hides the cursor.
func Civis(w io.Writer) {
fmt.Fprint(w, "\u001b[?25l")
write(w, "\u001b[?25l")
}

// Cnorm shows the cursor.
func Cnorm(w io.Writer) {
fmt.Fprintf(w, "\u001b[?25h")
writef(w, "\u001b[?25h")
}

// Cuu moves the cursor up by n lines.
func Cuu(w io.Writer, n int) {
fmt.Fprintf(w, "\u001b[%dA", n)
writef(w, "\u001b[%dA", n)
}

// BufScreen ensures that there are enough lines available
// by sending n * newlines to the writer.
func BufScreen(w io.Writer, n int) {
fmt.Fprintf(w, "%s", strings.Repeat("\n", n))
writef(w, "%s", strings.Repeat("\n", n))
}

func tty() bool {
return isatty.IsTerminal(os.Stdout.Fd()) || os.Getenv("YSMRR_FORCE_TTY") == "true"
}

func write(w io.Writer, s string) {
if tty() {
fmt.Fprint(w, s)
}
}

func writef(w io.Writer, format string, a ...interface{}) {
if tty() {
fmt.Fprintf(w, format, a...)
}
}
15 changes: 15 additions & 0 deletions pkg/tput/tput_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,26 @@ package tput_test
import (
"bytes"
"io"
"os"
"strings"
"testing"

"github.com/chelnak/ysmrr/pkg/tput"
"github.com/stretchr/testify/assert"
)

func setup() {
_ = os.Setenv("YSMRR_FORCE_TTY", "true")
}

func cleanup() {
_ = os.Unsetenv("YSMRR_FORCE_TTY")
}

func TestTput(t *testing.T) {
setup()
defer cleanup()

tests := []struct {
name string
fn func(w io.Writer)
Expand Down Expand Up @@ -48,6 +60,9 @@ func TestTput(t *testing.T) {
}

func TestTputCommandsWithInputs(t *testing.T) {
setup()
defer cleanup()

tests := []struct {
name string
input int
Expand Down

0 comments on commit 9b447b0

Please sign in to comment.