mirror of
https://github.com/zyedidia/micro.git
synced 2025-06-19 07:15:34 -04:00
parent
f059541e0d
commit
53bda0cfa7
@ -47,17 +47,17 @@ func check(t *testing.T, before []string, operations []operation, after []string
|
|||||||
|
|
||||||
b := NewBufferFromString(strings.Join(before, "\n"), "", BTDefault)
|
b := NewBufferFromString(strings.Join(before, "\n"), "", BTDefault)
|
||||||
|
|
||||||
assert.NotEqual(b.GetName(), "")
|
assert.NotEqual("", b.GetName())
|
||||||
assert.Equal(b.ExternallyModified(), false)
|
assert.Equal(false, b.ExternallyModified())
|
||||||
assert.Equal(b.Modified(), false)
|
assert.Equal(false, b.Modified())
|
||||||
assert.Equal(b.NumCursors(), 1)
|
assert.Equal(1, b.NumCursors())
|
||||||
|
|
||||||
checkText := func(lines []string) {
|
checkText := func(lines []string) {
|
||||||
assert.Equal(b.Bytes(), []byte(strings.Join(lines, "\n")))
|
assert.Equal([]byte(strings.Join(lines, "\n")), b.Bytes())
|
||||||
assert.Equal(b.LinesNum(), len(lines))
|
assert.Equal(len(lines), b.LinesNum())
|
||||||
for i, s := range lines {
|
for i, s := range lines {
|
||||||
assert.Equal(b.Line(i), s)
|
assert.Equal(s, b.Line(i))
|
||||||
assert.Equal(b.LineBytes(i), []byte(s))
|
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)
|
cursors = append(cursors, cursor)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(b.NumCursors(), 1+len(operations))
|
assert.Equal(1+len(operations), b.NumCursors())
|
||||||
|
|
||||||
for i, op := range operations {
|
for i, op := range operations {
|
||||||
cursor := cursors[i]
|
cursor := cursors[i]
|
||||||
|
b.SetCurCursor(cursor.Num)
|
||||||
cursor.DeleteSelection()
|
cursor.DeleteSelection()
|
||||||
|
cursor.ResetSelection()
|
||||||
b.Insert(cursor.Loc, strings.Join(op.text, "\n"))
|
b.Insert(cursor.Loc, strings.Join(op.text, "\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
checkText(after)
|
checkText(after)
|
||||||
|
|
||||||
for _ = range operations {
|
for b.UndoStack.Peek() != nil {
|
||||||
b.UndoOneEvent()
|
|
||||||
b.UndoOneEvent()
|
b.UndoOneEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,13 +93,15 @@ func check(t *testing.T, before []string, operations []operation, after []string
|
|||||||
|
|
||||||
for i, op := range operations {
|
for i, op := range operations {
|
||||||
cursor := cursors[i]
|
cursor := cursors[i]
|
||||||
assert.Equal(cursor.Loc, op.start)
|
if !cursor.HasSelection() {
|
||||||
assert.Equal(cursor.CurSelection[0], op.start)
|
assert.Equal(op.start, cursor.Loc)
|
||||||
assert.Equal(cursor.CurSelection[1], op.end)
|
} else {
|
||||||
|
assert.Equal(op.start, cursor.CurSelection[0])
|
||||||
|
assert.Equal(op.end, cursor.CurSelection[1])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _ = range operations {
|
for b.RedoStack.Peek() != nil {
|
||||||
b.RedoOneEvent()
|
|
||||||
b.RedoOneEvent()
|
b.RedoOneEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +41,73 @@ type Delta struct {
|
|||||||
End Loc
|
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
|
// ExecuteTextEvent runs a text event
|
||||||
func ExecuteTextEvent(t *TextEvent, buf *SharedBuffer) {
|
func ExecuteTextEvent(t *TextEvent, buf *SharedBuffer) {
|
||||||
if t.EventType == TextEventInsert {
|
if t.EventType == TextEventInsert {
|
||||||
@ -65,9 +132,9 @@ func ExecuteTextEvent(t *TextEvent, buf *SharedBuffer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UndoTextEvent undoes a text event
|
// UndoTextEvent undoes a text event
|
||||||
func UndoTextEvent(t *TextEvent, buf *SharedBuffer) {
|
func (eh *EventHandler) UndoTextEvent(t *TextEvent) {
|
||||||
t.EventType = -t.EventType
|
t.EventType = -t.EventType
|
||||||
ExecuteTextEvent(t, buf)
|
eh.DoTextEvent(t, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EventHandler executes text manipulations and allows undoing and redoing
|
// 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
|
// InsertBytes creates an insert text event and executes it
|
||||||
func (eh *EventHandler) InsertBytes(start Loc, text []byte) {
|
func (eh *EventHandler) InsertBytes(start Loc, text []byte) {
|
||||||
|
if len(text) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
start = clamp(start, eh.buf.LineArray)
|
start = clamp(start, eh.buf.LineArray)
|
||||||
e := &TextEvent{
|
e := &TextEvent{
|
||||||
C: *eh.cursors[eh.active],
|
C: *eh.cursors[eh.active],
|
||||||
@ -124,50 +194,14 @@ func (eh *EventHandler) InsertBytes(start Loc, text []byte) {
|
|||||||
Deltas: []Delta{{text, start, Loc{0, 0}}},
|
Deltas: []Delta{{text, start, Loc{0, 0}}},
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
}
|
}
|
||||||
oldl := eh.buf.LinesNum()
|
eh.DoTextEvent(e, true)
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove creates a remove text event and executes it
|
// Remove creates a remove text event and executes it
|
||||||
func (eh *EventHandler) Remove(start, end Loc) {
|
func (eh *EventHandler) Remove(start, end Loc) {
|
||||||
|
if start == end {
|
||||||
|
return
|
||||||
|
}
|
||||||
start = clamp(start, eh.buf.LineArray)
|
start = clamp(start, eh.buf.LineArray)
|
||||||
end = clamp(end, eh.buf.LineArray)
|
end = clamp(end, eh.buf.LineArray)
|
||||||
e := &TextEvent{
|
e := &TextEvent{
|
||||||
@ -176,24 +210,7 @@ func (eh *EventHandler) Remove(start, end Loc) {
|
|||||||
Deltas: []Delta{{[]byte{}, start, end}},
|
Deltas: []Delta{{[]byte{}, start, end}},
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
}
|
}
|
||||||
eh.Execute(e)
|
eh.DoTextEvent(e, true)
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MultipleReplace creates an multiple insertions executes them
|
// MultipleReplace creates an multiple insertions executes them
|
||||||
@ -253,6 +270,7 @@ func (eh *EventHandler) Undo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
eh.UndoOneEvent()
|
eh.UndoOneEvent()
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,10 +282,9 @@ func (eh *EventHandler) UndoOneEvent() {
|
|||||||
if t == nil {
|
if t == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Undo it
|
// Undo it
|
||||||
// Modifies the text event
|
// Modifies the text event
|
||||||
UndoTextEvent(t, eh.buf)
|
eh.UndoTextEvent(t)
|
||||||
|
|
||||||
// Set the cursor in the right place
|
// Set the cursor in the right place
|
||||||
teCursor := t.C
|
teCursor := t.C
|
||||||
@ -303,6 +320,7 @@ func (eh *EventHandler) Redo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
eh.RedoOneEvent()
|
eh.RedoOneEvent()
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,9 +331,6 @@ func (eh *EventHandler) RedoOneEvent() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modifies the text event
|
|
||||||
UndoTextEvent(t, eh.buf)
|
|
||||||
|
|
||||||
teCursor := t.C
|
teCursor := t.C
|
||||||
if teCursor.Num >= 0 && teCursor.Num < len(eh.cursors) {
|
if teCursor.Num >= 0 && teCursor.Num < len(eh.cursors) {
|
||||||
t.C = *eh.cursors[teCursor.Num]
|
t.C = *eh.cursors[teCursor.Num]
|
||||||
@ -324,5 +339,8 @@ func (eh *EventHandler) RedoOneEvent() {
|
|||||||
teCursor.Num = -1
|
teCursor.Num = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Modifies the text event
|
||||||
|
eh.UndoTextEvent(t)
|
||||||
|
|
||||||
eh.UndoStack.Push(t)
|
eh.UndoStack.Push(t)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user