@quenty/undostack 7.17.3 → 7.17.4-canary.559.339cfa7.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 +10 -10
- package/src/Shared/UndoStack.lua +51 -39
- package/src/Shared/UndoStackEntry.lua +31 -16
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
|
+
## [7.17.4-canary.559.339cfa7.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/undostack@7.17.3...@quenty/undostack@7.17.4-canary.559.339cfa7.0) (2025-05-10)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* Additional type checking updates ([05ba29a](https://github.com/Quenty/NevermoreEngine/commit/05ba29a03efc9f3feed74b34f1d9dfb237496214))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
## [7.17.3](https://github.com/Quenty/NevermoreEngine/compare/@quenty/undostack@7.17.2...@quenty/undostack@7.17.3) (2025-04-10)
|
|
7
18
|
|
|
8
19
|
**Note:** Version bump only for package @quenty/undostack
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/undostack",
|
|
3
|
-
"version": "7.17.
|
|
3
|
+
"version": "7.17.4-canary.559.339cfa7.0",
|
|
4
4
|
"description": "Generalized undo stack for Roblox",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -25,17 +25,17 @@
|
|
|
25
25
|
"Quenty"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@quenty/baseobject": "
|
|
29
|
-
"@quenty/ducktype": "
|
|
30
|
-
"@quenty/instanceutils": "
|
|
31
|
-
"@quenty/loader": "
|
|
32
|
-
"@quenty/maid": "
|
|
33
|
-
"@quenty/promise": "
|
|
34
|
-
"@quenty/signal": "
|
|
35
|
-
"@quenty/valueobject": "
|
|
28
|
+
"@quenty/baseobject": "10.8.4-canary.559.339cfa7.0",
|
|
29
|
+
"@quenty/ducktype": "5.8.5-canary.559.339cfa7.0",
|
|
30
|
+
"@quenty/instanceutils": "13.17.4-canary.559.339cfa7.0",
|
|
31
|
+
"@quenty/loader": "10.8.4-canary.559.339cfa7.0",
|
|
32
|
+
"@quenty/maid": "3.4.4-canary.559.339cfa7.0",
|
|
33
|
+
"@quenty/promise": "10.10.5-canary.559.339cfa7.0",
|
|
34
|
+
"@quenty/signal": "7.10.4-canary.559.339cfa7.0",
|
|
35
|
+
"@quenty/valueobject": "13.17.4-canary.559.339cfa7.0"
|
|
36
36
|
},
|
|
37
37
|
"publishConfig": {
|
|
38
38
|
"access": "public"
|
|
39
39
|
},
|
|
40
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "339cfa778736f08768ed7305041f6221faa35bfc"
|
|
41
41
|
}
|
package/src/Shared/UndoStack.lua
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
@class UndoStack
|
|
3
4
|
]=]
|
|
@@ -5,10 +6,11 @@
|
|
|
5
6
|
local require = require(script.Parent.loader).load(script)
|
|
6
7
|
|
|
7
8
|
local BaseObject = require("BaseObject")
|
|
9
|
+
local Maid = require("Maid")
|
|
10
|
+
local Observable = require("Observable")
|
|
8
11
|
local Promise = require("Promise")
|
|
9
12
|
local UndoStackEntry = require("UndoStackEntry")
|
|
10
13
|
local ValueObject = require("ValueObject")
|
|
11
|
-
local Maid = require("Maid")
|
|
12
14
|
|
|
13
15
|
local DEFAULT_MAX_SIZE = 25
|
|
14
16
|
|
|
@@ -16,8 +18,21 @@ local UndoStack = setmetatable({}, BaseObject)
|
|
|
16
18
|
UndoStack.ClassName = "UndoStack"
|
|
17
19
|
UndoStack.__index = UndoStack
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
export type UndoStack = typeof(setmetatable(
|
|
22
|
+
{} :: {
|
|
23
|
+
_undoStack: { UndoStackEntry.UndoStackEntry },
|
|
24
|
+
_redoStack: { UndoStackEntry.UndoStackEntry },
|
|
25
|
+
_hasUndoEntries: ValueObject.ValueObject<boolean>,
|
|
26
|
+
_hasRedoEntries: ValueObject.ValueObject<boolean>,
|
|
27
|
+
_isActionExecuting: ValueObject.ValueObject<boolean>,
|
|
28
|
+
_maxSize: number,
|
|
29
|
+
_latestPromiseChain: Promise.Promise<()>?,
|
|
30
|
+
},
|
|
31
|
+
{} :: typeof({ __index = UndoStack })
|
|
32
|
+
)) & BaseObject.BaseObject
|
|
33
|
+
|
|
34
|
+
function UndoStack.new(maxSize: number?): UndoStack
|
|
35
|
+
local self: UndoStack = setmetatable(BaseObject.new() :: any, UndoStack)
|
|
21
36
|
|
|
22
37
|
assert(type(maxSize) == "number" or maxSize == nil, "Bad maxSize")
|
|
23
38
|
|
|
@@ -38,7 +53,7 @@ end
|
|
|
38
53
|
can't push an undo.
|
|
39
54
|
@return boolean
|
|
40
55
|
]=]
|
|
41
|
-
function UndoStack
|
|
56
|
+
function UndoStack.ClearRedoStack(self: UndoStack)
|
|
42
57
|
self._redoStack = {}
|
|
43
58
|
self:_updateHasRedoEntries()
|
|
44
59
|
end
|
|
@@ -47,7 +62,7 @@ end
|
|
|
47
62
|
Returns true if an action is executing
|
|
48
63
|
@return boolean
|
|
49
64
|
]=]
|
|
50
|
-
function UndoStack
|
|
65
|
+
function UndoStack.IsActionExecuting(self: UndoStack): boolean
|
|
51
66
|
return self._isActionExecuting.Value
|
|
52
67
|
end
|
|
53
68
|
|
|
@@ -55,7 +70,7 @@ end
|
|
|
55
70
|
Observes whether the stack has undo entries
|
|
56
71
|
@return Observable<boolean>
|
|
57
72
|
]=]
|
|
58
|
-
function UndoStack
|
|
73
|
+
function UndoStack.ObserveHasUndoEntries(self: UndoStack): Observable.Observable<boolean>
|
|
59
74
|
return self._hasUndoEntries:Observe()
|
|
60
75
|
end
|
|
61
76
|
|
|
@@ -63,7 +78,7 @@ end
|
|
|
63
78
|
Observes whether the stack has redo entries
|
|
64
79
|
@return Observable<boolean>
|
|
65
80
|
]=]
|
|
66
|
-
function UndoStack
|
|
81
|
+
function UndoStack.ObserveHasRedoEntries(self: UndoStack): Observable.Observable<boolean>
|
|
67
82
|
return self._hasRedoEntries:Observe()
|
|
68
83
|
end
|
|
69
84
|
|
|
@@ -71,7 +86,7 @@ end
|
|
|
71
86
|
Returns true if there are undo entries on the stack
|
|
72
87
|
@return boolean
|
|
73
88
|
]=]
|
|
74
|
-
function UndoStack
|
|
89
|
+
function UndoStack.HasUndoEntries(self: UndoStack): boolean
|
|
75
90
|
return self._hasUndoEntries.Value
|
|
76
91
|
end
|
|
77
92
|
|
|
@@ -79,7 +94,7 @@ end
|
|
|
79
94
|
Returns true if there are redo entries on the stack
|
|
80
95
|
@return boolean
|
|
81
96
|
]=]
|
|
82
|
-
function UndoStack
|
|
97
|
+
function UndoStack.HasRedoEntries(self: UndoStack): boolean
|
|
83
98
|
return self._hasRedoEntries.Value
|
|
84
99
|
end
|
|
85
100
|
|
|
@@ -101,7 +116,7 @@ end
|
|
|
101
116
|
@param undoStackEntry UndoStackEntry
|
|
102
117
|
@return function -- Callback that removes the action
|
|
103
118
|
]=]
|
|
104
|
-
function UndoStack
|
|
119
|
+
function UndoStack.Push(self: UndoStack, undoStackEntry: UndoStackEntry.UndoStackEntry): () -> ()
|
|
105
120
|
assert(UndoStackEntry.isUndoStackEntry(undoStackEntry), "Bad undoStackEntry")
|
|
106
121
|
|
|
107
122
|
if self._maid[undoStackEntry] then
|
|
@@ -142,7 +157,7 @@ end
|
|
|
142
157
|
|
|
143
158
|
@param undoStackEntry The undo stack entry to remove
|
|
144
159
|
]=]
|
|
145
|
-
function UndoStack
|
|
160
|
+
function UndoStack.Remove(self: UndoStack, undoStackEntry: UndoStackEntry.UndoStackEntry): ()
|
|
146
161
|
assert(UndoStackEntry.isUndoStackEntry(undoStackEntry), "Bad undoStackEntry")
|
|
147
162
|
|
|
148
163
|
self._maid[undoStackEntry] = nil
|
|
@@ -171,7 +186,7 @@ end
|
|
|
171
186
|
|
|
172
187
|
@return Promise
|
|
173
188
|
]=]
|
|
174
|
-
function UndoStack
|
|
189
|
+
function UndoStack.PromiseUndo(self: UndoStack): Promise.Promise<()>
|
|
175
190
|
return self:_promiseCurrent(function()
|
|
176
191
|
local undoStackEntry = table.remove(self._undoStack)
|
|
177
192
|
if not undoStackEntry then
|
|
@@ -182,15 +197,14 @@ function UndoStack:PromiseUndo()
|
|
|
182
197
|
|
|
183
198
|
return self:_executePromiseWithMaid(function(maid)
|
|
184
199
|
return undoStackEntry:PromiseUndo(maid)
|
|
200
|
+
end):Then(function()
|
|
201
|
+
if undoStackEntry:HasRedo() then
|
|
202
|
+
table.insert(self._redoStack, undoStackEntry)
|
|
203
|
+
self:_updateHasRedoEntries()
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
return true
|
|
185
207
|
end)
|
|
186
|
-
:Then(function()
|
|
187
|
-
if undoStackEntry:HasRedo() then
|
|
188
|
-
table.insert(self._redoStack, undoStackEntry)
|
|
189
|
-
self:_updateHasRedoEntries()
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
return true
|
|
193
|
-
end)
|
|
194
208
|
end)
|
|
195
209
|
end
|
|
196
210
|
|
|
@@ -199,7 +213,7 @@ end
|
|
|
199
213
|
|
|
200
214
|
@return Promise
|
|
201
215
|
]=]
|
|
202
|
-
function UndoStack
|
|
216
|
+
function UndoStack.PromiseRedo(self: UndoStack): Promise.Promise<()>
|
|
203
217
|
return self:_promiseCurrent(function()
|
|
204
218
|
local undoStackEntry = table.remove(self._redoStack)
|
|
205
219
|
if not undoStackEntry then
|
|
@@ -210,25 +224,23 @@ function UndoStack:PromiseRedo()
|
|
|
210
224
|
|
|
211
225
|
return self:_executePromiseWithMaid(function(maid)
|
|
212
226
|
return undoStackEntry:PromiseRedo(maid)
|
|
227
|
+
end):Then(function()
|
|
228
|
+
if undoStackEntry:HasUndo() then
|
|
229
|
+
table.insert(self._undoStack, undoStackEntry)
|
|
230
|
+
self:_updateHasUndoEntries()
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
return true
|
|
213
234
|
end)
|
|
214
|
-
:Then(function()
|
|
215
|
-
if undoStackEntry:HasUndo() then
|
|
216
|
-
table.insert(self._undoStack, undoStackEntry)
|
|
217
|
-
self:_updateHasUndoEntries()
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
return true
|
|
221
|
-
end)
|
|
222
235
|
end)
|
|
223
236
|
end
|
|
224
237
|
|
|
225
|
-
function UndoStack
|
|
238
|
+
function UndoStack._promiseCurrent(self: UndoStack, doNextPromise: () -> Promise.Promise<()>): Promise.Promise<()>
|
|
226
239
|
local promise
|
|
227
240
|
if self._latestPromiseChain then
|
|
228
|
-
promise = self._latestPromiseChain
|
|
229
|
-
:
|
|
230
|
-
|
|
231
|
-
end)
|
|
241
|
+
promise = self._latestPromiseChain:Finally(function()
|
|
242
|
+
return self._maid:GivePromise(doNextPromise())
|
|
243
|
+
end)
|
|
232
244
|
else
|
|
233
245
|
promise = self._maid:GivePromise(doNextPromise())
|
|
234
246
|
end
|
|
@@ -248,8 +260,8 @@ function UndoStack:_promiseCurrent(doNextPromise)
|
|
|
248
260
|
return promise
|
|
249
261
|
end
|
|
250
262
|
|
|
251
|
-
function UndoStack
|
|
252
|
-
local maid
|
|
263
|
+
function UndoStack._executePromiseWithMaid(self: UndoStack, callback: (Maid.Maid) -> any): Promise.Promise<()>
|
|
264
|
+
local maid = Maid.new()
|
|
253
265
|
|
|
254
266
|
local promise = Promise.new()
|
|
255
267
|
maid:GiveTask(promise)
|
|
@@ -270,12 +282,12 @@ function UndoStack:_executePromiseWithMaid(callback)
|
|
|
270
282
|
return promise
|
|
271
283
|
end
|
|
272
284
|
|
|
273
|
-
function UndoStack
|
|
285
|
+
function UndoStack._updateHasUndoEntries(self: UndoStack)
|
|
274
286
|
self._hasUndoEntries.Value = #self._undoStack > 0
|
|
275
287
|
end
|
|
276
288
|
|
|
277
|
-
function UndoStack
|
|
289
|
+
function UndoStack._updateHasRedoEntries(self: UndoStack)
|
|
278
290
|
self._hasRedoEntries.Value = #self._redoStack > 0
|
|
279
291
|
end
|
|
280
292
|
|
|
281
|
-
return UndoStack
|
|
293
|
+
return UndoStack
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
Holds undo state
|
|
3
4
|
@class UndoStackEntry
|
|
@@ -5,23 +6,35 @@
|
|
|
5
6
|
|
|
6
7
|
local require = require(script.Parent.loader).load(script)
|
|
7
8
|
|
|
8
|
-
local Promise = require("Promise")
|
|
9
|
-
local Maid = require("Maid")
|
|
10
9
|
local BaseObject = require("BaseObject")
|
|
11
|
-
local Signal = require("Signal")
|
|
12
10
|
local DuckTypeUtils = require("DuckTypeUtils")
|
|
11
|
+
local Maid = require("Maid")
|
|
12
|
+
local Promise = require("Promise")
|
|
13
|
+
local Signal = require("Signal")
|
|
13
14
|
|
|
14
15
|
local UndoStackEntry = setmetatable({}, BaseObject)
|
|
15
16
|
UndoStackEntry.ClassName = "UndoStackEntry"
|
|
16
17
|
UndoStackEntry.__index = UndoStackEntry
|
|
17
18
|
|
|
19
|
+
export type ExecuteUndo = (Maid.Maid) -> Promise.Promise<()> | any
|
|
20
|
+
export type ExecuteRedo = (Maid.Maid) -> Promise.Promise<()> | any
|
|
21
|
+
|
|
22
|
+
export type UndoStackEntry = typeof(setmetatable(
|
|
23
|
+
{} :: {
|
|
24
|
+
Destroying: Signal.Signal<()>,
|
|
25
|
+
_promiseUndo: ExecuteUndo?,
|
|
26
|
+
_promiseRedo: ExecuteRedo?,
|
|
27
|
+
},
|
|
28
|
+
{} :: typeof({ __index = UndoStackEntry })
|
|
29
|
+
)) & BaseObject.BaseObject
|
|
30
|
+
|
|
18
31
|
--[=[
|
|
19
32
|
Constructs a new undo restack entry. See [UndoStack] for usage.
|
|
20
33
|
|
|
21
34
|
@return UndoStackEntry
|
|
22
35
|
]=]
|
|
23
|
-
function UndoStackEntry.new()
|
|
24
|
-
local self = setmetatable(BaseObject.new(), UndoStackEntry)
|
|
36
|
+
function UndoStackEntry.new(): UndoStackEntry
|
|
37
|
+
local self: UndoStackEntry = setmetatable(BaseObject.new() :: any, UndoStackEntry)
|
|
25
38
|
|
|
26
39
|
self.Destroying = Signal.new()
|
|
27
40
|
self._maid:GiveTask(function()
|
|
@@ -47,7 +60,7 @@ end
|
|
|
47
60
|
|
|
48
61
|
@param promiseUndo function | nil
|
|
49
62
|
]=]
|
|
50
|
-
function UndoStackEntry
|
|
63
|
+
function UndoStackEntry.SetPromiseUndo(self: UndoStackEntry, promiseUndo: ExecuteUndo)
|
|
51
64
|
assert(type(promiseUndo) == "function" or promiseUndo == nil, "Bad promiseUndo")
|
|
52
65
|
|
|
53
66
|
self._promiseUndo = promiseUndo
|
|
@@ -58,7 +71,7 @@ end
|
|
|
58
71
|
|
|
59
72
|
@param promiseRedo function | nil
|
|
60
73
|
]=]
|
|
61
|
-
function UndoStackEntry
|
|
74
|
+
function UndoStackEntry.SetPromiseRedo(self: UndoStackEntry, promiseRedo: ExecuteRedo)
|
|
62
75
|
assert(type(promiseRedo) == "function" or promiseRedo == nil, "Bad promiseRedo")
|
|
63
76
|
|
|
64
77
|
self._promiseRedo = promiseRedo
|
|
@@ -68,7 +81,7 @@ end
|
|
|
68
81
|
Returns true if this entry can be undone
|
|
69
82
|
@return boolean
|
|
70
83
|
]=]
|
|
71
|
-
function UndoStackEntry
|
|
84
|
+
function UndoStackEntry.HasUndo(self: UndoStackEntry): boolean
|
|
72
85
|
return self._promiseUndo ~= nil
|
|
73
86
|
end
|
|
74
87
|
|
|
@@ -76,7 +89,7 @@ end
|
|
|
76
89
|
Returns true if this entry can be redone
|
|
77
90
|
@return boolean
|
|
78
91
|
]=]
|
|
79
|
-
function UndoStackEntry
|
|
92
|
+
function UndoStackEntry.HasRedo(self: UndoStackEntry): boolean
|
|
80
93
|
return self._promiseRedo ~= nil
|
|
81
94
|
end
|
|
82
95
|
|
|
@@ -86,14 +99,15 @@ end
|
|
|
86
99
|
@param maid Maid
|
|
87
100
|
@return Promise
|
|
88
101
|
]=]
|
|
89
|
-
function UndoStackEntry
|
|
102
|
+
function UndoStackEntry.PromiseUndo(self: UndoStackEntry, maid: Maid.Maid): Promise.Promise<()>
|
|
90
103
|
assert(Maid.isMaid(maid), "Bad maid")
|
|
91
104
|
|
|
92
|
-
|
|
105
|
+
local promiseUndo = self._promiseUndo
|
|
106
|
+
if not promiseUndo then
|
|
93
107
|
return Promise.resolved()
|
|
94
108
|
end
|
|
95
109
|
|
|
96
|
-
local result = maid:GivePromise(
|
|
110
|
+
local result = maid:GivePromise(promiseUndo(maid))
|
|
97
111
|
if Promise.isPromise(result) then
|
|
98
112
|
return result
|
|
99
113
|
else
|
|
@@ -107,14 +121,15 @@ end
|
|
|
107
121
|
@param maid Maid
|
|
108
122
|
@return Promise
|
|
109
123
|
]=]
|
|
110
|
-
function UndoStackEntry
|
|
124
|
+
function UndoStackEntry.PromiseRedo(self: UndoStackEntry, maid: Maid.Maid): Promise.Promise<()>
|
|
111
125
|
assert(Maid.isMaid(maid), "Bad maid")
|
|
112
126
|
|
|
113
|
-
|
|
127
|
+
local promiseRedo = self._promiseRedo
|
|
128
|
+
if not promiseRedo then
|
|
114
129
|
return Promise.resolved()
|
|
115
130
|
end
|
|
116
131
|
|
|
117
|
-
local result = maid:GivePromise(
|
|
132
|
+
local result = maid:GivePromise(promiseRedo(maid))
|
|
118
133
|
if Promise.isPromise(result) then
|
|
119
134
|
return result
|
|
120
135
|
else
|
|
@@ -122,4 +137,4 @@ function UndoStackEntry:PromiseRedo(maid)
|
|
|
122
137
|
end
|
|
123
138
|
end
|
|
124
139
|
|
|
125
|
-
return UndoStackEntry
|
|
140
|
+
return UndoStackEntry
|