@quenty/undostack 1.14.0 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/package.json +7 -4
- package/src/Shared/UndoStack.lua +56 -5
- package/src/Shared/UndoStackEntry.lua +61 -6
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [1.15.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/undostack@1.14.0...@quenty/undostack@1.15.0) (2023-06-17)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* UndoStackEntry has a maid and can be removed from the stack ([d40668e](https://github.com/Quenty/NevermoreEngine/commit/d40668e07dbd00fc9b816eb7070a1d90219f8e95))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
# [1.14.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/undostack@1.13.0...@quenty/undostack@1.14.0) (2023-05-26)
|
|
7
18
|
|
|
8
19
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/undostack",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.0",
|
|
4
4
|
"description": "Generalized undo stack for Roblox",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -26,12 +26,15 @@
|
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@quenty/baseobject": "^6.2.1",
|
|
29
|
-
"@quenty/instanceutils": "^7.
|
|
29
|
+
"@quenty/instanceutils": "^7.15.0",
|
|
30
30
|
"@quenty/loader": "^6.2.1",
|
|
31
|
-
"@quenty/
|
|
31
|
+
"@quenty/maid": "^2.5.0",
|
|
32
|
+
"@quenty/promise": "^6.6.0",
|
|
33
|
+
"@quenty/signal": "^2.4.0",
|
|
34
|
+
"@quenty/valueobject": "^7.16.0"
|
|
32
35
|
},
|
|
33
36
|
"publishConfig": {
|
|
34
37
|
"access": "public"
|
|
35
38
|
},
|
|
36
|
-
"gitHead": "
|
|
39
|
+
"gitHead": "dc77d6de09e9eb9d3fd6dafd790c052d8393d38f"
|
|
37
40
|
}
|
package/src/Shared/UndoStack.lua
CHANGED
|
@@ -8,6 +8,7 @@ local BaseObject = require("BaseObject")
|
|
|
8
8
|
local Promise = require("Promise")
|
|
9
9
|
local UndoStackEntry = require("UndoStackEntry")
|
|
10
10
|
local ValueObject = require("ValueObject")
|
|
11
|
+
local Maid = require("Maid")
|
|
11
12
|
|
|
12
13
|
local DEFAULT_MAX_SIZE = 25
|
|
13
14
|
|
|
@@ -43,7 +44,7 @@ end
|
|
|
43
44
|
@return boolean
|
|
44
45
|
]=]
|
|
45
46
|
function UndoStack:ClearRedoStack()
|
|
46
|
-
self._redoStack ={}
|
|
47
|
+
self._redoStack = {}
|
|
47
48
|
self:_updateHasRedoEntries()
|
|
48
49
|
end
|
|
49
50
|
|
|
@@ -108,6 +109,23 @@ end
|
|
|
108
109
|
function UndoStack:Push(undoStackEntry)
|
|
109
110
|
assert(UndoStackEntry.isUndoStackEntry(undoStackEntry), "Bad undoStackEntry")
|
|
110
111
|
|
|
112
|
+
if self._maid[undoStackEntry] then
|
|
113
|
+
return function()
|
|
114
|
+
self:Remove(undoStackEntry)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
local maid = Maid.new()
|
|
119
|
+
maid:GiveTask(undoStackEntry)
|
|
120
|
+
|
|
121
|
+
maid:GiveTask(undoStackEntry.Destroying:Connect(function()
|
|
122
|
+
if undoStackEntry.Destroy then
|
|
123
|
+
self:Remove(undoStackEntry)
|
|
124
|
+
end
|
|
125
|
+
end))
|
|
126
|
+
|
|
127
|
+
self._maid[undoStackEntry] = maid
|
|
128
|
+
|
|
111
129
|
table.insert(self._undoStack, undoStackEntry)
|
|
112
130
|
while #self._undoStack > self._maxSize do
|
|
113
131
|
table.remove(self._undoStack, 1)
|
|
@@ -132,18 +150,25 @@ end
|
|
|
132
150
|
function UndoStack:Remove(undoStackEntry)
|
|
133
151
|
assert(UndoStackEntry.isUndoStackEntry(undoStackEntry), "Bad undoStackEntry")
|
|
134
152
|
|
|
153
|
+
self._maid[undoStackEntry] = nil
|
|
154
|
+
|
|
155
|
+
local changed = false
|
|
135
156
|
local undoIndex = table.find(self._undoStack, undoStackEntry)
|
|
136
157
|
if undoIndex then
|
|
137
158
|
table.remove(self._undoStack, undoIndex)
|
|
159
|
+
changed = true
|
|
138
160
|
end
|
|
139
161
|
|
|
140
162
|
local redoIndex = table.find(self._redoStack, undoStackEntry)
|
|
141
163
|
if redoIndex then
|
|
142
164
|
table.remove(self._redoStack, redoIndex)
|
|
165
|
+
changed = true
|
|
143
166
|
end
|
|
144
167
|
|
|
145
|
-
|
|
146
|
-
|
|
168
|
+
if changed then
|
|
169
|
+
self:_updateHasUndoEntries()
|
|
170
|
+
self:_updateHasRedoEntries()
|
|
171
|
+
end
|
|
147
172
|
end
|
|
148
173
|
|
|
149
174
|
--[=[
|
|
@@ -160,7 +185,9 @@ function UndoStack:PromiseUndo()
|
|
|
160
185
|
|
|
161
186
|
self:_updateHasUndoEntries()
|
|
162
187
|
|
|
163
|
-
return
|
|
188
|
+
return self:_executePromiseWithMaid(function(maid)
|
|
189
|
+
return undoStackEntry:PromiseUndo(maid)
|
|
190
|
+
end)
|
|
164
191
|
:Then(function()
|
|
165
192
|
if undoStackEntry:HasRedo() then
|
|
166
193
|
table.insert(self._redoStack, undoStackEntry)
|
|
@@ -186,7 +213,9 @@ function UndoStack:PromiseRedo()
|
|
|
186
213
|
|
|
187
214
|
self:_updateHasRedoEntries()
|
|
188
215
|
|
|
189
|
-
return
|
|
216
|
+
return self:_executePromiseWithMaid(function(maid)
|
|
217
|
+
return undoStackEntry:PromiseRedo(maid)
|
|
218
|
+
end)
|
|
190
219
|
:Then(function()
|
|
191
220
|
if undoStackEntry:HasUndo() then
|
|
192
221
|
table.insert(self._undoStack, undoStackEntry)
|
|
@@ -224,6 +253,28 @@ function UndoStack:_promiseCurrent(doNextPromise)
|
|
|
224
253
|
return promise
|
|
225
254
|
end
|
|
226
255
|
|
|
256
|
+
function UndoStack:_executePromiseWithMaid(callback)
|
|
257
|
+
local maid = Maid.new()
|
|
258
|
+
|
|
259
|
+
local promise = Promise.new()
|
|
260
|
+
maid:GiveTask(promise)
|
|
261
|
+
|
|
262
|
+
local result = callback(maid)
|
|
263
|
+
|
|
264
|
+
maid:GiveTask(function()
|
|
265
|
+
self._maid[maid] = nil
|
|
266
|
+
end)
|
|
267
|
+
self._maid[maid] = maid
|
|
268
|
+
|
|
269
|
+
promise:Finally(function()
|
|
270
|
+
self._maid[maid] = nil
|
|
271
|
+
end)
|
|
272
|
+
|
|
273
|
+
promise:Resolve(result)
|
|
274
|
+
|
|
275
|
+
return promise
|
|
276
|
+
end
|
|
277
|
+
|
|
227
278
|
function UndoStack:_updateHasUndoEntries()
|
|
228
279
|
self._hasUndoEntries.Value = #self._undoStack > 0
|
|
229
280
|
end
|
|
@@ -1,51 +1,98 @@
|
|
|
1
1
|
--[=[
|
|
2
|
+
Holds undo state
|
|
2
3
|
@class UndoStackEntry
|
|
3
4
|
]=]
|
|
4
5
|
|
|
5
6
|
local require = require(script.Parent.loader).load(script)
|
|
6
7
|
|
|
7
8
|
local Promise = require("Promise")
|
|
9
|
+
local Maid = require("Maid")
|
|
10
|
+
local BaseObject = require("BaseObject")
|
|
11
|
+
local Signal = require("Signal")
|
|
8
12
|
|
|
9
|
-
local UndoStackEntry = {}
|
|
13
|
+
local UndoStackEntry = setmetatable({}, BaseObject)
|
|
10
14
|
UndoStackEntry.ClassName = "UndoStackEntry"
|
|
11
15
|
UndoStackEntry.__index = UndoStackEntry
|
|
12
16
|
|
|
17
|
+
--[=[
|
|
18
|
+
Constructs a new undo restack entry. See [UndoStack] for usage.
|
|
19
|
+
|
|
20
|
+
@return UndoStackEntry
|
|
21
|
+
]=]
|
|
13
22
|
function UndoStackEntry.new()
|
|
14
|
-
local self = setmetatable(
|
|
23
|
+
local self = setmetatable(BaseObject.new(), UndoStackEntry)
|
|
24
|
+
|
|
25
|
+
self.Destroying = Signal.new()
|
|
26
|
+
self._maid:GiveTask(function()
|
|
27
|
+
self.Destroying:Fire()
|
|
28
|
+
self.Destroying:Destroy()
|
|
29
|
+
end)
|
|
15
30
|
|
|
16
31
|
return self
|
|
17
32
|
end
|
|
18
33
|
|
|
34
|
+
--[=[
|
|
35
|
+
Returns true if the etnry is an undo stack entry
|
|
36
|
+
|
|
37
|
+
@param value any
|
|
38
|
+
@return boolean
|
|
39
|
+
]=]
|
|
19
40
|
function UndoStackEntry.isUndoStackEntry(value)
|
|
20
41
|
return type(value) == "table" and getmetatable(value) == UndoStackEntry
|
|
21
42
|
end
|
|
22
43
|
|
|
44
|
+
--[=[
|
|
45
|
+
Sets the handler that will undo the result
|
|
46
|
+
|
|
47
|
+
@param promiseUndo function | nil
|
|
48
|
+
]=]
|
|
23
49
|
function UndoStackEntry:SetPromiseUndo(promiseUndo)
|
|
24
50
|
assert(type(promiseUndo) == "function" or promiseUndo == nil, "Bad promiseUndo")
|
|
25
51
|
|
|
26
52
|
self._promiseUndo = promiseUndo
|
|
27
53
|
end
|
|
28
54
|
|
|
55
|
+
--[=[
|
|
56
|
+
Sets the handler that will redo the result
|
|
57
|
+
|
|
58
|
+
@param promiseRedo function | nil
|
|
59
|
+
]=]
|
|
29
60
|
function UndoStackEntry:SetPromiseRedo(promiseRedo)
|
|
30
61
|
assert(type(promiseRedo) == "function" or promiseRedo == nil, "Bad promiseRedo")
|
|
31
62
|
|
|
32
63
|
self._promiseRedo = promiseRedo
|
|
33
64
|
end
|
|
34
65
|
|
|
66
|
+
--[=[
|
|
67
|
+
Returns true if this entry can be undone
|
|
68
|
+
@return boolean
|
|
69
|
+
]=]
|
|
35
70
|
function UndoStackEntry:HasUndo()
|
|
36
71
|
return self._promiseUndo ~= nil
|
|
37
72
|
end
|
|
38
73
|
|
|
74
|
+
--[=[
|
|
75
|
+
Returns true if this entry can be redone
|
|
76
|
+
@return boolean
|
|
77
|
+
]=]
|
|
39
78
|
function UndoStackEntry:HasRedo()
|
|
40
79
|
return self._promiseRedo ~= nil
|
|
41
80
|
end
|
|
42
81
|
|
|
43
|
-
|
|
82
|
+
--[=[
|
|
83
|
+
Promises undo. Should be done via [UndoStack.PromiseUndo]
|
|
84
|
+
|
|
85
|
+
@param maid Maid
|
|
86
|
+
@return Promise
|
|
87
|
+
]=]
|
|
88
|
+
function UndoStackEntry:PromiseUndo(maid)
|
|
89
|
+
assert(Maid.isMaid(maid), "Bad maid")
|
|
90
|
+
|
|
44
91
|
if not self._promiseUndo then
|
|
45
92
|
return Promise.resolved()
|
|
46
93
|
end
|
|
47
94
|
|
|
48
|
-
local result = self._promiseUndo()
|
|
95
|
+
local result = maid:GivePromise(self._promiseUndo(maid))
|
|
49
96
|
if Promise.isPromise(result) then
|
|
50
97
|
return result
|
|
51
98
|
else
|
|
@@ -53,12 +100,20 @@ function UndoStackEntry:PromiseUndo()
|
|
|
53
100
|
end
|
|
54
101
|
end
|
|
55
102
|
|
|
56
|
-
|
|
103
|
+
--[=[
|
|
104
|
+
Promises redo execution. Should be done via [UndoStack.PromiseRedo]
|
|
105
|
+
|
|
106
|
+
@param maid Maid
|
|
107
|
+
@return Promise
|
|
108
|
+
]=]
|
|
109
|
+
function UndoStackEntry:PromiseRedo(maid)
|
|
110
|
+
assert(Maid.isMaid(maid), "Bad maid")
|
|
111
|
+
|
|
57
112
|
if not self._promiseUndo then
|
|
58
113
|
return Promise.resolved()
|
|
59
114
|
end
|
|
60
115
|
|
|
61
|
-
local result = self._promiseRedo()
|
|
116
|
+
local result = maid:GivePromise(self._promiseRedo(maid))
|
|
62
117
|
if Promise.isPromise(result) then
|
|
63
118
|
return result
|
|
64
119
|
else
|