]> git.lizzy.rs Git - micro.git/blobdiff - internal/buffer/eventhandler.go
fix eofnewline not running on files with 1 rune (#1535)
[micro.git] / internal / buffer / eventhandler.go
index eeb7b8129023f60f55f5eeb7f842e95411fec523..4e4243a07953488adcf8310ec1104964e1752c3f 100644 (file)
@@ -1,10 +1,15 @@
 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 (
@@ -17,7 +22,7 @@ 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
@@ -107,26 +112,52 @@ func (eh *EventHandler) ApplyDiff(new string) {
 // 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])
@@ -137,6 +168,8 @@ func (eh *EventHandler) Insert(start Loc, textStr string) {
 
 // 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,
@@ -147,7 +180,7 @@ func (eh *EventHandler) Remove(start, end Loc) {
 
        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)
@@ -187,16 +220,14 @@ func (eh *EventHandler) Execute(t *TextEvent) {
        }
        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)
 }
@@ -209,8 +240,7 @@ func (eh *EventHandler) Undo() {
        }
 
        startTime := t.Time.UnixNano() / int64(time.Millisecond)
-
-       eh.UndoOneEvent()
+       endTime := startTime - (startTime % undoThreshold)
 
        for {
                t = eh.UndoStack.Peek()
@@ -218,10 +248,9 @@ func (eh *EventHandler) Undo() {
                        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()
        }
@@ -261,8 +290,7 @@ func (eh *EventHandler) Redo() {
        }
 
        startTime := t.Time.UnixNano() / int64(time.Millisecond)
-
-       eh.RedoOneEvent()
+       endTime := startTime - (startTime % undoThreshold) + undoThreshold
 
        for {
                t = eh.RedoStack.Peek()
@@ -270,7 +298,7 @@ func (eh *EventHandler) Redo() {
                        return
                }
 
-               if (t.Time.UnixNano()/int64(time.Millisecond))-startTime > undoThreshold {
+               if t.Time.UnixNano()/int64(time.Millisecond) > endTime {
                        return
                }