From 927dd9dba9c5b5479dea5254d4e02454ccb661ad Mon Sep 17 00:00:00 2001 From: Zachary Yedidia Date: Sun, 27 Mar 2016 15:22:57 -0400 Subject: [PATCH] Use a different rope implementation --- src/buffer.go | 24 ++++++++--- src/rope.go | 105 ----------------------------------------------- src/rope_test.go | 46 --------------------- 3 files changed, 18 insertions(+), 157 deletions(-) delete mode 100644 src/rope.go delete mode 100644 src/rope_test.go diff --git a/src/buffer.go b/src/buffer.go index 2020babe..0ffe5fc8 100644 --- a/src/buffer.go +++ b/src/buffer.go @@ -1,6 +1,7 @@ package main import ( + "github.com/vinzmay/go-rope" "io/ioutil" "strings" ) @@ -10,7 +11,7 @@ import ( // simple functions for saving and wrapper functions for modifying the rope type Buffer struct { // Stores the text of the buffer - r *Rope + r *rope.Rope // Path to the file on disk path string @@ -35,7 +36,11 @@ type Buffer struct { // NewBuffer creates a new buffer from `txt` with path and name `path` func NewBuffer(txt, path string) *Buffer { b := new(Buffer) - b.r = NewRope(txt) + if txt == "" { + b.r = new(rope.Rope) + } else { + b.r = rope.New(txt) + } b.path = path b.name = path b.savedText = txt @@ -54,7 +59,11 @@ func (b *Buffer) UpdateRules() { // Update fetches the string from the rope and updates the `text` and `lines` in the buffer func (b *Buffer) Update() { - b.text = b.r.String() + if b.r.Len() == 0 { + b.text = "" + } else { + b.text = b.r.String() + } b.lines = strings.Split(b.text, "\n") } @@ -79,7 +88,7 @@ func (b *Buffer) IsDirty() bool { // Insert a string into the rope func (b *Buffer) Insert(idx int, value string) { - b.r.Insert(idx, value) + b.r = b.r.Insert(idx, value) b.Update() } @@ -93,12 +102,15 @@ func (b *Buffer) Remove(start, end int) string { end = b.Len() } removed := b.text[start:end] - b.r.Remove(start, end) + // The rope implenentation I am using wants indicies starting at 1 instead of 0 + start++ + end++ + b.r = b.r.Delete(start, end-start) b.Update() return removed } // Len gives the length of the buffer func (b *Buffer) Len() int { - return b.r.len + return b.r.Len() } diff --git a/src/rope.go b/src/rope.go deleted file mode 100644 index 90fff63c..00000000 --- a/src/rope.go +++ /dev/null @@ -1,105 +0,0 @@ -package main - -import ( - "math" -) - -const ( - // RopeSplitLength is the threshold used to split a leaf node into two child nodes. - RopeSplitLength = 1000000000 - // RopeJoinLength is the threshold used to join two child nodes into one leaf node. - RopeJoinLength = 500 - // RopeRebalanceRatio = 1.2 -) - -// A Rope is a data structure for efficiently manipulating large strings -type Rope struct { - left *Rope - right *Rope - value string - valueNil bool - - len int -} - -// NewRope returns a new rope from a given string -func NewRope(str string) *Rope { - r := new(Rope) - r.value = str - r.valueNil = false - r.len = Count(r.value) - - r.Adjust() - - return r -} - -// Adjust modifies the rope so it is more balanced -func (r *Rope) Adjust() { - if !r.valueNil { - if r.len > RopeSplitLength { - divide := int(math.Floor(float64(r.len) / 2)) - runes := []rune(r.value) - r.left = NewRope(string(runes[:divide])) - r.right = NewRope(string(runes[divide:])) - r.valueNil = true - } - } else { - if r.len < RopeJoinLength { - r.value = r.left.String() + r.right.String() - r.valueNil = false - r.left = nil - r.right = nil - } - } -} - -// String returns the string representation of the rope -func (r *Rope) String() string { - if !r.valueNil { - return r.value - } - return r.left.String() + r.right.String() -} - -// Remove deletes a slice of the rope from start the to end (exclusive) -func (r *Rope) Remove(start, end int) { - if !r.valueNil { - r.value = string(append([]rune(r.value)[:start], []rune(r.value)[end:]...)) - r.valueNil = false - r.len = Count(r.value) - } else { - leftStart := Min(start, r.left.len) - leftEnd := Min(end, r.left.len) - rightStart := Max(0, Min(start-r.left.len, r.right.len)) - rightEnd := Max(0, Min(end-r.left.len, r.right.len)) - if leftStart < r.left.len { - r.left.Remove(leftStart, leftEnd) - } - if rightEnd > 0 { - r.right.Remove(rightStart, rightEnd) - } - r.len = r.left.len + r.right.len - } - - r.Adjust() -} - -// Insert inserts a string into the rope at a specified position -func (r *Rope) Insert(pos int, value string) { - if !r.valueNil { - first := append([]rune(r.value)[:pos], []rune(value)...) - r.value = string(append(first, []rune(r.value)[pos:]...)) - r.valueNil = false - r.len = Count(r.value) - } else { - if pos < r.left.len { - r.left.Insert(pos, value) - r.len = r.left.len + r.right.len - } else { - r.right.Insert(pos-r.left.len, value) - } - } - - r.Adjust() -} diff --git a/src/rope_test.go b/src/rope_test.go deleted file mode 100644 index 73fa1830..00000000 --- a/src/rope_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package main - -import "testing" - -func TestInsert(t *testing.T) { - var tests = []struct { - origStr string - insertStr string - insertPos int - want string - }{ - {"foo", " bar", 3, "foo bar"}, - {"üñîç", "ø∂é", 4, "üñîçø∂é"}, - {"test", "3", 2, "te3st"}, - {"", "test", 0, "test"}, - } - for _, test := range tests { - r := NewRope(test.origStr) - r.Insert(test.insertPos, test.insertStr) - got := r.String() - if got != test.want { - t.Errorf("Insert(%d, %s) = %s", test.insertPos, test.insertStr, got) - } - } -} - -func TestRemove(t *testing.T) { - var tests = []struct { - inputStr string - removeStart int - removeEnd int - want string - }{ - {"foo bar", 3, 7, "foo"}, - {"üñîçø∂é", 0, 3, "çø∂é"}, - {"test", 0, 4, ""}, - } - for _, test := range tests { - r := NewRope(test.inputStr) - r.Remove(test.removeStart, test.removeEnd) - got := r.String() - if got != test.want { - t.Errorf("Remove(%d, %d) = %s", test.removeStart, test.removeEnd, got) - } - } -}