]> git.lizzy.rs Git - micro.git/blob - cmd/micro/loc.go
Code optimisation (#1117)
[micro.git] / cmd / micro / loc.go
1 package main
2
3 // FromCharPos converts from a character position to an x, y position
4 func FromCharPos(loc int, buf *Buffer) Loc {
5         charNum := 0
6         x, y := 0, 0
7
8         lineLen := Count(buf.Line(y)) + 1
9         for charNum+lineLen <= loc {
10                 charNum += lineLen
11                 y++
12                 lineLen = Count(buf.Line(y)) + 1
13         }
14         x = loc - charNum
15
16         return Loc{x, y}
17 }
18
19 // ToCharPos converts from an x, y position to a character position
20 func ToCharPos(start Loc, buf *Buffer) int {
21         x, y := start.X, start.Y
22         loc := 0
23         for i := 0; i < y; i++ {
24                 // + 1 for the newline
25                 loc += Count(buf.Line(i)) + 1
26         }
27         loc += x
28         return loc
29 }
30
31 // InBounds returns whether the given location is a valid character position in the given buffer
32 func InBounds(pos Loc, buf *Buffer) bool {
33         if pos.Y < 0 || pos.Y >= buf.NumLines || pos.X < 0 || pos.X > Count(buf.Line(pos.Y)) {
34                 return false
35         }
36
37         return true
38 }
39
40 // ByteOffset is just like ToCharPos except it counts bytes instead of runes
41 func ByteOffset(pos Loc, buf *Buffer) int {
42         x, y := pos.X, pos.Y
43         loc := 0
44         for i := 0; i < y; i++ {
45                 // + 1 for the newline
46                 loc += len(buf.Line(i)) + 1
47         }
48         loc += len(buf.Line(y)[:x])
49         return loc
50 }
51
52 // Loc stores a location
53 type Loc struct {
54         X, Y int
55 }
56
57 // Diff returns the distance between two locations
58 func Diff(a, b Loc, buf *Buffer) int {
59         if a.Y == b.Y {
60                 if a.X > b.X {
61                         return a.X - b.X
62                 }
63                 return b.X - a.X
64         }
65
66         // Make sure a is guaranteed to be less than b
67         if b.LessThan(a) {
68                 a, b = b, a
69         }
70
71         loc := 0
72         for i := a.Y + 1; i < b.Y; i++ {
73                 // + 1 for the newline
74                 loc += Count(buf.Line(i)) + 1
75         }
76         loc += Count(buf.Line(a.Y)) - a.X + b.X + 1
77         return loc
78 }
79
80 // LessThan returns true if b is smaller
81 func (l Loc) LessThan(b Loc) bool {
82         if l.Y < b.Y {
83                 return true
84         }
85         if l.Y == b.Y && l.X < b.X {
86                 return true
87         }
88         return false
89 }
90
91 // GreaterThan returns true if b is bigger
92 func (l Loc) GreaterThan(b Loc) bool {
93         if l.Y > b.Y {
94                 return true
95         }
96         if l.Y == b.Y && l.X > b.X {
97                 return true
98         }
99         return false
100 }
101
102 // GreaterEqual returns true if b is greater than or equal to b
103 func (l Loc) GreaterEqual(b Loc) bool {
104         if l.Y > b.Y {
105                 return true
106         }
107         if l.Y == b.Y && l.X > b.X {
108                 return true
109         }
110         if l == b {
111                 return true
112         }
113         return false
114 }
115
116 // LessEqual returns true if b is less than or equal to b
117 func (l Loc) LessEqual(b Loc) bool {
118         if l.Y < b.Y {
119                 return true
120         }
121         if l.Y == b.Y && l.X < b.X {
122                 return true
123         }
124         if l == b {
125                 return true
126         }
127         return false
128 }
129
130 // This moves the location one character to the right
131 func (l Loc) right(buf *Buffer) Loc {
132         if l == buf.End() {
133                 return Loc{l.X + 1, l.Y}
134         }
135         var res Loc
136         if l.X < Count(buf.Line(l.Y)) {
137                 res = Loc{l.X + 1, l.Y}
138         } else {
139                 res = Loc{0, l.Y + 1}
140         }
141         return res
142 }
143
144 // This moves the given location one character to the left
145 func (l Loc) left(buf *Buffer) Loc {
146         if l == buf.Start() {
147                 return Loc{l.X - 1, l.Y}
148         }
149         var res Loc
150         if l.X > 0 {
151                 res = Loc{l.X - 1, l.Y}
152         } else {
153                 res = Loc{Count(buf.Line(l.Y - 1)), l.Y - 1}
154         }
155         return res
156 }
157
158 // Move moves the cursor n characters to the left or right
159 // It moves the cursor left if n is negative
160 func (l Loc) Move(n int, buf *Buffer) Loc {
161         if n > 0 {
162                 for i := 0; i < n; i++ {
163                         l = l.right(buf)
164                 }
165                 return l
166         }
167         for i := 0; i < Abs(n); i++ {
168                 l = l.left(buf)
169         }
170         return l
171 }