@@ -16,30 +16,30 @@ import TextStory
1616/// - Grouping pasted text
1717///
1818/// If needed, the automatic undo grouping can be overridden using the `beginGrouping()` and `endGrouping()` methods.
19- class CEUndoManager {
19+ public class CEUndoManager {
2020 /// An `UndoManager` subclass that forwards relevant actions to a `CEUndoManager`.
2121 /// Allows for objects like `STTextView` to use the `UndoManager` API
2222 /// while CETV manages the undo/redo actions.
23- class DelegatedUndoManager : UndoManager {
23+ public class DelegatedUndoManager : UndoManager {
2424 weak var parent : CEUndoManager ?
2525
26- override var canUndo : Bool { parent? . canUndo ?? false }
27- override var canRedo : Bool { parent? . canRedo ?? false }
26+ public override var canUndo : Bool { parent? . canUndo ?? false }
27+ public override var canRedo : Bool { parent? . canRedo ?? false }
2828
29- func registerMutation( _ mutation: TextMutation ) {
29+ public func registerMutation( _ mutation: TextMutation ) {
3030 parent? . registerMutation ( mutation)
3131 removeAllActions ( )
3232 }
3333
34- override func undo( ) {
34+ public override func undo( ) {
3535 parent? . undo ( )
3636 }
3737
38- override func redo( ) {
38+ public override func redo( ) {
3939 parent? . redo ( )
4040 }
4141
42- override func registerUndo( withTarget target: Any , selector: Selector , object anObject: Any ? ) {
42+ public override func registerUndo( withTarget target: Any , selector: Selector , object anObject: Any ? ) {
4343 // no-op, but just in case to save resources:
4444 removeAllActions ( )
4545 }
@@ -71,36 +71,41 @@ class CEUndoManager {
7171 /// A stack of operations that can be redone.
7272 private var redoStack : [ UndoGroup ] = [ ]
7373
74- private unowned let textView : STTextView
74+ internal weak var textView : STTextView ?
7575 private( set) var isGrouping : Bool = false
7676
77- public init ( textView: STTextView ) {
78- self . textView = textView
77+ public init ( ) {
7978 self . manager = DelegatedUndoManager ( )
8079 manager. parent = self
8180 }
8281
8382 /// Performs an undo operation if there is one available.
8483 public func undo( ) {
85- guard let item = undoStack. popLast ( ) else {
84+ guard let item = undoStack. popLast ( ) ,
85+ let textView else {
8686 return
8787 }
8888 isUndoing = true
8989 for mutation in item. mutations. reversed ( ) {
90+ NotificationCenter . default. post ( name: . NSUndoManagerWillUndoChange, object: self . manager)
9091 textView. applyMutationNoUndo ( mutation. inverse)
92+ NotificationCenter . default. post ( name: . NSUndoManagerDidUndoChange, object: self . manager)
9193 }
9294 redoStack. append ( item)
9395 isUndoing = false
9496 }
9597
9698 /// Performs a redo operation if there is one available.
9799 public func redo( ) {
98- guard let item = redoStack. popLast ( ) else {
100+ guard let item = redoStack. popLast ( ) ,
101+ let textView else {
99102 return
100103 }
101104 isRedoing = true
102105 for mutation in item. mutations {
106+ NotificationCenter . default. post ( name: . NSUndoManagerWillRedoChange, object: self . manager)
103107 textView. applyMutationNoUndo ( mutation. mutation)
108+ NotificationCenter . default. post ( name: . NSUndoManagerDidRedoChange, object: self . manager)
104109 }
105110 undoStack. append ( item)
106111 isRedoing = false
@@ -117,6 +122,8 @@ class CEUndoManager {
117122 /// Calling this method while the manager is in an undo/redo operation will result in a no-op.
118123 /// - Parameter mutation: The mutation to register for undo/redo
119124 public func registerMutation( _ mutation: TextMutation ) {
125+ guard let textView else { return }
126+
120127 if ( mutation. range. length == 0 && mutation. string. isEmpty) || isUndoing || isRedoing { return }
121128 let newMutation = UndoGroup . Mutation ( mutation: mutation, inverse: textView. inverseMutation ( for: mutation) )
122129 if !undoStack. isEmpty, let lastMutation = undoStack. last? . mutations. last {
0 commit comments