]> git.lizzy.rs Git - micro.git/blob - internal/buffer/loc.go
Fix buffer tests and selection bug
[micro.git] / internal / buffer / loc.go
1 package buffer
2
3 import (
4         "unicode/utf8"
5
6         "github.com/zyedidia/micro/internal/util"
7 )
8
9 // Loc stores a location
10 type Loc struct {
11         X, Y int
12 }
13
14 // LessThan returns true if b is smaller
15 func (l Loc) LessThan(b Loc) bool {
16         if l.Y < b.Y {
17                 return true
18         }
19         return l.Y == b.Y && l.X < b.X
20 }
21
22 // GreaterThan returns true if b is bigger
23 func (l Loc) GreaterThan(b Loc) bool {
24         if l.Y > b.Y {
25                 return true
26         }
27         return l.Y == b.Y && l.X > b.X
28 }
29
30 // GreaterEqual returns true if b is greater than or equal to b
31 func (l Loc) GreaterEqual(b Loc) bool {
32         if l.Y > b.Y {
33                 return true
34         }
35         if l.Y == b.Y && l.X > b.X {
36                 return true
37         }
38         return l == b
39 }
40
41 // LessEqual returns true if b is less than or equal to b
42 func (l Loc) LessEqual(b Loc) bool {
43         if l.Y < b.Y {
44                 return true
45         }
46         if l.Y == b.Y && l.X < b.X {
47                 return true
48         }
49         return l == b
50 }
51
52 // The following functions require a buffer to know where newlines are
53
54 // Diff returns the distance between two locations
55 func DiffLA(a, b Loc, buf *LineArray) int {
56         if a.Y == b.Y {
57                 if a.X > b.X {
58                         return a.X - b.X
59                 }
60                 return b.X - a.X
61         }
62
63         // Make sure a is guaranteed to be less than b
64         if b.LessThan(a) {
65                 a, b = b, a
66         }
67
68         loc := 0
69         for i := a.Y + 1; i < b.Y; i++ {
70                 // + 1 for the newline
71                 loc += utf8.RuneCount(buf.LineBytes(i)) + 1
72         }
73         loc += utf8.RuneCount(buf.LineBytes(a.Y)) - a.X + b.X + 1
74         return loc
75 }
76
77 // This moves the location one character to the right
78 func (l Loc) right(buf *LineArray) Loc {
79         if l == buf.End() {
80                 return Loc{l.X + 1, l.Y}
81         }
82         var res Loc
83         if l.X < utf8.RuneCount(buf.LineBytes(l.Y)) {
84                 res = Loc{l.X + 1, l.Y}
85         } else {
86                 res = Loc{0, l.Y + 1}
87         }
88         return res
89 }
90
91 // This moves the given location one character to the left
92 func (l Loc) left(buf *LineArray) Loc {
93         if l == buf.Start() {
94                 return Loc{l.X - 1, l.Y}
95         }
96         var res Loc
97         if l.X > 0 {
98                 res = Loc{l.X - 1, l.Y}
99         } else {
100                 res = Loc{utf8.RuneCount(buf.LineBytes(l.Y - 1)), l.Y - 1}
101         }
102         return res
103 }
104
105 // MoveLA moves the cursor n characters to the left or right
106 // It moves the cursor left if n is negative
107 func (l Loc) MoveLA(n int, buf *LineArray) Loc {
108         if n > 0 {
109                 for i := 0; i < n; i++ {
110                         l = l.right(buf)
111                 }
112                 return l
113         }
114         for i := 0; i < util.Abs(n); i++ {
115                 l = l.left(buf)
116         }
117         return l
118 }
119
120 // Diff returns the difference between two locs
121 func (l Loc) Diff(b Loc, buf *Buffer) int {
122         return DiffLA(l, b, buf.LineArray)
123 }
124
125 // Move moves a loc n characters
126 func (l Loc) Move(n int, buf *Buffer) Loc {
127         return l.MoveLA(n, buf.LineArray)
128 }
129
130 // ByteOffset is just like ToCharPos except it counts bytes instead of runes
131 func ByteOffset(pos Loc, buf *Buffer) int {
132         x, y := pos.X, pos.Y
133         loc := 0
134         for i := 0; i < y; i++ {
135                 // + 1 for the newline
136                 loc += len(buf.Line(i)) + 1
137         }
138         loc += len(buf.Line(y)[:x])
139         return loc
140 }
141
142 // clamps a loc within a buffer
143 func clamp(pos Loc, la *LineArray) Loc {
144         if pos.GreaterEqual(la.End()) {
145                 return la.End()
146         } else if pos.LessThan(la.Start()) {
147                 return la.Start()
148         }
149         return pos
150 }