-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Copy pathloc.go
148 lines (131 loc) · 2.9 KB
/
loc.go
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package buffer
import (
"github.com/zyedidia/micro/v2/internal/util"
)
// Loc stores a location
type Loc struct {
X, Y int
}
// LessThan returns true if b is smaller
func (l Loc) LessThan(b Loc) bool {
if l.Y < b.Y {
return true
}
return l.Y == b.Y && l.X < b.X
}
// GreaterThan returns true if b is bigger
func (l Loc) GreaterThan(b Loc) bool {
if l.Y > b.Y {
return true
}
return l.Y == b.Y && l.X > b.X
}
// GreaterEqual returns true if b is greater than or equal to b
func (l Loc) GreaterEqual(b Loc) bool {
if l.Y > b.Y {
return true
}
if l.Y == b.Y && l.X > b.X {
return true
}
return l == b
}
// LessEqual returns true if b is less than or equal to b
func (l Loc) LessEqual(b Loc) bool {
if l.Y < b.Y {
return true
}
if l.Y == b.Y && l.X < b.X {
return true
}
return l == b
}
// The following functions require a buffer to know where newlines are
// Diff returns the distance between two locations
func DiffLA(a, b Loc, buf *LineArray) int {
if a.Y == b.Y {
if a.X > b.X {
return a.X - b.X
}
return b.X - a.X
}
// Make sure a is guaranteed to be less than b
if b.LessThan(a) {
a, b = b, a
}
loc := 0
for i := a.Y + 1; i < b.Y; i++ {
// + 1 for the newline
loc += util.CharacterCount(buf.LineBytes(i)) + 1
}
loc += util.CharacterCount(buf.LineBytes(a.Y)) - a.X + b.X + 1
return loc
}
// This moves the location one character to the right
func (l Loc) right(buf *LineArray) Loc {
if l == buf.End() {
return Loc{l.X + 1, l.Y}
}
var res Loc
if l.X < util.CharacterCount(buf.LineBytes(l.Y)) {
res = Loc{l.X + 1, l.Y}
} else {
res = Loc{0, l.Y + 1}
}
return res
}
// This moves the given location one character to the left
func (l Loc) left(buf *LineArray) Loc {
if l == buf.Start() {
return Loc{l.X - 1, l.Y}
}
var res Loc
if l.X > 0 {
res = Loc{l.X - 1, l.Y}
} else {
res = Loc{util.CharacterCount(buf.LineBytes(l.Y - 1)), l.Y - 1}
}
return res
}
// MoveLA moves the cursor n characters to the left or right
// It moves the cursor left if n is negative
func (l Loc) MoveLA(n int, buf *LineArray) Loc {
if n > 0 {
for i := 0; i < n; i++ {
l = l.right(buf)
}
return l
}
for i := 0; i < util.Abs(n); i++ {
l = l.left(buf)
}
return l
}
// Diff returns the difference between two locs
func (l Loc) Diff(b Loc, buf *Buffer) int {
return DiffLA(l, b, buf.LineArray)
}
// Move moves a loc n characters
func (l Loc) Move(n int, buf *Buffer) Loc {
return l.MoveLA(n, buf.LineArray)
}
// ByteOffset is just like ToCharPos except it counts bytes instead of runes
func ByteOffset(pos Loc, buf *Buffer) int {
x, y := pos.X, pos.Y
loc := 0
for i := 0; i < y; i++ {
// + 1 for the newline
loc += len(buf.Line(i)) + 1
}
loc += len(buf.Line(y)[:x])
return loc
}
// clamps a loc within a buffer
func clamp(pos Loc, la *LineArray) Loc {
if pos.GreaterEqual(la.End()) {
return la.End()
} else if pos.LessThan(la.Start()) {
return la.Start()
}
return pos
}