mirror of
https://github.com/sst/opencode.git
synced 2025-08-04 05:28:16 +00:00
fix(tui): textarea issues
This commit is contained in:
parent
ce0cebb7d7
commit
b40ba32adc
1 changed files with 96 additions and 28 deletions
|
@ -956,22 +956,77 @@ func (m *Model) CursorUp() {
|
|||
m.lastCharOffset = charOffset
|
||||
|
||||
if li.RowOffset <= 0 && m.row > 0 {
|
||||
// Move to the previous model line
|
||||
// Move to the previous model line. We want to land on the last wrapped
|
||||
// line of the previous model line.
|
||||
m.row--
|
||||
m.col = m.mapVisualOffsetToSliceIndex(m.row, charOffset)
|
||||
} else if li.RowOffset > 0 {
|
||||
// Move to the previous wrapped line within the same model line
|
||||
// To do this, we need to find the start of the previous wrapped line.
|
||||
prevLineInfo := m.LineInfo()
|
||||
// prevLineStart := 0
|
||||
if prevLineInfo.RowOffset > 0 {
|
||||
// This is complex, so we'll approximate by moving to the start of the current wrapped line
|
||||
// and then letting characterLeft handle it. A more precise calculation would
|
||||
// require re-wrapping to find the previous line's start.
|
||||
// For now, a simpler approach:
|
||||
m.col = li.StartColumn - 1
|
||||
grid := m.memoizedWrap(m.value[m.row], m.width)
|
||||
targetLineContent := grid[len(grid)-1]
|
||||
|
||||
// Find start of last wrapped line.
|
||||
startCol := len(m.value[m.row]) - len(targetLineContent)
|
||||
|
||||
// Find position within the last 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 foundPrevLine
|
||||
}
|
||||
offset += itemWidth
|
||||
}
|
||||
m.col = m.mapVisualOffsetToSliceIndex(m.row, charOffset)
|
||||
colInLine = len(targetLineContent)
|
||||
foundPrevLine:
|
||||
m.col = startCol + colInLine
|
||||
} else if li.RowOffset > 0 {
|
||||
// Move to the previous wrapped line within the same model line.
|
||||
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)
|
||||
}
|
||||
|
@ -1591,7 +1646,7 @@ func (m Model) View() string {
|
|||
// guaranteed to be a space since any other character would
|
||||
// have been wrapped.
|
||||
wrappedLineStr = strings.TrimSuffix(wrappedLineStr, " ")
|
||||
padding -= m.width - strwidth
|
||||
padding = m.width - uniseg.StringWidth(wrappedLineStr)
|
||||
}
|
||||
|
||||
if m.row == l && lineInfo.RowOffset == wl {
|
||||
|
@ -1903,6 +1958,16 @@ func (m *Model) splitLine(row, col int) {
|
|||
m.row++
|
||||
}
|
||||
|
||||
func itemWidth(item any) int {
|
||||
switch v := item.(type) {
|
||||
case rune:
|
||||
return rw.RuneWidth(v)
|
||||
case *Attachment:
|
||||
return uniseg.StringWidth(v.Display)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func wrapInterfaces(content []any, width int) [][]any {
|
||||
if width <= 0 {
|
||||
return [][]any{content}
|
||||
|
@ -1945,19 +2010,18 @@ func wrapInterfaces(content []any, width int) [][]any {
|
|||
}
|
||||
inSpaces = true
|
||||
spaceW += itemW
|
||||
} else {
|
||||
} else { // It's not a space, it's a character for a word.
|
||||
if inSpaces {
|
||||
// End of spaces
|
||||
if lineW > 0 && lineW+spaceW > width {
|
||||
lines = append(lines, []any{})
|
||||
lineW = 0
|
||||
} else {
|
||||
lineW += spaceW
|
||||
}
|
||||
// Add spaces to current line
|
||||
// We just finished a block of spaces. Handle them now.
|
||||
lineW += spaceW
|
||||
for i := 0; i < spaceW; i++ {
|
||||
lines[len(lines)-1] = append(lines[len(lines)-1], rune(' '))
|
||||
}
|
||||
if lineW > width {
|
||||
// The spaces made the line overflow. Start a new line for the upcoming word.
|
||||
lines = append(lines, []any{})
|
||||
lineW = 0
|
||||
}
|
||||
spaceW = 0
|
||||
}
|
||||
inSpaces = false
|
||||
|
@ -1966,20 +2030,24 @@ func wrapInterfaces(content []any, width int) [][]any {
|
|||
}
|
||||
}
|
||||
|
||||
// Handle any remaining word/spaces
|
||||
// Handle any remaining word/spaces at the end of the content.
|
||||
if wordW > 0 {
|
||||
if lineW > 0 && lineW+wordW > width {
|
||||
lines = append(lines, word)
|
||||
lineW = wordW
|
||||
} else {
|
||||
lines[len(lines)-1] = append(lines[len(lines)-1], word...)
|
||||
lineW += wordW
|
||||
}
|
||||
}
|
||||
if spaceW > 0 {
|
||||
if lineW > 0 && lineW+spaceW > width {
|
||||
lines = append(lines, []any{})
|
||||
}
|
||||
// There are trailing spaces. Add them.
|
||||
for i := 0; i < spaceW; i++ {
|
||||
lines[len(lines)-1] = append(lines[len(lines)-1], rune(' '))
|
||||
lineW += 1
|
||||
}
|
||||
if lineW > width {
|
||||
lines = append(lines, []any{})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue