diff --git a/textinput/textinput.go b/textinput/textinput.go index 363089b2d..55f88deaa 100644 --- a/textinput/textinput.go +++ b/textinput/textinput.go @@ -745,8 +745,19 @@ func (m Model) placeholderView() string { render = styles.Placeholder.Render ) - p := make([]rune, m.Width()+1) - copy(p, []rune(m.Placeholder)) + // Size the buffer to the longer of Width and the placeholder + // itself so that, when Width is 0 ("no width") or shorter than + // the placeholder, copy still pulls in every rune. The old + // `m.Width()+1` left exactly one slot when Width was 0, so all + // but the first character of the placeholder fell on the floor. + // See #950. + placeholderRunes := []rune(m.Placeholder) + size := m.Width() + 1 + if size < len(placeholderRunes) { + size = len(placeholderRunes) + } + p := make([]rune, size) + copy(p, placeholderRunes) m.virtualCursor.TextStyle = styles.Placeholder m.virtualCursor.SetChar(string(p[:1])) diff --git a/textinput/textinput_test.go b/textinput/textinput_test.go index b5e344b99..b4726b6ee 100644 --- a/textinput/textinput_test.go +++ b/textinput/textinput_test.go @@ -48,6 +48,28 @@ func Test_SlicingOutsideCap(t *testing.T) { textinput.View() } +// Regression for #950. When SetWidth(0) is used (the documented +// "no width" mode), the placeholder buffer was sized to exactly 1 +// rune and copy lost everything past the first character. The +// rendered placeholder was a single letter regardless of length. +func TestPlaceholderZeroWidth(t *testing.T) { + ti := New() + ti.Placeholder = "Something" + ti.SetWidth(0) + + got := ti.View() + // View output carries ANSI styling, so check each rune of the + // placeholder appears somewhere in the string in order. + idx := 0 + for _, r := range "Something" { + i := strings.IndexRune(got[idx:], r) + if i < 0 { + t.Fatalf("expected full placeholder %q to appear in view %q", "Something", got) + } + idx += i + 1 + } +} + func TestChinesePlaceholder(t *testing.T) { t.Skip("Skipping flaky test, the returned view seems incorrect. TODO: Needs investigation.") textinput := New()