Skip to content

Commit

Permalink
Fix re-rendering when prompt is exactly the width of the terminal (Al…
Browse files Browse the repository at this point in the history
…ecAivazis#321)

* Fix re-rendering when prompt is exactly the width of the terminal

The code that measures width of rendered lines of content and whether
any have overflown in the terminal did not account for the possibility
that the content could be _exactly_ the width of the terminal. In that
case, it shouldn't be counted as overflow.

* Reduce test dependencies by going straight to `pty`

This skips the go-expect & vt10x dependencies when stubbing only
terminal size and goes straight to the `creack/pty` library, which is
already used by go-expect under its old name, `kr/pty`.

* Use old name of `creack/pty` since it was already vendored
  • Loading branch information
mislav committed Dec 17, 2020
1 parent 85b98f3 commit e64d9b6
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 3 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/kr/pty v1.1.4 // indirect
github.com/kr/pty v1.1.4
github.com/mattn/go-colorable v0.1.2 // indirect
github.com/mattn/go-isatty v0.0.8
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b
Expand Down
11 changes: 9 additions & 2 deletions renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,15 @@ func (r *Renderer) countLines(buf bytes.Buffer) int {
delim = len(bufBytes) // no new line found, read rest of text
}

// account for word wrapping
count += int(utf8.RuneCount(bufBytes[curr:delim]) / w)
if lineWidth := utf8.RuneCount(bufBytes[curr:delim]); lineWidth > w {
// account for word wrapping
count += lineWidth / w
if (lineWidth % w) == 0 {
// content whose width is exactly a multiplier of available width should not
// count as having wrapped on the last line
count -= 1
}
}
curr = delim + 1
}

Expand Down
91 changes: 91 additions & 0 deletions renderer_posix_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// +build !windows

package survey

import (
"bytes"
"strings"
"testing"

"github.com/AlecAivazis/survey/v2/terminal"
pseudotty "github.com/kr/pty"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestRenderer_countLines(t *testing.T) {
t.Parallel()

termWidth := 72
pty, tty, err := pseudotty.Open()
require.Nil(t, err)
defer pty.Close()
defer tty.Close()

err = pseudotty.Setsize(tty, &pseudotty.Winsize{
Rows: 30,
Cols: uint16(termWidth),
})
require.Nil(t, err)

r := Renderer{
stdio: terminal.Stdio{
In: tty,
Out: tty,
Err: tty,
},
}

tests := []struct {
name string
buf *bytes.Buffer
wants int
}{
{
name: "empty",
buf: new(bytes.Buffer),
wants: 0,
},
{
name: "no newline",
buf: bytes.NewBufferString("hello"),
wants: 0,
},
{
name: "short line",
buf: bytes.NewBufferString("hello\n"),
wants: 1,
},
{
name: "three short lines",
buf: bytes.NewBufferString("hello\nbeautiful\nworld\n"),
wants: 3,
},
{
name: "full line",
buf: bytes.NewBufferString(strings.Repeat("A", termWidth) + "\n"),
wants: 1,
},
{
name: "overflow",
buf: bytes.NewBufferString(strings.Repeat("A", termWidth+1) + "\n"),
wants: 2,
},
{
name: "overflow fills 2nd line",
buf: bytes.NewBufferString(strings.Repeat("A", termWidth*2) + "\n"),
wants: 2,
},
{
name: "overflow spills to 3rd line",
buf: bytes.NewBufferString(strings.Repeat("A", termWidth*2+1) + "\n"),
wants: 3,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
n := r.countLines(*tt.buf)
assert.Equal(t, tt.wants, n)
})
}
}

0 comments on commit e64d9b6

Please sign in to comment.