Skip to content

Commit 6a04ca7

Browse files
authored
Make CEUndoManager public (#212)
1 parent 7f130bd commit 6a04ca7

File tree

5 files changed

+34
-19
lines changed

5 files changed

+34
-19
lines changed

Sources/CodeEditTextView/CodeEditTextView.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public struct CodeEditTextView: NSViewControllerRepresentable {
3535
/// character's width between characters, etc. Defaults to `1.0`
3636
/// - bracketPairHighlight: The type of highlight to use to highlight bracket pairs.
3737
/// See `BracketPairHighlight` for more information. Defaults to `nil`
38+
/// - undoManager: The undo manager for the text view. Defaults to `nil`, which will create a new CEUndoManager
3839
public init(
3940
_ text: Binding<String>,
4041
language: CodeLanguage,
@@ -51,7 +52,8 @@ public struct CodeEditTextView: NSViewControllerRepresentable {
5152
contentInsets: NSEdgeInsets? = nil,
5253
isEditable: Bool = true,
5354
letterSpacing: Double = 1.0,
54-
bracketPairHighlight: BracketPairHighlight? = nil
55+
bracketPairHighlight: BracketPairHighlight? = nil,
56+
undoManager: CEUndoManager? = nil
5557
) {
5658
self._text = text
5759
self.language = language
@@ -69,6 +71,7 @@ public struct CodeEditTextView: NSViewControllerRepresentable {
6971
self.isEditable = isEditable
7072
self.letterSpacing = letterSpacing
7173
self.bracketPairHighlight = bracketPairHighlight
74+
self.undoManager = undoManager ?? CEUndoManager()
7275
}
7376

7477
@Binding private var text: String
@@ -87,6 +90,7 @@ public struct CodeEditTextView: NSViewControllerRepresentable {
8790
private var isEditable: Bool
8891
private var letterSpacing: Double
8992
private var bracketPairHighlight: BracketPairHighlight?
93+
private var undoManager: CEUndoManager
9094

9195
public typealias NSViewControllerType = STTextViewController
9296

@@ -107,7 +111,8 @@ public struct CodeEditTextView: NSViewControllerRepresentable {
107111
contentInsets: contentInsets,
108112
isEditable: isEditable,
109113
letterSpacing: letterSpacing,
110-
bracketPairHighlight: bracketPairHighlight
114+
bracketPairHighlight: bracketPairHighlight,
115+
undoManager: undoManager
111116
)
112117
return controller
113118
}

Sources/CodeEditTextView/Controller/CEUndoManager.swift

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -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 {

Sources/CodeEditTextView/Controller/STTextViewController+Lifecycle.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ extension STTextViewController {
5757
return event
5858
}
5959

60-
textViewUndoManager = CEUndoManager(textView: textView)
60+
textViewUndoManager.textView = textView
6161
reloadUI()
6262
setUpHighlighter()
6363
setHighlightProvider(self.highlightProvider)

Sources/CodeEditTextView/Controller/STTextViewController.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public class STTextViewController: NSViewController, STTextViewDelegate, ThemeAt
2727
/// for every new selection.
2828
internal var lastTextSelections: [NSTextRange] = []
2929

30-
internal var textViewUndoManager: CEUndoManager!
30+
internal var textViewUndoManager: CEUndoManager
3131

3232
/// Binding for the `textView`s string
3333
public var text: Binding<String>
@@ -133,7 +133,8 @@ public class STTextViewController: NSViewController, STTextViewDelegate, ThemeAt
133133
contentInsets: NSEdgeInsets? = nil,
134134
isEditable: Bool,
135135
letterSpacing: Double,
136-
bracketPairHighlight: BracketPairHighlight? = nil
136+
bracketPairHighlight: BracketPairHighlight? = nil,
137+
undoManager: CEUndoManager
137138
) {
138139
self.text = text
139140
self.language = language
@@ -150,6 +151,7 @@ public class STTextViewController: NSViewController, STTextViewDelegate, ThemeAt
150151
self.contentInsets = contentInsets
151152
self.isEditable = isEditable
152153
self.bracketPairHighlight = bracketPairHighlight
154+
self.textViewUndoManager = undoManager
153155
super.init(nibName: nil, bundle: nil)
154156
}
155157

Tests/CodeEditTextViewTests/STTextViewControllerTests.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ final class STTextViewControllerTests: XCTestCase {
4242
editorOverscroll: 0.5,
4343
useThemeBackground: true,
4444
isEditable: true,
45-
letterSpacing: 1.0
45+
letterSpacing: 1.0,
46+
undoManager: CEUndoManager()
4647
)
4748

4849
controller.loadView()

0 commit comments

Comments
 (0)