]> git.lizzy.rs Git - micro.git/blobdiff - cmd/micro/eventhandler.go
Use messenger error instead of termerror
[micro.git] / cmd / micro / eventhandler.go
index 2c0e6482e977e3afe94fba4ad8565881beb79d57..1a94813f266695cc8d072507de1bc7e33ccc5046 100644 (file)
@@ -1,7 +1,11 @@
 package main
 
 import (
+       "strings"
        "time"
+
+       dmp "github.com/sergi/go-diff/diffmatchpatch"
+       "github.com/yuin/gopher-lua"
 )
 
 const (
@@ -11,6 +15,8 @@ const (
        TextEventInsert = 1
        // TextEventRemove represents a deletion event
        TextEventRemove = -1
+
+       TextEventReplace = 0
 )
 
 // TextEvent holds data for a manipulation on some text that can be undone
@@ -18,18 +24,31 @@ type TextEvent struct {
        C Cursor
 
        EventType int
-       Text      string
-       Start     int
-       End       int
+       Deltas    []Delta
        Time      time.Time
 }
 
+type Delta struct {
+       Text  string
+       Start Loc
+       End   Loc
+}
+
 // ExecuteTextEvent runs a text event
 func ExecuteTextEvent(t *TextEvent, buf *Buffer) {
        if t.EventType == TextEventInsert {
-               buf.insert(t.Start, t.Text)
+               for _, d := range t.Deltas {
+                       buf.insert(d.Start, []byte(d.Text))
+               }
        } else if t.EventType == TextEventRemove {
-               t.Text = buf.remove(t.Start, t.End)
+               for i, d := range t.Deltas {
+                       t.Deltas[i].Text = buf.remove(d.Start, d.End)
+               }
+       } else if t.EventType == TextEventReplace {
+               for i, d := range t.Deltas {
+                       t.Deltas[i].Text = buf.remove(d.Start, d.End)
+                       buf.insert(d.Start, []byte(d.Text))
+               }
        }
 }
 
@@ -55,33 +74,62 @@ func NewEventHandler(buf *Buffer) *EventHandler {
        return eh
 }
 
+// ApplyDiff takes a string and runs the necessary insertion and deletion events to make
+// the buffer equal to that string
+// This means that we can transform the buffer into any string and still preserve undo/redo
+// through insert and delete events
+func (eh *EventHandler) ApplyDiff(new string) {
+       differ := dmp.New()
+       diff := differ.DiffMain(eh.buf.String(), new, false)
+       loc := eh.buf.Start()
+       for _, d := range diff {
+               if d.Type == dmp.DiffDelete {
+                       eh.Remove(loc, loc.Move(Count(d.Text), eh.buf))
+               } else {
+                       if d.Type == dmp.DiffInsert {
+                               eh.Insert(loc, d.Text)
+                       }
+                       loc = loc.Move(Count(d.Text), eh.buf)
+               }
+       }
+}
+
 // Insert creates an insert text event and executes it
-func (eh *EventHandler) Insert(start int, text string) {
+func (eh *EventHandler) Insert(start Loc, text string) {
        e := &TextEvent{
                C:         eh.buf.Cursor,
                EventType: TextEventInsert,
-               Text:      text,
-               Start:     start,
-               End:       start + Count(text),
+               Deltas:    []Delta{Delta{text, start, Loc{0, 0}}},
                Time:      time.Now(),
        }
        eh.Execute(e)
+       e.Deltas[0].End = start.Move(Count(text), eh.buf)
 }
 
 // Remove creates a remove text event and executes it
-func (eh *EventHandler) Remove(start, end int) {
+func (eh *EventHandler) Remove(start, end Loc) {
        e := &TextEvent{
                C:         eh.buf.Cursor,
                EventType: TextEventRemove,
-               Start:     start,
-               End:       end,
+               Deltas:    []Delta{Delta{"", start, end}},
+               Time:      time.Now(),
+       }
+       eh.Execute(e)
+}
+
+// Multiple creates an multiple insertions executes them
+func (eh *EventHandler) MultipleReplace(deltas []Delta) {
+       e := &TextEvent{
+               C:         eh.buf.Cursor,
+               EventType: TextEventReplace,
+               Deltas:    deltas,
                Time:      time.Now(),
        }
        eh.Execute(e)
 }
 
 // Replace deletes from start to end and replaces it with the given string
-func (eh *EventHandler) Replace(start, end int, replace string) {
+func (eh *EventHandler) Replace(start, end Loc, replace string) {
        eh.Remove(start, end)
        eh.Insert(start, replace)
 }
@@ -92,6 +140,17 @@ func (eh *EventHandler) Execute(t *TextEvent) {
                eh.RedoStack = new(Stack)
        }
        eh.UndoStack.Push(t)
+
+       for pl := range loadedPlugins {
+               ret, err := Call(pl+".onBeforeTextEvent", t)
+               if err != nil && !strings.HasPrefix(err.Error(), "function does not exist") {
+                       TermMessage(err)
+               }
+               if val, ok := ret.(lua.LBool); ok && val == lua.LFalse {
+                       return
+               }
+       }
+
        ExecuteTextEvent(t, eh.buf)
 }