Skip to content

Commit 3dfd444

Browse files
authored
Merge pull request #658 from rumpl/nicer-selection
Nicer selection highlight
2 parents eb8adcd + 07750f0 commit 3dfd444

1 file changed

Lines changed: 26 additions & 13 deletions

File tree

pkg/tui/components/messages/messages.go

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ type selectionState struct {
7272
endLine int
7373
endCol int
7474
mouseButtonDown bool
75+
mouseY int // Screen Y coordinate for autoscroll
7576
}
7677

7778
// start initializes a new selection at the given position
@@ -156,13 +157,15 @@ func (m *model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
156157
if msg.Button == tea.MouseLeft {
157158
line, col := m.mouseToLineCol(msg.X, msg.Y)
158159
m.selection.start(line, col)
160+
m.selection.mouseY = msg.Y // Store screen Y for autoscroll
159161
}
160162
return m, nil
161163

162164
case tea.MouseMotionMsg:
163165
if m.selection.mouseButtonDown && m.selection.active {
164166
line, col := m.mouseToLineCol(msg.X, msg.Y)
165167
m.selection.update(line, col)
168+
m.selection.mouseY = msg.Y // Store screen Y for autoscroll
166169

167170
cmd := m.autoScroll()
168171
return m, cmd
@@ -945,15 +948,17 @@ func (m *model) applySelectionHighlight(lines []string, viewportStartLine int) [
945948
case absoluteLine == startLine:
946949
// Start of multi-line selection
947950
plainLine := ansi.Strip(line)
948-
lineWidth := runewidth.StringWidth(plainLine)
951+
trimmedLine := strings.TrimRight(plainLine, " \t")
952+
lineWidth := runewidth.StringWidth(trimmedLine)
949953
highlighted[i] = m.highlightLine(line, startCol, lineWidth)
950954
case absoluteLine == endLine:
951955
// End of multi-line selection
952956
highlighted[i] = m.highlightLine(line, 0, endCol)
953957
default:
954958
// Middle of multi-line selection
955959
plainLine := ansi.Strip(line)
956-
lineWidth := runewidth.StringWidth(plainLine)
960+
trimmedLine := strings.TrimRight(plainLine, " \t")
961+
lineWidth := runewidth.StringWidth(trimmedLine)
957962
highlighted[i] = m.highlightLine(line, 0, lineWidth)
958963
}
959964
}
@@ -1007,23 +1012,31 @@ func (m *model) autoScroll() tea.Cmd {
10071012
const scrollThreshold = 2
10081013
direction := 0
10091014

1010-
if m.selection.endCol < scrollThreshold && m.scrollOffset > 0 {
1011-
// Scroll up
1015+
// Use stored screen Y coordinate to check if mouse is in autoscroll region
1016+
// mouseToLineCol subtracts 2 for header, so viewport-relative Y is mouseY - 2
1017+
viewportY := m.selection.mouseY - 2
1018+
1019+
// Ensure viewportY is valid (can't be negative or beyond viewport)
1020+
if viewportY < 0 {
1021+
viewportY = 0
1022+
}
1023+
1024+
if viewportY < scrollThreshold && m.scrollOffset > 0 {
1025+
// Scroll up - mouse is near top of viewport
10121026
direction = -1
10131027
m.scrollUp()
1014-
if m.selection.endLine > 0 {
1015-
m.selection.endLine--
1016-
}
1017-
} else if m.selection.endCol >= m.height-scrollThreshold {
1018-
// Scroll down
1028+
// Update endLine to reflect new scroll position
1029+
// When scrolling up, content moves up, so mouse points to a line that's 1 less in absolute terms
1030+
m.selection.endLine = max(0, m.selection.endLine-1)
1031+
} else if viewportY >= m.height-scrollThreshold && viewportY < m.height {
1032+
// Scroll down - mouse is near bottom of viewport
10191033
maxScrollOffset := max(0, m.totalHeight-m.height)
10201034
if m.scrollOffset < maxScrollOffset {
10211035
direction = 1
10221036
m.scrollDown()
1023-
lines := strings.Split(m.rendered, "\n")
1024-
if m.selection.endLine < len(lines)-1 {
1025-
m.selection.endLine++
1026-
}
1037+
// Update endLine to reflect new scroll position
1038+
// When scrolling down, content moves down, so mouse points to a line that's 1 more in absolute terms
1039+
m.selection.endLine++
10271040
}
10281041
}
10291042

0 commit comments

Comments
 (0)