package main // A simple program demonstrating the text area component from the Bubbles // component library. import ( "fmt" "log" "strings" "github.com/charmbracelet/bubbles/textarea" "github.com/charmbracelet/bubbles/viewport" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" ) func main() { p := tea.NewProgram(initialModel()) if err := p.Start(); err != nil { log.Fatal(err) } } type ( tickMsg struct{} errMsg error ) type model struct { viewport viewport.Model messages []string textarea textarea.Model senderStyle lipgloss.Style err error } func initialModel() model { ta := textarea.New() ta.Placeholder = "Send a message..." ta.Focus() ta.Prompt = "┃ " ta.CharLimit = 280 ta.SetWidth(30) ta.SetHeight(3) // Remove cursor line styling ta.FocusedStyle.CursorLine = lipgloss.NewStyle() ta.ShowLineNumbers = false vp := viewport.New(30, 10) vp.SetContent(`Welcome to the Bubbles multi-line text input! Try typing any message and pressing ENTER. If you write a long message, it will automatically wrap :D `) ta.KeyMap.InsertNewline.SetEnabled(false) return model{ textarea: ta, messages: []string{}, viewport: vp, senderStyle: lipgloss.NewStyle().Foreground(lipgloss.Color("5")), err: nil, } } func (m model) Init() tea.Cmd { return textarea.Blink } func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var ( tiCmd tea.Cmd vpCmd tea.Cmd ) m.textarea, tiCmd = m.textarea.Update(msg) m.viewport, vpCmd = m.viewport.Update(msg) switch msg := msg.(type) { case tea.KeyMsg: switch msg.Type { case tea.KeyCtrlC, tea.KeyEsc: fmt.Println(m.textarea.Value()) return m, tea.Quit case tea.KeyEnter: m.messages = append(m.messages, m.senderStyle.Render("You: ")+m.textarea.Value()) m.viewport.SetContent(strings.Join(m.messages, "\n")) m.textarea.Reset() m.viewport.GotoBottom() } // We handle errors just like any other message case errMsg: m.err = msg return m, nil } return m, tea.Batch(tiCmd, vpCmd) } func (m model) View() string { return fmt.Sprintf( "%s\n\n%s", m.viewport.View(), m.textarea.View(), ) + "\n\n" }