forked from reeflective/readline
-
Notifications
You must be signed in to change notification settings - Fork 0
/
undo.go
104 lines (82 loc) · 1.95 KB
/
undo.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
package readline
type undoItem struct {
line string
pos int
}
// will only skip appending to undo history if not forced
// to append by another pending/running widget.
func (rl *Instance) skipUndoAppend() {
rl.undoSkipAppend = true
}
func (rl *Instance) undoHistoryAppend() {
defer rl.resetUndoDirectives()
if rl.undoSkipAppend {
return
}
// When the line is identical to the previous undo, we skip it.
if len(rl.undoHistory) > 0 {
if rl.undoHistory[len(rl.undoHistory)-1].line == string(rl.line) {
return
}
}
// When we add an item to the undo history, the history
// is cut from the current undo hist position onwards.
rl.undoHistory = rl.undoHistory[:len(rl.undoHistory)-rl.undoPos]
rl.undoHistory = append(rl.undoHistory, undoItem{
line: string(rl.line),
pos: rl.pos,
})
}
func (rl *Instance) undo() {
rl.undoSkipAppend = true
rl.isUndoing = true
if len(rl.undoHistory) == 0 {
return
}
if rl.undoPos == 0 {
rl.lineBuf = string(rl.line)
}
var undo undoItem
// When undoing, we loop through preceding undo items
// as long as they are identical to the current line.
for {
rl.undoPos++
// Exit if we reached the end.
if rl.undoPos > len(rl.undoHistory) {
rl.undoPos = len(rl.undoHistory)
return
}
// Break as soon as we find a non-matching line.
undo = rl.undoHistory[len(rl.undoHistory)-rl.undoPos]
if undo.line != string(rl.line) {
break
}
}
// Use the undo we found
rl.line = []rune(undo.line)
rl.pos = undo.pos
}
func (rl *Instance) redo() {
rl.undoSkipAppend = true
rl.isUndoing = true
if len(rl.undoHistory) == 0 {
return
}
rl.undoPos--
if rl.undoPos < 1 {
rl.undoPos = 0
rl.line = []rune(rl.lineBuf)
rl.pos = len(rl.lineBuf)
return
}
undo := rl.undoHistory[len(rl.undoHistory)-rl.undoPos]
rl.line = []rune(undo.line)
rl.pos = undo.pos
}
func (rl *Instance) resetUndoDirectives() {
rl.undoSkipAppend = false
if !rl.isUndoing {
rl.undoPos = 0
}
rl.isUndoing = false
}