fix(tui): textarea cursor sync issues with attachments

This commit is contained in:
adamdottv 2025-07-10 07:49:36 -05:00
parent b40ba32adc
commit d2b1307bff
No known key found for this signature in database
GPG key ID: 9CB48779AF150E75

View file

@ -931,7 +931,6 @@ func (m *Model) mapVisualOffsetToSliceIndex(row int, charOffset int) int {
}
// CursorDown moves the cursor down by one line.
// Returns whether or not the cursor blink should be reset.
func (m *Model) CursorDown() {
li := m.LineInfo()
charOffset := max(m.lastCharOffset, li.CharOffset)
@ -940,11 +939,73 @@ func (m *Model) CursorDown() {
if li.RowOffset+1 >= li.Height && m.row < len(m.value)-1 {
// Move to the next model line
m.row++
m.col = m.mapVisualOffsetToSliceIndex(m.row, charOffset)
// We want to land on the first wrapped line of the new model line.
grid := m.memoizedWrap(m.value[m.row], m.width)
targetLineContent := grid[0]
// Find position within the first wrapped line.
offset := 0
colInLine := 0
for i, item := range targetLineContent {
var itemWidth int
switch v := item.(type) {
case rune:
itemWidth = rw.RuneWidth(v)
case *Attachment:
itemWidth = uniseg.StringWidth(v.Display)
}
if offset+itemWidth > charOffset {
// Decide whether to stick with the previous index or move to the current
// one based on which is closer to the target offset.
if (charOffset - offset) > ((offset + itemWidth) - charOffset) {
colInLine = i + 1
} else {
colInLine = i
}
goto foundNextLine
}
offset += itemWidth
}
colInLine = len(targetLineContent)
foundNextLine:
m.col = colInLine // startCol is 0 for the first wrapped line
} else if li.RowOffset+1 < li.Height {
// Move to the next wrapped line within the same model line
startOfNextWrappedLine := li.StartColumn + li.Width
m.col = startOfNextWrappedLine + m.mapVisualOffsetToSliceIndex(m.row, charOffset)
grid := m.memoizedWrap(m.value[m.row], m.width)
targetLineContent := grid[li.RowOffset+1]
startCol := 0
for i := 0; i < li.RowOffset+1; i++ {
startCol += len(grid[i])
}
// Find position within the target wrapped line.
offset := 0
colInLine := 0
for i, item := range targetLineContent {
var itemWidth int
switch v := item.(type) {
case rune:
itemWidth = rw.RuneWidth(v)
case *Attachment:
itemWidth = uniseg.StringWidth(v.Display)
}
if offset+itemWidth > charOffset {
// Decide whether to stick with the previous index or move to the current
// one based on which is closer to the target offset.
if (charOffset - offset) > ((offset + itemWidth) - charOffset) {
colInLine = i + 1
} else {
colInLine = i
}
goto foundSameLine
}
offset += itemWidth
}
colInLine = len(targetLineContent)
foundSameLine:
m.col = startCol + colInLine
}
m.SetCursorColumn(m.col)
}