@@ -350,13 +350,12 @@ func (l *list[T]) selectionView(view string, textOnly bool) string {
350350 scr := uv.NewScreenBuffer(area.Dx(), area.Dy())
351351 uv.NewStyledString(view).Draw(scr, area)
352352
353− selArea := uv.Rectangle{
354− Min: uv.Pos(l.selectionStartCol, l.selectionStartLine),
355− Max: uv.Pos(l.selectionEndCol, l.selectionEndLine),
356− }
357− selArea = selArea.Canon()
358−
353+ selArea := l.selectionArea(false)
359354 specialChars := getSpecialCharsMap()
355+ selStyle := uv.Style{
356+ Bg: t.TextSelection.GetBackground(),
357+ Fg: t.TextSelection.GetForeground(),
358+ }
360359
361360 isNonWhitespace := func(r rune) bool {
362361 return r != ' ' && r != '\t' && r != 0 && r != '\n' && r != '\r'
@@ -371,9 +370,9 @@ func (l *list[T]) selectionView(view string, textOnly bool) string {
371370 for y := range scr.Height() {
372371 bounds := selectionBounds{startX: -1, endX: -1, inSelection: false}
373372
374− if y >= selArea.Min.Y && y <= selArea.Max.Y {
373+ if y >= selArea.Min.Y && y < selArea.Max.Y {
375374 bounds.inSelection = true
376− if selArea.Min.Y == selArea.Max.Y {
375+ if selArea.Min.Y == selArea.Max.Y-1 {
377376 // Single line selection
378377 bounds.startX = selArea.Min.X
379378 bounds.endX = selArea.Max.X
@@ -381,7 +380,7 @@ func (l *list[T]) selectionView(view string, textOnly bool) string {
381380 // First line of multi-line selection
382381 bounds.startX = selArea.Min.X
383382 bounds.endX = scr.Width()
384− } else if y == selArea.Max.Y {
383+ } else if y == selArea.Max.Y-1 {
385384 // Last line of multi-line selection
386385 bounds.startX = 0
387386 bounds.endX = selArea.Max.X
@@ -470,13 +469,9 @@ func (l *list[T]) selectionView(view string, textOnly bool) string {
470469 continue
471470 }
472471
473− // Text selection styling, which is a Lip Gloss style. We must
474− // extract the values to use in a UV style, below.
475− ts := t.TextSelection
476−
477472 cell = cell.Clone()
478− cell.Style.Bg = ts.GetBackground()
479− cell.Style.Fg = ts.GetForeground()
473+ cell.Style.Bg = selStyle.Bg
474+ cell.Style.Fg = selStyle.Fg
480475 scr.SetCell(x, y, cell)
481476 }
482477 }
@@ -1706,11 +1701,75 @@ func (l *list[T]) HasSelection() bool {
17061701 return l.hasSelection()
17071702}
17081703
1704+func (l *list[T]) selectionArea(absolute bool) uv.Rectangle {
1705+ var startY int
1706+ if absolute {
1707+ startY, _ = l.viewPosition()
1708+ }
1709+ selArea := uv.Rectangle{
1710+ Min: uv.Pos(l.selectionStartCol, l.selectionStartLine+startY),
1711+ Max: uv.Pos(l.selectionEndCol, l.selectionEndLine+startY),
1712+ }
1713+ selArea = selArea.Canon()
1714+ selArea.Max.Y++ // make max Y exclusive
1715+ return selArea
1716+}
1717+
17091718// GetSelectedText returns the currently selected text.
17101719func (l *list[T]) GetSelectedText(paddingLeft int) string {
17111720 if !l.hasSelection() {
17121721 return ""
17131722 }
17141723
1715− return l.selectionView(l.View(), true)
1724+ selArea := l.selectionArea(true)
1725+ if selArea.Empty() {
1726+ return ""
1727+ }
1728+
1729+ selectionHeight := selArea.Dy()
1730+
1731+ tempBuf := uv.NewScreenBuffer(l.width, selectionHeight)
1732+ tempBufArea := tempBuf.Bounds()
1733+ renderedLines := l.getLines(selArea.Min.Y, selArea.Max.Y)
1734+ styled := uv.NewStyledString(renderedLines)
1735+ styled.Draw(tempBuf, tempBufArea)
1736+
1737+ // XXX: Left padding assumes the list component is rendered with absolute
1738+ // positioning. The chat component has a left margin of 1 and items in the
1739+ // list have a border of 1 plus a padding of 1. The paddingLeft parameter
1740+ // assumes this total left padding of 3 and we should fix that.
1741+ leftBorder := paddingLeft - 1
1742+
1743+ var b strings.Builder
1744+ for y := tempBufArea.Min.Y; y < tempBufArea.Max.Y; y++ {
1745+ var pending strings.Builder
1746+ for x := tempBufArea.Min.X + leftBorder; x < tempBufArea.Max.X; {
1747+ cell := tempBuf.CellAt(x, y)
1748+ if cell == nil || cell.IsZero() {
1749+ x++
1750+ continue
1751+ }
1752+ if y == 0 && x < selArea.Min.X {
1753+ x++
1754+ continue
1755+ }
1756+ if y == selectionHeight-1 && x > selArea.Max.X-1 {
1757+ break
1758+ }
1759+ if cell.Width == 1 && cell.Content == " " {
1760+ pending.WriteString(cell.Content)
1761+ x++
1762+ continue
1763+ }
1764+ b.WriteString(pending.String())
1765+ pending.Reset()
1766+ b.WriteString(cell.Content)
1767+ x += cell.Width
1768+ }
1769+ if y < tempBufArea.Max.Y-1 {
1770+ b.WriteByte('\n')
1771+ }
1772+ }
1773+
1774+ return b.String()
17161775}