From 8c3085a6cd90810887c9435b9885259379d5717c Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Wed, 13 Nov 2024 13:09:40 -0500 Subject: [PATCH] feat(textarea): use a real cursor position This sets the real cursor to its correct position when the cursor is moved. --- textarea/textarea.go | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/textarea/textarea.go b/textarea/textarea.go index b5e3aa34..6291a6f8 100644 --- a/textarea/textarea.go +++ b/textarea/textarea.go @@ -272,6 +272,12 @@ type Model struct { // Cursor row. row int + // The bubble offset relative to the parent bubble. + offsetX, offsetY int + + // The last recorded real cursor position. + realCol, realRow int + // Last character offset, used to maintain state when the cursor is moved // vertically such that we can maintain the same navigating position. lastCharOffset int @@ -358,6 +364,11 @@ func DefaultDarkStyles() Styles { return DefaultStyles(true) } +// SetOffset sets the offset of the textarea relative to the parent bubble. +func (m *Model) SetOffset(x, y int) { + m.offsetX, m.offsetY = x, y +} + // SetValue sets the value of the text input. func (m *Model) SetValue(s string) { m.Reset() @@ -1101,11 +1112,23 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { newRow, newCol := m.cursorLineNumber(), m.col m.Cursor, cmd = m.Cursor.Update(msg) - if (newRow != oldRow || newCol != oldCol) && m.Cursor.Mode() == cursor.CursorBlink { + if cmd != nil { + cmds = append(cmds, cmd) + } + + if m.Cursor.Mode() == cursor.CursorBlink && (newRow != oldRow || newCol != oldCol) { m.Cursor.Blink = false - cmd = m.Cursor.BlinkCmd() + cmds = append(cmds, m.Cursor.BlinkCmd()) + } + + // Ensure the real cursor is at the correct position. + row := m.cursorLineNumber() + lineInfo := m.LineInfo() + realCol, realRow := m.offsetX+lineInfo.ColumnOffset, m.offsetY+row-m.viewport.YOffset + if realCol != m.realCol || realRow != m.realRow { + m.realCol, m.realRow = realCol, realRow + cmds = append(cmds, tea.SetCursorPosition(realCol, realRow)) } - cmds = append(cmds, cmd) m.repositionView() @@ -1183,7 +1206,9 @@ func (m Model) View() string { wrappedLine = []rune(strings.TrimSuffix(string(wrappedLine), " ")) padding -= m.width - strwidth } - if m.row == l && lineInfo.RowOffset == wl { + + // We don't need to render the cursor if it's hidden. + if m.Cursor.Mode() != cursor.CursorHide && m.row == l && lineInfo.RowOffset == wl { s.WriteString(style.Render(string(wrappedLine[:lineInfo.ColumnOffset]))) if m.col >= len(line) && lineInfo.CharOffset >= m.width { m.Cursor.SetChar(" ")