package buffer
import (
+ "bytes"
"time"
"unicode/utf8"
dmp "github.com/sergi/go-diff/diffmatchpatch"
+ "github.com/zyedidia/micro/internal/config"
+ ulua "github.com/zyedidia/micro/internal/lua"
+ "github.com/zyedidia/micro/internal/screen"
+ luar "layeh.com/gopher-luar"
)
const (
// TextEventReplace represents a replace event
TextEventReplace = 0
- undoThreshold = 500 // If two events are less than n milliseconds apart, undo both of them
+ undoThreshold = 1000 // If two events are less than n milliseconds apart, undo both of them
)
// TextEvent holds data for a manipulation on some text that can be undone
// Insert creates an insert text event and executes it
func (eh *EventHandler) Insert(start Loc, textStr string) {
text := []byte(textStr)
+ eh.InsertBytes(start, text)
+}
+
+// InsertBytes creates an insert text event and executes it
+func (eh *EventHandler) InsertBytes(start Loc, text []byte) {
+ start = clamp(start, eh.buf.LineArray)
e := &TextEvent{
C: *eh.cursors[eh.active],
EventType: TextEventInsert,
Deltas: []Delta{{text, start, Loc{0, 0}}},
Time: time.Now(),
}
+ oldl := eh.buf.LinesNum()
eh.Execute(e)
- e.Deltas[0].End = start.MoveLA(utf8.RuneCount(text), eh.buf.LineArray)
+ 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 != end.Y && loc.GreaterThan(start) {
+ if start.Y != loc.Y && loc.GreaterThan(start) {
loc.Y += end.Y - start.Y
} else if loc.Y == start.Y && loc.GreaterEqual(start) {
- loc = loc.MoveLA(utf8.RuneCount(text), eh.buf.LineArray)
+ 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])
// Remove creates a remove text event and executes it
func (eh *EventHandler) Remove(start, end Loc) {
+ start = clamp(start, eh.buf.LineArray)
+ end = clamp(end, eh.buf.LineArray)
e := &TextEvent{
C: *eh.cursors[eh.active],
EventType: TextEventRemove,
for _, c := range eh.cursors {
move := func(loc Loc) Loc {
- if start.Y != end.Y && loc.GreaterThan(end) {
+ 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)
}
eh.UndoStack.Push(t)
- // TODO: Call plugins on text events
- // for pl := range loadedPlugins {
- // ret, err := Call(pl+".onBeforeTextEvent", t)
- // if err != nil && !strings.HasPrefix(err.Error(), "function does not exist") {
- // screen.TermMessage(err)
- // }
- // if val, ok := ret.(lua.LBool); ok && val == lua.LFalse {
- // return
- // }
- // }
+ b, err := config.RunPluginFnBool("onBeforeTextEvent", luar.New(ulua.L, eh.buf), luar.New(ulua.L, t))
+ if err != nil {
+ screen.TermMessage(err)
+ }
+
+ if !b {
+ return
+ }
ExecuteTextEvent(t, eh.buf)
}
}
startTime := t.Time.UnixNano() / int64(time.Millisecond)
-
- eh.UndoOneEvent()
+ endTime := startTime - (startTime % undoThreshold)
for {
t = eh.UndoStack.Peek()
return
}
- if startTime-(t.Time.UnixNano()/int64(time.Millisecond)) > undoThreshold {
+ if t.Time.UnixNano()/int64(time.Millisecond) < endTime {
return
}
- startTime = t.Time.UnixNano() / int64(time.Millisecond)
eh.UndoOneEvent()
}
}
startTime := t.Time.UnixNano() / int64(time.Millisecond)
-
- eh.RedoOneEvent()
+ endTime := startTime - (startTime % undoThreshold) + undoThreshold
for {
t = eh.RedoStack.Peek()
return
}
- if (t.Time.UnixNano()/int64(time.Millisecond))-startTime > undoThreshold {
+ if t.Time.UnixNano()/int64(time.Millisecond) > endTime {
return
}