charmbracelet / bubbles

TUI components for Bubble Tea 🫧

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

textarea: Text reflow off by one

mikelorant opened this issue · comments

When adding text in the textarea, the reflow capability is activating one character too early.

Create a textarea with a width of 10. This should allow 10 characters and cause reflow to activate on the 11th character. A single "word" of 10 characters will fit. If there is any break in the string, only 9 characters is allowed. The 10th character takes the preceeding word and moves it to the next line.

Test case is:

1234567890
1 2 3 4 5

Adding 6 should fit however it causes 56 to reflow to the next line.

My hypothesis of what is happening is as follows:

  • Under no circumstances is the cursor allowed to be in the 11th character position.
  • 10 sequential values without spaces has no determinable break point. This means that the 11th character MUST be on the next line and this immediately happens when the 10th character is added.
  • When there is a space within the line, moving to the cursor to the 11th character position immediately forces all proceeding characters of that word to move to the next line. It is uncertain whether the next character will be a space which would allow the text to move back to the previous line. As soon as the space is added, the text stays where it is. This then causes the off by 1 error.

What I believe should happen is that the text should not reflow on the 10th character however the cursor should move to the next line. If a space is entered, nothing changes and the next character afterwards will be rendered. If another character is added the previous line should have the word moved to the next line.

Is this the expected outcome? Fixing this issue may be significantly more complex than the gain.

Use the following code to reproduce this issue:

package main

import (
    "github.com/charmbracelet/bubbles/textarea"
    tea "github.com/charmbracelet/bubbletea"
)

func main() {
    p := tea.NewProgram(initialModel())
    p.Run()
}

type model struct {
    textarea textarea.Model
}

func initialModel() model {
    ti := textarea.New()
    ti.Focus()
    ti.ShowLineNumbers = false
    ti.Prompt = ""
    ti.SetWidth(10)

    return model{
        textarea: ti,
    }
}

func (m model) Init() tea.Cmd {
    return textarea.Blink
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    var cmd tea.Cmd

    switch msg := msg.(type) {
    case tea.KeyMsg:
        switch msg.Type {
        case tea.KeyCtrlC:
            return m, tea.Quit
        }
    }

    m.textarea, cmd = m.textarea.Update(msg)
    return m, cmd
}

func (m model) View() string {
    return m.textarea.View()
}

Looking through the code I believe the problem may be within this function however it is difficult to determine the exact cause of the bug:
https://github.com/charmbracelet/bubbles/blob/master/textarea/textarea.go#L1239