Fix buffer tests and selection bug

Fixes #1528
Ref #1526
This commit is contained in:
Zachary Yedidia 2020-02-25 20:24:02 -05:00
parent f059541e0d
commit 53bda0cfa7
2 changed files with 102 additions and 81 deletions

View File

@ -47,17 +47,17 @@ func check(t *testing.T, before []string, operations []operation, after []string
b := NewBufferFromString(strings.Join(before, "\n"), "", BTDefault)
assert.NotEqual(b.GetName(), "")
assert.Equal(b.ExternallyModified(), false)
assert.Equal(b.Modified(), false)
assert.Equal(b.NumCursors(), 1)
assert.NotEqual("", b.GetName())
assert.Equal(false, b.ExternallyModified())
assert.Equal(false, b.Modified())
assert.Equal(1, b.NumCursors())
checkText := func(lines []string) {
assert.Equal(b.Bytes(), []byte(strings.Join(lines, "\n")))
assert.Equal(b.LinesNum(), len(lines))
assert.Equal([]byte(strings.Join(lines, "\n")), b.Bytes())
assert.Equal(len(lines), b.LinesNum())
for i, s := range lines {
assert.Equal(b.Line(i), s)
assert.Equal(b.LineBytes(i), []byte(s))
assert.Equal(s, b.Line(i))
assert.Equal([]byte(s), b.LineBytes(i))
}
}
@ -73,18 +73,19 @@ func check(t *testing.T, before []string, operations []operation, after []string
cursors = append(cursors, cursor)
}
assert.Equal(b.NumCursors(), 1+len(operations))
assert.Equal(1+len(operations), b.NumCursors())
for i, op := range operations {
cursor := cursors[i]
b.SetCurCursor(cursor.Num)
cursor.DeleteSelection()
cursor.ResetSelection()
b.Insert(cursor.Loc, strings.Join(op.text, "\n"))
}
checkText(after)
for _ = range operations {
b.UndoOneEvent()
for b.UndoStack.Peek() != nil {
b.UndoOneEvent()
}
@ -92,13 +93,15 @@ func check(t *testing.T, before []string, operations []operation, after []string
for i, op := range operations {
cursor := cursors[i]
assert.Equal(cursor.Loc, op.start)
assert.Equal(cursor.CurSelection[0], op.start)
assert.Equal(cursor.CurSelection[1], op.end)
if !cursor.HasSelection() {
assert.Equal(op.start, cursor.Loc)
} else {
assert.Equal(op.start, cursor.CurSelection[0])
assert.Equal(op.end, cursor.CurSelection[1])
}
}
for _ = range operations {
b.RedoOneEvent()
for b.RedoStack.Peek() != nil {
b.RedoOneEvent()
}

View File

@ -41,6 +41,73 @@ type Delta struct {
End Loc
}
// DoTextEvent runs a text event
func (eh *EventHandler) DoTextEvent(t *TextEvent, useUndo bool) {
oldl := eh.buf.LinesNum()
if useUndo {
eh.Execute(t)
} else {
ExecuteTextEvent(t, eh.buf)
}
if len(t.Deltas) != 1 {
return
}
text := t.Deltas[0].Text
start := t.Deltas[0].Start
lastnl := -1
var endX int
var textX int
if t.EventType == TextEventInsert {
linecount := eh.buf.LinesNum() - oldl
textcount := utf8.RuneCount(text)
lastnl = bytes.LastIndex(text, []byte{'\n'})
if lastnl >= 0 {
endX = utf8.RuneCount(text[lastnl+1:])
textX = endX
} else {
endX = start.X + textcount
textX = textcount
}
t.Deltas[0].End = clamp(Loc{endX, start.Y + linecount}, eh.buf.LineArray)
}
end := t.Deltas[0].End
for _, c := range eh.cursors {
move := func(loc Loc) Loc {
if t.EventType == TextEventInsert {
if start.Y != loc.Y && loc.GreaterThan(start) {
loc.Y += end.Y - start.Y
} else if loc.Y == start.Y && loc.GreaterEqual(start) {
loc.Y += end.Y - start.Y
if lastnl >= 0 {
loc.X += textX - start.X
} else {
loc.X += textX
}
}
return loc
} else {
if loc.Y != end.Y && loc.GreaterThan(end) {
loc.Y -= end.Y - start.Y
} else if loc.Y == end.Y && loc.GreaterEqual(end) {
loc = loc.MoveLA(-DiffLA(start, end, eh.buf.LineArray), eh.buf.LineArray)
}
return loc
}
}
c.Loc = move(c.Loc)
c.CurSelection[0] = move(c.CurSelection[0])
c.CurSelection[1] = move(c.CurSelection[1])
c.OrigSelection[0] = move(c.OrigSelection[0])
c.OrigSelection[1] = move(c.OrigSelection[1])
c.Relocate()
c.LastVisualX = c.GetVisualX()
}
}
// ExecuteTextEvent runs a text event
func ExecuteTextEvent(t *TextEvent, buf *SharedBuffer) {
if t.EventType == TextEventInsert {
@ -65,9 +132,9 @@ func ExecuteTextEvent(t *TextEvent, buf *SharedBuffer) {
}
// UndoTextEvent undoes a text event
func UndoTextEvent(t *TextEvent, buf *SharedBuffer) {
func (eh *EventHandler) UndoTextEvent(t *TextEvent) {
t.EventType = -t.EventType
ExecuteTextEvent(t, buf)
eh.DoTextEvent(t, false)
}
// EventHandler executes text manipulations and allows undoing and redoing
@ -117,6 +184,9 @@ func (eh *EventHandler) Insert(start Loc, textStr string) {
// InsertBytes creates an insert text event and executes it
func (eh *EventHandler) InsertBytes(start Loc, text []byte) {
if len(text) == 0 {
return
}
start = clamp(start, eh.buf.LineArray)
e := &TextEvent{
C: *eh.cursors[eh.active],
@ -124,50 +194,14 @@ func (eh *EventHandler) InsertBytes(start Loc, text []byte) {
Deltas: []Delta{{text, start, Loc{0, 0}}},
Time: time.Now(),
}
oldl := eh.buf.LinesNum()
eh.Execute(e)
linecount := eh.buf.LinesNum() - oldl
textcount := utf8.RuneCount(text)
lastnl := bytes.LastIndex(text, []byte{'\n'})
var endX int
var textX int
if lastnl >= 0 {
endX = utf8.RuneCount(text[lastnl+1:])
textX = endX
} else {
endX = start.X + textcount
textX = textcount
}
e.Deltas[0].End = clamp(Loc{endX, start.Y + linecount}, eh.buf.LineArray)
end := e.Deltas[0].End
for _, c := range eh.cursors {
move := func(loc Loc) Loc {
if start.Y != loc.Y && loc.GreaterThan(start) {
loc.Y += end.Y - start.Y
} else if loc.Y == start.Y && loc.GreaterEqual(start) {
loc.Y += end.Y - start.Y
if lastnl >= 0 {
loc.X += textX - start.X
} else {
loc.X += textX
}
}
return loc
}
c.Loc = move(c.Loc)
c.Relocate()
c.CurSelection[0] = move(c.CurSelection[0])
c.CurSelection[1] = move(c.CurSelection[1])
c.OrigSelection[0] = move(c.OrigSelection[0])
c.OrigSelection[1] = move(c.OrigSelection[1])
c.LastVisualX = c.GetVisualX()
}
eh.DoTextEvent(e, true)
}
// Remove creates a remove text event and executes it
func (eh *EventHandler) Remove(start, end Loc) {
if start == end {
return
}
start = clamp(start, eh.buf.LineArray)
end = clamp(end, eh.buf.LineArray)
e := &TextEvent{
@ -176,24 +210,7 @@ func (eh *EventHandler) Remove(start, end Loc) {
Deltas: []Delta{{[]byte{}, start, end}},
Time: time.Now(),
}
eh.Execute(e)
for _, c := range eh.cursors {
move := func(loc Loc) Loc {
if loc.Y != end.Y && loc.GreaterThan(end) {
loc.Y -= end.Y - start.Y
} else if loc.Y == end.Y && loc.GreaterEqual(end) {
loc = loc.MoveLA(-DiffLA(start, end, eh.buf.LineArray), eh.buf.LineArray)
}
return loc
}
c.Loc = move(c.Loc)
c.CurSelection[0] = move(c.CurSelection[0])
c.CurSelection[1] = move(c.CurSelection[1])
c.OrigSelection[0] = move(c.OrigSelection[0])
c.OrigSelection[1] = move(c.OrigSelection[1])
c.LastVisualX = c.GetVisualX()
}
eh.DoTextEvent(e, true)
}
// MultipleReplace creates an multiple insertions executes them
@ -253,6 +270,7 @@ func (eh *EventHandler) Undo() {
}
eh.UndoOneEvent()
break
}
}
@ -264,10 +282,9 @@ func (eh *EventHandler) UndoOneEvent() {
if t == nil {
return
}
// Undo it
// Modifies the text event
UndoTextEvent(t, eh.buf)
eh.UndoTextEvent(t)
// Set the cursor in the right place
teCursor := t.C
@ -303,6 +320,7 @@ func (eh *EventHandler) Redo() {
}
eh.RedoOneEvent()
break
}
}
@ -313,9 +331,6 @@ func (eh *EventHandler) RedoOneEvent() {
return
}
// Modifies the text event
UndoTextEvent(t, eh.buf)
teCursor := t.C
if teCursor.Num >= 0 && teCursor.Num < len(eh.cursors) {
t.C = *eh.cursors[teCursor.Num]
@ -324,5 +339,8 @@ func (eh *EventHandler) RedoOneEvent() {
teCursor.Num = -1
}
// Modifies the text event
eh.UndoTextEvent(t)
eh.UndoStack.Push(t)
}