-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathselect.go
More file actions
127 lines (116 loc) · 3.04 KB
/
Copy pathselect.go
File metadata and controls
127 lines (116 loc) · 3.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package termview
import (
"strings"
uv "github.com/charmbracelet/ultraviolet"
)
func (m Model) hasSelection() bool {
if !m.isSelecting {
return false
}
// Check that start and end coordinates are not the same. If they are, then there is no selection.
// We do not support single character selection, because on every mouse click, the will be a selected
// cell which looks like another cursor. Consider this as a feature, at lest for now.
return m.startX != m.endX || m.startY != m.endY
}
func normalize(sx, sy, ex, ey int) (x1, y1, x2, y2 int) {
x1, y1, x2, y2 = sx, sy, ex, ey
// If user selected from bottom to top
if y1 > y2 {
return x2, y2, x1, y1
}
// If user selected from right to left
if y1 == y2 && x1 > x2 {
return x2, y2, x1, y1
}
// Otherwise, return as is
return x1, y1, x2, y2
}
func inSelection(x, y, left, top, right, bottom int) bool {
// If beyond selection bounds, return false.
if y < top || y > bottom {
return false
}
// If on the same line, check if x is within the selection bounds.
if top == bottom {
return left <= x && x <= right
}
// If on the top line, check if x is to the right of the left bound.
if y == top {
return left <= x
}
// If on the bottom line, check if x is to the left of the right bound.
if y == bottom {
return x <= right
}
// Otherwise, it's a full middle line.
return true
}
func (m Model) bufferCell(x, bufY int) *uv.Cell {
if m.emu == nil || x < 0 || x >= m.width || bufY < 0 {
return nil
}
sbLen := m.emu.ScrollbackLen()
if bufY < sbLen {
return m.emu.ScrollbackCellAt(x, bufY)
}
screenY := bufY - sbLen
if screenY >= m.height {
return nil
}
return m.emu.CellAt(x, screenY)
}
func (m Model) selectedText() string {
left, top, right, bottom := normalize(m.startX, m.startY, m.endX, m.endY)
lines := []string{}
for bufY := top; bufY <= bottom; bufY++ {
selectedLine := false
var str strings.Builder
for x := 0; x < m.width; {
cell := m.bufferCell(x, bufY)
if cell == nil {
break
}
if inSelection(x, bufY, left, top, right, bottom) {
str.WriteString(cell.Content)
selectedLine = true
}
if cell.Width <= 0 {
x++
continue
}
x += cell.Width
}
if selectedLine {
lines = append(lines, strings.TrimRight(str.String(), " "))
}
}
return strings.Join(lines, "\n")
}
func (m Model) viewWithSelection() string {
left, top, right, bottom := normalize(m.startX, m.startY, m.endX, m.endY)
lines := make([]string, 0, m.height)
origin := m.emu.ScrollbackLen() - m.scrollOffset
for y := 0; y < m.height; y++ {
yRelativeToScrollback := origin + y
line := make(uv.Line, 0, m.width)
for x := 0; x < m.width; {
cell := m.bufferCell(x, yRelativeToScrollback)
if cell == nil {
line = append(line, uv.EmptyCell)
x++
continue
}
c := *cell
if c.Width <= 0 {
c.Width = 1
}
if inSelection(x, yRelativeToScrollback, left, top, right, bottom) {
c.Style.Attrs |= uv.AttrReverse
}
line = append(line, c)
x += c.Width
}
lines = append(lines, line.Render())
}
return strings.Join(lines, "\n")
}