@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 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.14.0",
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.14.0",
29
+ "@quenty/instanceutils": "^7.15.0",
30
30
  "@quenty/loader": "^6.2.1",
31
- "@quenty/promise": "^6.5.0"
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": "11058e90e51ea83d3dad6ae9abe59cc19c36b94b"
39
+ "gitHead": "dc77d6de09e9eb9d3fd6dafd790c052d8393d38f"
37
40
  }
@@ -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
- self:_updateHasUndoEntries()
146
- self:_updateHasRedoEntries()
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 undoStackEntry:PromiseUndo()
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 undoStackEntry:PromiseRedo()
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({}, UndoStackEntry)
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
- function UndoStackEntry:PromiseUndo()
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
- function UndoStackEntry:PromiseRedo()
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