micro/internal/buffer/loc.go

149 lines
2.9 KiB
Go
Raw Normal View History

2018-08-27 19:53:10 +00:00
package buffer
2016-06-07 15:43:28 +00:00
2018-08-27 19:53:10 +00:00
import (
2020-05-04 14:16:15 +00:00
"github.com/zyedidia/micro/v2/internal/util"
2018-08-27 19:53:10 +00:00
)
2016-06-07 15:43:28 +00:00
// 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
}
2018-08-26 03:06:44 +00:00
return l.Y == b.Y && l.X < b.X
2016-06-07 15:43:28 +00:00
}
// GreaterThan returns true if b is bigger
func (l Loc) GreaterThan(b Loc) bool {
if l.Y > b.Y {
return true
}
2018-08-26 03:06:44 +00:00
return l.Y == b.Y && l.X > b.X
2016-06-07 15:43:28 +00:00
}
// 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
}
2018-08-26 03:06:44 +00:00
return l == b
2016-06-07 15:43:28 +00:00
}
// 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
}
2018-08-26 03:06:44 +00:00
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 {
2018-08-26 03:06:44 +00:00
if a.Y == b.Y {
if a.X > b.X {
return a.X - b.X
}
return b.X - a.X
2016-06-07 15:43:28 +00:00
}
2018-08-26 03:06:44 +00:00
// 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
2020-05-20 20:47:08 +00:00
loc += util.CharacterCount(buf.LineBytes(i)) + 1
2018-08-26 03:06:44 +00:00
}
2020-05-20 20:47:08 +00:00
loc += util.CharacterCount(buf.LineBytes(a.Y)) - a.X + b.X + 1
2018-08-26 03:06:44 +00:00
return loc
2016-06-07 15:43:28 +00:00
}
2016-07-10 17:26:05 +00:00
// This moves the location one character to the right
func (l Loc) right(buf *LineArray) Loc {
2016-06-07 15:43:28 +00:00
if l == buf.End() {
2016-06-07 20:10:39 +00:00
return Loc{l.X + 1, l.Y}
2016-06-07 15:43:28 +00:00
}
var res Loc
2020-05-20 20:47:08 +00:00
if l.X < util.CharacterCount(buf.LineBytes(l.Y)) {
2016-06-07 15:43:28 +00:00
res = Loc{l.X + 1, l.Y}
} else {
res = Loc{0, l.Y + 1}
}
return res
}
2016-07-10 17:26:05 +00:00
// This moves the given location one character to the left
func (l Loc) left(buf *LineArray) Loc {
2016-06-07 15:43:28 +00:00
if l == buf.Start() {
2016-06-07 20:10:39 +00:00
return Loc{l.X - 1, l.Y}
2016-06-07 15:43:28 +00:00
}
var res Loc
if l.X > 0 {
res = Loc{l.X - 1, l.Y}
} else {
2020-05-20 20:47:08 +00:00
res = Loc{util.CharacterCount(buf.LineBytes(l.Y - 1)), l.Y - 1}
2016-06-07 15:43:28 +00:00
}
return res
}
// MoveLA moves the cursor n characters to the left or right
2016-07-10 17:26:05 +00:00
// It moves the cursor left if n is negative
func (l Loc) MoveLA(n int, buf *LineArray) Loc {
2016-06-07 15:43:28 +00:00
if n > 0 {
2016-06-07 16:31:02 +00:00
for i := 0; i < n; i++ {
l = l.right(buf)
}
return l
}
2018-08-27 19:53:10 +00:00
for i := 0; i < util.Abs(n); i++ {
2016-08-18 18:31:09 +00:00
l = l.left(buf)
2016-06-07 15:43:28 +00:00
}
2016-06-07 16:31:02 +00:00
return l
2016-06-07 15:43:28 +00:00
}
// 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)
}
2019-08-27 01:06:27 +00:00
// 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
}
2020-02-09 19:30:20 +00:00
// clamps a loc within a buffer
func clamp(pos Loc, la *LineArray) Loc {
if pos.GreaterEqual(la.End()) {
2020-02-09 19:58:37 +00:00
return la.End()
2020-02-09 19:30:20 +00:00
} else if pos.LessThan(la.Start()) {
return la.Start()
}
return pos
}