diff --git a/src/eventhandler.go b/src/eventhandler.go index 4616e2b7..b563151d 100644 --- a/src/eventhandler.go +++ b/src/eventhandler.go @@ -94,24 +94,85 @@ func (eh *EventHandler) Execute(t *TextEvent) { // Undo the first event in the undo stack func (eh *EventHandler) Undo() { + t := eh.undo.Peek() + if t == nil { + return + } + + te := t.(*TextEvent) + startTime := t.(*TextEvent).time.UnixNano() / int64(time.Millisecond) + + eh.UndoOneEvent() + + for { + t = eh.undo.Peek() + if t == nil { + return + } + + te = t.(*TextEvent) + + if startTime-(te.time.UnixNano()/int64(time.Millisecond)) > undoThreshold { + return + } + + eh.UndoOneEvent() + } +} + +// UndoOneEvent undoes one event +func (eh *EventHandler) UndoOneEvent() { + // This event should be undone + // Pop it off the stack t := eh.undo.Pop() if t == nil { return } te := t.(*TextEvent) + // Undo it // Modifies the text event UndoTextEvent(te) + // Set the cursor in the right place teCursor := te.c te.c = eh.v.cursor eh.v.cursor = teCursor + // Push it to the redo stack eh.redo.Push(te) } // Redo the first event in the redo stack func (eh *EventHandler) Redo() { + t := eh.redo.Peek() + if t == nil { + return + } + + te := t.(*TextEvent) + startTime := t.(*TextEvent).time.UnixNano() / int64(time.Millisecond) + + eh.RedoOneEvent() + + for { + t = eh.redo.Peek() + if t == nil { + return + } + + te = t.(*TextEvent) + + if (te.time.UnixNano()/int64(time.Millisecond))-startTime > undoThreshold { + return + } + + eh.RedoOneEvent() + } +} + +// RedoOneEvent redoes one event +func (eh *EventHandler) RedoOneEvent() { t := eh.redo.Pop() if t == nil { return diff --git a/src/micro.go b/src/micro.go index 8f155fd6..47828d8c 100644 --- a/src/micro.go +++ b/src/micro.go @@ -13,6 +13,7 @@ const ( synLinesUp = 75 // How many lines up to look to do syntax highlighting synLinesDown = 75 // How many lines down to look to do syntax highlighting doubleClickThreshold = 400 // How many milliseconds to wait before a second click is not a double click + undoThreshold = 500 // If two events are less than n milliseconds apart, undo both of them ) // The main screen diff --git a/src/stack.go b/src/stack.go index b3200e1a..c7c8fd78 100644 --- a/src/stack.go +++ b/src/stack.go @@ -33,3 +33,11 @@ func (s *Stack) Pop() (value interface{}) { } return nil } + +// Peek returns the top element of the stack without removing it +func (s *Stack) Peek() interface{} { + if s.size > 0 { + return s.top.value + } + return nil +}