diff --git a/textinput/textinput.go b/textinput/textinput.go index 363089b2d..615f173fc 100644 --- a/textinput/textinput.go +++ b/textinput/textinput.go @@ -719,15 +719,16 @@ func (m Model) View() string { } } - // If a max width and background color were set fill the empty spaces with - // the background color. + // Pad the rest of the input out to its full width. The padding spaces are + // left unstyled so that Text styling stops at the value's end, matching + // the placeholder's behavior. See #245. valWidth := uniseg.StringWidth(string(value)) if m.Width() > 0 && valWidth <= m.Width() { padding := max(0, m.Width()-valWidth) if valWidth+padding <= m.Width() && pos < len(value) { padding++ } - v += styleText(strings.Repeat(" ", padding)) + v += strings.Repeat(" ", padding) } return m.promptView() + v @@ -768,9 +769,11 @@ func (m Model) placeholderView() string { minWidth += availWidth availWidth = 0 } - // append placeholder[len] - cursor, append padding + // append placeholder[len] - cursor, append padding (padding is + // intentionally unstyled so the placeholder color only covers the + // placeholder text itself, matching the text-mode behavior in View). v += render(string(p[1:minWidth])) - v += render(strings.Repeat(" ", availWidth)) + v += strings.Repeat(" ", availWidth) } else { // if there is no width, the placeholder can be any length v += render(string(p[1:])) diff --git a/textinput/textinput_test.go b/textinput/textinput_test.go index b5e344b99..bc9c03f5b 100644 --- a/textinput/textinput_test.go +++ b/textinput/textinput_test.go @@ -7,6 +7,7 @@ import ( "testing" tea "charm.land/bubbletea/v2" + "charm.land/lipgloss/v2" ) func Test_CurrentSuggestion(t *testing.T) { @@ -107,6 +108,36 @@ func ExampleValidateFunc() { } } +func TestTextStyleAndPlaceholderStyleScopeMatch(t *testing.T) { + // Regression test for #245. The padding spaces that fill the input out to + // its full width must not pick up the Text or Placeholder style, otherwise + // the user sees a styled background extending past the actual text. Both + // the text and placeholder code paths should agree. + bg := lipgloss.NewStyle().Background(lipgloss.Color("#AFAFAF")) + + m := New() + m.SetWidth(20) + m.Placeholder = "Pies" + styles := m.Styles() + styles.Focused.Text = bg + styles.Focused.Placeholder = bg + styles.Blurred.Text = bg + styles.Blurred.Placeholder = bg + m.SetStyles(styles) + m.Blur() + + placeholderView := m.View() + if !strings.HasSuffix(placeholderView, strings.Repeat(" ", 17)) { + t.Errorf("placeholder view should end with unstyled padding spaces, got %q", placeholderView) + } + + m.SetValue("foo") + textView := m.View() + if !strings.HasSuffix(textView, strings.Repeat(" ", 17)) { + t.Errorf("text view should end with unstyled padding spaces, got %q", textView) + } +} + func keyPress(key rune) tea.Msg { return tea.KeyPressMsg{Code: key, Text: string(key)} }