Skip to content

Commit d2b53a5

Browse files
committed
Add skupUpdateSelection
1 parent 3581f1f commit d2b53a5

File tree

1 file changed

+40
-5
lines changed

1 file changed

+40
-5
lines changed

Sources/CodeEditTextView/TextView/TextView+ReplaceCharacters.swift

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@ extension TextView {
1313
/// - Parameters:
1414
/// - ranges: The ranges to replace
1515
/// - string: The string to insert in the ranges.
16-
public func replaceCharacters(in ranges: [NSRange], with string: String) {
16+
/// - skipUpdateSelection: Skips the selection update step
17+
public func replaceCharacters(
18+
in ranges: [NSRange],
19+
with string: String,
20+
skipUpdateSelection: Bool = false
21+
) {
1722
guard isEditable else { return }
1823
NotificationCenter.default.post(name: Self.textWillChangeNotification, object: self)
1924
textStorage.beginEditing()
@@ -34,13 +39,17 @@ extension TextView {
3439
in: range,
3540
with: NSAttributedString(string: string, attributes: typingAttributes)
3641
)
37-
selectionManager.didReplaceCharacters(in: range, replacementLength: (string as NSString).length)
42+
if !skipUpdateSelection {
43+
selectionManager.didReplaceCharacters(in: range, replacementLength: (string as NSString).length)
44+
}
3845

3946
delegate?.textView(self, didReplaceContentsIn: range, with: string)
4047
}
4148

4249
textStorage.endEditing()
43-
selectionManager.notifyAfterEdit()
50+
if !skipUpdateSelection {
51+
selectionManager.notifyAfterEdit()
52+
}
4453
NotificationCenter.default.post(name: Self.textDidChangeNotification, object: self)
4554

4655
// `scrollSelectionToVisible` is a little expensive to call every time. Instead we just check if the first
@@ -54,7 +63,33 @@ extension TextView {
5463
/// - Parameters:
5564
/// - range: The range to replace.
5665
/// - string: The string to insert in the range.
57-
public func replaceCharacters(in range: NSRange, with string: String) {
58-
replaceCharacters(in: [range], with: string)
66+
/// - skipUpdateSelection: Skips the selection update step
67+
public func replaceCharacters(
68+
in range: NSRange,
69+
with string: String,
70+
skipUpdateSelection: Bool = false
71+
) {
72+
replaceCharacters(in: [range], with: string, skipUpdateSelection: skipUpdateSelection)
73+
}
74+
75+
/// Iterates over all text selections in the `TextView` and applies the provided callback.
76+
///
77+
/// This method is typically used when you need to perform an operation on each text selection in the editor,
78+
/// such as adjusting indentation, or other selection-based operations. The callback
79+
/// is executed for each selection, and you can modify the selection or perform related tasks.
80+
///
81+
/// - Parameters:
82+
/// - callback: A closure that will be executed for each selection in the `TextView`. It takes two parameters:
83+
/// a `TextView` instance, allowing access to the view's properties and methods and a
84+
/// `TextSelectionManager.TextSelection` representing the current selection to operate on.
85+
///
86+
/// - Note: The selections are iterated in reverse order, so modifications to earlier selections won't affect later
87+
/// ones. The method automatically calls `notifyAfterEdit()` on the `selectionManager` after all
88+
/// selections are processed.
89+
public func editSelections(callback: (TextView, TextSelectionManager.TextSelection) -> Void) {
90+
for textSelection in selectionManager.textSelections.reversed() {
91+
callback(self, textSelection)
92+
}
93+
selectionManager.notifyAfterEdit(force: true)
5994
}
6095
}

0 commit comments

Comments
 (0)