|
|
@@ -2,6 +2,7 @@ package buffer
|
|
|
|
|
|
import (
|
|
|
"unicode/utf8"
|
|
|
+ "slices"
|
|
|
|
|
|
"github.com/zyedidia/rope"
|
|
|
)
|
|
|
@@ -19,50 +20,68 @@ func (buf *Buffer) ensureRope() {
|
|
|
|
|
|
func (buf *Buffer) Insert(content rune) {
|
|
|
buf.ensureRope()
|
|
|
+ buf.CM.DeduplicateAndSort()
|
|
|
+
|
|
|
+ delta := 0
|
|
|
data := []byte(string(content))
|
|
|
shift := len(data)
|
|
|
|
|
|
for i := range buf.CM.Cursors {
|
|
|
cur := &buf.CM.Cursors[i]
|
|
|
- if cur.Offset < 0 {
|
|
|
- cur.Offset = 0
|
|
|
+
|
|
|
+ pos := cur.Offset + delta
|
|
|
+
|
|
|
+ if pos < 0 {
|
|
|
+ pos = 0
|
|
|
}
|
|
|
- if cur.Offset > buf.Rope.Len() {
|
|
|
- cur.Offset = buf.Rope.Len()
|
|
|
+ if pos > buf.Rope.Len() {
|
|
|
+ pos = buf.Rope.Len()
|
|
|
}
|
|
|
|
|
|
- buf.Rope.Insert(cur.Offset, data)
|
|
|
- cur.Offset += shift
|
|
|
- }
|
|
|
+ buf.Rope.Insert(pos, data)
|
|
|
+ cur.Offset = pos + shift
|
|
|
|
|
|
- buf.CM.DeduplicateAndSort()
|
|
|
+ delta += shift
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
func (buf *Buffer) Delete() {
|
|
|
buf.ensureRope()
|
|
|
|
|
|
+ buf.CM.DeduplicateAndSort()
|
|
|
+
|
|
|
+ delta := 0
|
|
|
+
|
|
|
for i := range buf.CM.Cursors {
|
|
|
cur := &buf.CM.Cursors[i]
|
|
|
- if cur.Offset <= 0 {
|
|
|
+
|
|
|
+ pos := cur.Offset + delta
|
|
|
+
|
|
|
+ if pos <= 0 {
|
|
|
+ cur.Offset = 0
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
- if cur.Offset > buf.Rope.Len() {
|
|
|
- cur.Offset = buf.Rope.Len()
|
|
|
+ if pos > buf.Rope.Len() {
|
|
|
+ pos = buf.Rope.Len()
|
|
|
}
|
|
|
|
|
|
- left := buf.Rope.Slice(0, cur.Offset)
|
|
|
+ left := buf.Rope.Slice(0, pos)
|
|
|
_, size := utf8.DecodeLastRune(left)
|
|
|
if size <= 0 {
|
|
|
size = 1
|
|
|
}
|
|
|
|
|
|
- start := cur.Offset - size
|
|
|
+ start := pos - size
|
|
|
if start < 0 {
|
|
|
start = 0
|
|
|
}
|
|
|
|
|
|
- buf.Rope.Remove(start, cur.Offset)
|
|
|
+ buf.Rope.Remove(start, pos)
|
|
|
+
|
|
|
+ deleted := pos - start
|
|
|
+ delta -= deleted
|
|
|
+
|
|
|
cur.Offset = start
|
|
|
}
|
|
|
|
|
|
@@ -82,6 +101,8 @@ func (buf *Buffer) MoveHoriz(dir int) {
|
|
|
_, goal := LineCol(buf.Rope, cur.Offset)
|
|
|
cur.Goal = goal
|
|
|
}
|
|
|
+
|
|
|
+ buf.CM.DeduplicateAndSort()
|
|
|
}
|
|
|
|
|
|
func (buf *Buffer) MoveVert(dir int) {
|
|
|
@@ -91,27 +112,80 @@ func (buf *Buffer) MoveVert(dir int) {
|
|
|
cur := &buf.CM.Cursors[i]
|
|
|
line, _ := LineCol(buf.Rope, cur.Offset)
|
|
|
|
|
|
- if line + dir < 0 || line + dir > LineCount(buf.Rope) {
|
|
|
+ targetLine := line + dir
|
|
|
+ if targetLine < 0 || targetLine >= LineCount(buf.Rope) {
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
- line += dir
|
|
|
- cur.Offset = OffsetForLine(buf.Rope, line) + cur.Goal
|
|
|
+ lineStart := OffsetForLine(buf.Rope, targetLine)
|
|
|
+ lineEnd := OffsetForLine(buf.Rope, targetLine+1)
|
|
|
+ lineLen := lineEnd - lineStart
|
|
|
+ if lineLen < 0 {
|
|
|
+ lineLen = 0
|
|
|
+ }
|
|
|
+
|
|
|
+ goal := cur.Goal
|
|
|
+ if goal > lineLen {
|
|
|
+ goal = lineLen
|
|
|
+ }
|
|
|
+
|
|
|
+ cur.Offset = lineStart + goal
|
|
|
}
|
|
|
+
|
|
|
+ buf.CM.DeduplicateAndSort()
|
|
|
}
|
|
|
|
|
|
-func LineCount(r *rope.Node) int {
|
|
|
- if r.Len() == 0 {
|
|
|
- return 0
|
|
|
- }
|
|
|
+func (buf *Buffer) AddCursorVert(dir int) {
|
|
|
+ buf.ensureRope()
|
|
|
|
|
|
- lines := r.Count(0, r.Len(), []byte{'\n'})
|
|
|
+ var newCursors []Cursor
|
|
|
|
|
|
- if r.At(r.Len()-1) != '\n' {
|
|
|
- lines++
|
|
|
- }
|
|
|
+ for i := range buf.CM.Cursors {
|
|
|
+ cur := &buf.CM.Cursors[i]
|
|
|
+
|
|
|
+ line, _ := LineCol(buf.Rope, cur.Offset)
|
|
|
|
|
|
- return lines
|
|
|
+ targetLine := line + dir
|
|
|
+ if targetLine < 0 || targetLine >= LineCount(buf.Rope) {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ lineStart := OffsetForLine(buf.Rope, targetLine)
|
|
|
+ lineEnd := OffsetForLine(buf.Rope, targetLine+1)
|
|
|
+ lineLen := lineEnd - lineStart
|
|
|
+ if lineLen < 0 {
|
|
|
+ lineLen = 0
|
|
|
+ }
|
|
|
+
|
|
|
+ goal := cur.Goal
|
|
|
+ if goal > lineLen {
|
|
|
+ goal = lineLen
|
|
|
+ }
|
|
|
+
|
|
|
+ newCursors = append(newCursors, Cursor{
|
|
|
+ Offset: lineStart + goal,
|
|
|
+ Goal: goal,
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ buf.CM.Cursors = slices.Concat(buf.CM.Cursors, newCursors)
|
|
|
+
|
|
|
+ buf.CM.DeduplicateAndSort()
|
|
|
+}
|
|
|
+
|
|
|
+func (buf *Buffer) ClearCursors() {
|
|
|
+ primaryCursor := &Cursor{
|
|
|
+ Offset: buf.CM.Cursors[buf.CM.PrimaryIdx].Offset,
|
|
|
+ Goal: buf.CM.Cursors[buf.CM.PrimaryIdx].Goal,
|
|
|
+ }
|
|
|
+
|
|
|
+ buf.CM.Cursors = buf.CM.Cursors[:0]
|
|
|
+ buf.CM.Cursors = append(buf.CM.Cursors, *primaryCursor)
|
|
|
+ buf.CM.PrimaryIdx = 0
|
|
|
+}
|
|
|
+
|
|
|
+func LineCount(r *rope.Node) int {
|
|
|
+ return r.Count(0, r.Len(), []byte{'\n'}) + 1
|
|
|
}
|
|
|
|
|
|
func LineCol(r *rope.Node, offset int) (line, col int) {
|