-
Notifications
You must be signed in to change notification settings - Fork 0
/
action.go
112 lines (97 loc) · 2.36 KB
/
action.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package file
import (
"slices"
)
//----------------------------------------------------------------------------
// action
//
// A single entity of undo/redo history. All changes to contents of a buffer
// must be initiated by an action.
//----------------------------------------------------------------------------
type ActionClass int
const (
Insert ActionClass = iota
Delete
DeleteBackward
ActionSeparator
)
type Action struct {
Class ActionClass
Before Cursor
After Cursor
Data []rune
}
//----------------------------------------------------------------------------
// action group
//----------------------------------------------------------------------------
type ActionGroup []Action
/*
type ActionGroup1 struct {
actions []Action
prev *ActionGroup1
next *ActionGroup1
}
*/
func NewActionGroup() *ActionGroup {
var ag ActionGroup = make([]Action, 0, 32)
return &ag
}
func (ag *ActionGroup) Push(a Action) {
// If an action exists in action group and the action to add is
// the same as the last action (same class and cursor position),
// update the last action.
lastIndex := len(*ag) - 1
if lastIndex != -1 && // exists and same action?
(*ag)[lastIndex].Class == a.Class &&
(*ag)[lastIndex].After.Equals(a.Before) {
if a.Class == DeleteBackward {
slices.Reverse(a.Data) // Reverse
(*ag)[lastIndex].Data = append(a.Data, (*ag)[lastIndex].Data...)
(*ag)[lastIndex].After = a.After
} else { // Delete, Insert
(*ag)[lastIndex].Data = append((*ag)[lastIndex].Data, a.Data...)
(*ag)[lastIndex].After = a.After
}
return
}
// Add the new action
(*ag) = append((*ag), a)
}
// try before isUndoEmpty() method
func (ag *ActionGroup) Pop() (lastAction Action, _ bool) {
if ag.IsEmpty() {
return lastAction, false
}
lastIndex := len((*ag)) - 1
lastAction = (*ag)[lastIndex]
(*ag) = (*ag)[:lastIndex] // remove last action
return lastAction, true
}
func (ag *ActionGroup) IsEmpty() bool {
return len(*ag) == 0
}
// This bad function
// Move Undo ActionGroup to Redo
func (undo *ActionGroup) MoveTo(redo *ActionGroup) {
for {
u, ok := undo.Pop()
if !ok {
break
}
switch u.Class {
case Insert:
u.Class = DeleteBackward
a := u.After
u.After = u.Before
u.Before = a
case Delete:
u.Class = Insert
case DeleteBackward:
u.Class = Insert
a := u.After
u.After = u.Before
u.Before = a
}
redo.Push(u)
}
}