]> git.lizzy.rs Git - micro.git/blob - cmd/micro/eventhandler.go
make undothresthold a setting (part 2)
[micro.git] / cmd / micro / eventhandler.go
1 package main
2
3 import (
4         "time"
5 )
6
7 const (
8         // Opposite and undoing events must have opposite values
9
10         // TextEventInsert repreasents an insertion event
11         TextEventInsert = 1
12         // TextEventRemove represents a deletion event
13         TextEventRemove = -1
14 )
15
16 // TextEvent holds data for a manipulation on some text that can be undone
17 type TextEvent struct {
18         c Cursor
19
20         eventType int
21         text      string
22         start     int
23         end       int
24         time      time.Time
25 }
26
27 // ExecuteTextEvent runs a text event
28 func ExecuteTextEvent(t *TextEvent, buf *Buffer) {
29         if t.eventType == TextEventInsert {
30                 buf.insert(t.start, t.text)
31         } else if t.eventType == TextEventRemove {
32                 t.text = buf.remove(t.start, t.end)
33         }
34 }
35
36 // UndoTextEvent undoes a text event
37 func UndoTextEvent(t *TextEvent, buf *Buffer) {
38         t.eventType = -t.eventType
39         ExecuteTextEvent(t, buf)
40 }
41
42 // EventHandler executes text manipulations and allows undoing and redoing
43 type EventHandler struct {
44         buf  *Buffer
45         undo *Stack
46         redo *Stack
47 }
48
49 // NewEventHandler returns a new EventHandler
50 func NewEventHandler(buf *Buffer) *EventHandler {
51         eh := new(EventHandler)
52         eh.undo = new(Stack)
53         eh.redo = new(Stack)
54         eh.buf = buf
55         return eh
56 }
57
58 // Insert creates an insert text event and executes it
59 func (eh *EventHandler) Insert(start int, text string) {
60         e := &TextEvent{
61                 c:         eh.buf.Cursor,
62                 eventType: TextEventInsert,
63                 text:      text,
64                 start:     start,
65                 end:       start + Count(text),
66                 time:      time.Now(),
67         }
68         eh.Execute(e)
69 }
70
71 // Remove creates a remove text event and executes it
72 func (eh *EventHandler) Remove(start, end int) {
73         e := &TextEvent{
74                 c:         eh.buf.Cursor,
75                 eventType: TextEventRemove,
76                 start:     start,
77                 end:       end,
78                 time:      time.Now(),
79         }
80         eh.Execute(e)
81 }
82
83 // Replace deletes from start to end and replaces it with the given string
84 func (eh *EventHandler) Replace(start, end int, replace string) {
85         eh.Remove(start, end)
86         eh.Insert(start, replace)
87 }
88
89 // Execute a textevent and add it to the undo stack
90 func (eh *EventHandler) Execute(t *TextEvent) {
91         if eh.redo.Len() > 0 {
92                 eh.redo = new(Stack)
93         }
94         eh.undo.Push(t)
95         ExecuteTextEvent(t, eh.buf)
96 }
97
98 // Undo the first event in the undo stack
99 func (eh *EventHandler) Undo() {
100         t := eh.undo.Peek()
101         if t == nil {
102                 return
103         }
104
105         te := t.(*TextEvent)
106         startTime := t.(*TextEvent).time.UnixNano() / int64(time.Millisecond)
107
108         eh.UndoOneEvent()
109
110         for {
111                 t = eh.undo.Peek()
112                 if t == nil {
113                         return
114                 }
115
116                 te = t.(*TextEvent)
117
118                 undoThreshold := int64(settings["undothreshold"].(float64))
119                 if startTime-(te.time.UnixNano()/int64(time.Millisecond)) > undoThreshold {
120                         return
121                 }
122
123                 eh.UndoOneEvent()
124         }
125 }
126
127 // UndoOneEvent undoes one event
128 func (eh *EventHandler) UndoOneEvent() {
129         // This event should be undone
130         // Pop it off the stack
131         t := eh.undo.Pop()
132         if t == nil {
133                 return
134         }
135
136         te := t.(*TextEvent)
137         // Undo it
138         // Modifies the text event
139         UndoTextEvent(te, eh.buf)
140
141         // Set the cursor in the right place
142         teCursor := te.c
143         te.c = eh.buf.Cursor
144         eh.buf.Cursor = teCursor
145
146         // Push it to the redo stack
147         eh.redo.Push(te)
148 }
149
150 // Redo the first event in the redo stack
151 func (eh *EventHandler) Redo() {
152         t := eh.redo.Peek()
153         if t == nil {
154                 return
155         }
156
157         te := t.(*TextEvent)
158         startTime := t.(*TextEvent).time.UnixNano() / int64(time.Millisecond)
159
160         eh.RedoOneEvent()
161
162         for {
163                 t = eh.redo.Peek()
164                 if t == nil {
165                         return
166                 }
167
168                 te = t.(*TextEvent)
169
170                 undoThreshold := int64(settings["undothreshold"].(float64))
171                 if (te.time.UnixNano()/int64(time.Millisecond))-startTime > undoThreshold {
172                         return
173                 }
174
175                 eh.RedoOneEvent()
176         }
177 }
178
179 // RedoOneEvent redoes one event
180 func (eh *EventHandler) RedoOneEvent() {
181         t := eh.redo.Pop()
182         if t == nil {
183                 return
184         }
185
186         te := t.(*TextEvent)
187         // Modifies the text event
188         UndoTextEvent(te, eh.buf)
189
190         teCursor := te.c
191         te.c = eh.buf.Cursor
192         eh.buf.Cursor = teCursor
193
194         eh.undo.Push(te)
195 }