From 3ba296c534e46fb6c5fc0f32452701988c9c007e Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Thu, 23 Jan 2025 11:49:34 -0500 Subject: [PATCH] (v2) Revert cursor position from v2-area (#709) * chore: revert "wip" This reverts commit d020289a27cd1f929bceae8a3ec88bed40ab78a6, reversing changes made to c288adf7ab3b618b5d0400bddc768fd41020d1f5. * chore: revert "feat(textarea): add SetOffset and CursorPosition methods" This reverts commit afbb7bc049ae53e2fa2543ac99cdfb9ffe9bec68. * chor: revert "fix(textarea): respect double-width characters in real cursor position" This reverts commit 804c3708016e720928bca9797c69ff5a315a2d6d. * chore: revert "feat(textarea): use a real cursor position" This reverts commit 8c3085a6cd90810887c9435b9885259379d5717c. --- textarea/textarea.go | 107 ++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 58 deletions(-) diff --git a/textarea/textarea.go b/textarea/textarea.go index 6510d85..42f063f 100644 --- a/textarea/textarea.go +++ b/textarea/textarea.go @@ -293,12 +293,6 @@ 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 @@ -386,11 +380,6 @@ 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() @@ -614,11 +603,6 @@ func (m *Model) CursorUp() { } } -// CursorPosition returns the current cursor position. -func (m Model) CursorPosition() (int, int) { - return m.col, m.row -} - // SetCursor moves the cursor to the given position. If the position is // out of bounds the cursor will be moved to the start or end accordingly. func (m *Model) SetCursor(col int) { @@ -664,8 +648,6 @@ func (m *Model) Reset() { m.value = make([][]rune, minHeight, maxLines) m.col = 0 m.row = 0 - m.realCol = 0 - m.realRow = 0 m.viewport.GotoTop() m.SetCursor(0) } @@ -1031,16 +1013,15 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { } // Need to check for completion before, because key is configurable and might be double assigned - // keyMsg, ok := msg.(tea.KeyMsg) - // if ok && key.Matches(keyMsg, m.KeyMap.AcceptSuggestion) { - // if m.canAcceptSuggestion() { - // m.value = m.matchedSuggestions[m.currentSuggestionIndex] - // m.format() - // m.row = len(m.value) - 1 - // m.CursorEnd() - // m.SetSuggestions(nil) - // } - // } + keyMsg, ok := msg.(tea.KeyMsg) + if ok && key.Matches(keyMsg, m.KeyMap.AcceptSuggestion) { + if m.canAcceptSuggestion() { + m.value = m.matchedSuggestions[m.currentSuggestionIndex] + m.format() + m.row = len(m.value) - 1 + m.CursorEnd() + } + } // Used to determine if the cursor should blink. oldRow, oldCol := m.cursorLineNumber(), m.col @@ -1176,26 +1157,12 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { cmds = append(cmds, cmd) newRow, newCol := m.cursorLineNumber(), m.col - cmds = append(cmds, tea.SetCursorPosition(m.offsetX+newCol, m.offsetY+newRow)) - m.Cursor, cmd = m.Cursor.Update(msg) - if cmd != nil { - cmds = append(cmds, cmd) - } - - if m.Cursor.Mode() == cursor.CursorBlink && (newRow != oldRow || newCol != oldCol) { + if (newRow != oldRow || newCol != oldCol) && m.Cursor.Mode() == cursor.CursorBlink { m.Cursor.Blink = false - 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.CharOffset, 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)) + cmd = m.Cursor.BlinkCmd() } + cmds = append(cmds, cmd) m.repositionView() @@ -1235,7 +1202,7 @@ func (m Model) View() string { style lipgloss.Style newLines int widestLineNumber int - // lineInfo = m.LineInfo() + lineInfo = m.LineInfo() ) displayLine := 0 @@ -1294,20 +1261,45 @@ func (m Model) View() string { wrappedLine = []rune(strings.TrimSuffix(string(wrappedLine), " ")) padding -= m.width - strwidth } + if m.row == l && lineInfo.RowOffset == wl { + ln := string(wrappedLine[:lineInfo.ColumnOffset]) + if m.SyntaxHighlighter == nil { + ln = style.Render(ln) + } else { + ln = m.SyntaxHighlighter(ln) + } + s.WriteString(ln) - ln = string(wrappedLine) - if m.SyntaxHighlighter == nil { - ln = style.Render(ln) + if m.col >= len(line) && lineInfo.CharOffset >= m.width { + m.Cursor.SetChar(" ") + s.WriteString(m.Cursor.View()) + // XXX: suggestions? + } else { + m.Cursor.SetChar(string(wrappedLine[lineInfo.ColumnOffset])) + if m.canAcceptSuggestion() && len(m.matchedSuggestions) > 0 { + suggestion := m.matchedSuggestions[m.currentSuggestionIndex] + if len(suggestion) >= m.row { + suggestion = suggestion[m.row:] + } + m.Cursor.TextStyle = m.activeStyle.Placeholder + if len(suggestion) > m.row && len(suggestion[m.row]) > m.col { + m.Cursor.SetChar(string(suggestion[m.row][m.col])) + } + } + s.WriteString(style.Render(m.Cursor.View())) + s.WriteString(style.Render(string(wrappedLine[lineInfo.ColumnOffset+1:]))) + s.WriteString(m.suggestionView(1)) + // XXX: suggestions + } } else { - ln = m.SyntaxHighlighter(ln) + ln := string(wrappedLine) + if m.SyntaxHighlighter == nil { + ln = style.Render(ln) + } else { + ln = m.SyntaxHighlighter(ln) + } + s.WriteString(ln) } - s.WriteString(ln) - - // if m.col < len(line) || lineInfo.CharOffset < m.width { - // if m.canAcceptSuggestion() && len(m.matchedSuggestions) > 0 { - // s.WriteString(m.suggestionView(1)) - // } - // } pad := strings.Repeat(" ", max(0, padding)) if m.SyntaxHighlighter == nil { @@ -1522,7 +1514,6 @@ func (m *Model) splitLine(row, col int) { m.value[row+1] = tail m.col = 0 - m.SetHeight(m.row + 2) m.row++ }