Skip to content

Commit 86d20a7

Browse files
committed
Fixed most of the bugs introduced in the find replace refactor.
1 parent 35df1a2 commit 86d20a7

File tree

6 files changed

+73
-34
lines changed

6 files changed

+73
-34
lines changed

Sources/CodeEditSourceEditor/Find/PanelView/FindPanelView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ struct FindPanelView: View {
106106
HStack(spacing: 4) {
107107
ControlGroup {
108108
Button {
109-
viewModel.replace(all: false)
109+
viewModel.replace()
110110
} label: {
111111
Text("Replace")
112112
.opacity(
@@ -126,7 +126,7 @@ struct FindPanelView: View {
126126
Divider().overlay(Color(nsColor: .tertiaryLabelColor))
127127

128128
Button {
129-
viewModel.replace(all: true)
129+
viewModel.replaceAll()
130130
} label: {
131131
Text("All")
132132
.opacity(viewModel.findText.isEmpty || viewModel.matchCount == 0 ? 0.33 : 1)

Sources/CodeEditSourceEditor/Find/ViewModel/FindPanelViewModel+Emphasis.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,33 @@ extension FindPanelViewModel {
3131
emphasisManager.addEmphases(emphases, for: EmphasisGroup.find)
3232
}
3333

34+
func flashCurrentMatch() {
35+
guard let target = target,
36+
let emphasisManager = target.emphasisManager,
37+
let currentFindMatchIndex else {
38+
return
39+
}
40+
41+
let currentMatch = findMatches[currentFindMatchIndex]
42+
43+
// Clear existing emphases
44+
emphasisManager.removeEmphases(for: EmphasisGroup.find)
45+
46+
// Create emphasis with the nearest match as active
47+
let emphasis = (
48+
Emphasis(
49+
range: currentMatch,
50+
style: .standard,
51+
flash: true,
52+
inactive: false,
53+
selectInDocument: true
54+
)
55+
)
56+
57+
// Add the emphasis
58+
emphasisManager.addEmphases([emphasis], for: EmphasisGroup.find)
59+
}
60+
3461
func clearMatchEmphases() {
3562
target?.emphasisManager?.removeEmphases(for: EmphasisGroup.find)
3663
}

Sources/CodeEditSourceEditor/Find/ViewModel/FindPanelViewModel+Find.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ extension FindPanelViewModel {
1515
func find() {
1616
// Don't find if target or emphasisManager isn't ready or the query is empty
1717
guard let target = target, isFocused, !findText.isEmpty else {
18-
updateMatches([])
18+
self.findMatches = []
1919
return
2020
}
2121

@@ -24,14 +24,15 @@ extension FindPanelViewModel {
2424
let escapedQuery = NSRegularExpression.escapedPattern(for: findText)
2525

2626
guard let regex = try? NSRegularExpression(pattern: escapedQuery, options: findOptions) else {
27-
updateMatches([])
27+
self.findMatches = []
28+
self.currentFindMatchIndex = 0
2829
return
2930
}
3031

3132
let text = target.text
3233
let matches = regex.matches(in: text, range: NSRange(location: 0, length: text.utf16.count))
3334

34-
updateMatches(matches.map(\.range))
35+
self.findMatches = matches.map(\.range)
3536

3637
// Find the nearest match to the current cursor position
3738
currentFindMatchIndex = getNearestEmphasisIndex(matchRanges: findMatches) ?? 0

Sources/CodeEditSourceEditor/Find/ViewModel/FindPanelViewModel+Move.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,13 @@ extension FindPanelViewModel {
2525
}
2626

2727
// From here on out we want to emphasize the result no matter what
28-
defer { addMatchEmphases(flashCurrent: isTargetFirstResponder) }
28+
defer {
29+
if isTargetFirstResponder {
30+
flashCurrentMatch()
31+
} else {
32+
addMatchEmphases(flashCurrent: isTargetFirstResponder)
33+
}
34+
}
2935

3036
guard let currentFindMatchIndex else {
3137
self.currentFindMatchIndex = 0
@@ -54,7 +60,7 @@ extension FindPanelViewModel {
5460
}
5561
BezelNotification.show(
5662
symbolName: error ?
57-
forwards ? "arrow.up.to.line" : "arrow.down.to.line"
63+
forwards ? "arrow.down.to.line" : "arrow.up.to.line"
5864
: forwards
5965
? "arrow.trianglehead.topright.capsulepath.clockwise"
6066
: "arrow.trianglehead.bottomleft.capsulepath.clockwise",

Sources/CodeEditSourceEditor/Find/ViewModel/FindPanelViewModel+Replace.swift

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,39 +11,51 @@ import CodeEditTextView
1111
extension FindPanelViewModel {
1212
/// Replace one or all ``findMatches`` with the contents of ``replaceText``.
1313
/// - Parameter all: If true, replaces all matches instead of just the selected one.
14-
func replace(all: Bool) {
14+
func replace() {
1515
guard let target = target,
1616
let currentFindMatchIndex,
1717
!findMatches.isEmpty,
1818
let textViewController = target as? TextViewController else {
1919
return
2020
}
2121

22-
if all {
23-
textViewController.textView.undoManager?.beginUndoGrouping()
24-
textViewController.textView.textStorage.beginEditing()
22+
replaceMatch(index: currentFindMatchIndex, textView: textViewController.textView, matches: &findMatches)
2523

26-
var sortedMatches = findMatches.sorted(by: { $0.location < $1.location })
27-
for (idx, _) in sortedMatches.enumerated().reversed() {
28-
replaceMatch(index: idx, textView: textViewController.textView, matches: &sortedMatches)
29-
}
24+
self.findMatches = findMatches.enumerated().filter({ $0.offset != currentFindMatchIndex }).map(\.element)
25+
self.currentFindMatchIndex = findMatches.isEmpty ? nil : (currentFindMatchIndex) % findMatches.count
3026

31-
textViewController.textView.textStorage.endEditing()
32-
textViewController.textView.undoManager?.endUndoGrouping()
27+
// Update the emphases
28+
addMatchEmphases(flashCurrent: true)
29+
}
3330

34-
if let lastMatch = sortedMatches.last {
35-
target.setCursorPositions(
36-
[CursorPosition(range: NSRange(location: lastMatch.location, length: 0))],
37-
scrollToVisible: true
38-
)
39-
}
31+
func replaceAll() {
32+
guard let target = target,
33+
!findMatches.isEmpty,
34+
let textViewController = target as? TextViewController else {
35+
return
36+
}
37+
38+
textViewController.textView.undoManager?.beginUndoGrouping()
39+
textViewController.textView.textStorage.beginEditing()
40+
41+
var sortedMatches = findMatches.sorted(by: { $0.location < $1.location })
42+
for (idx, _) in sortedMatches.enumerated().reversed() {
43+
replaceMatch(index: idx, textView: textViewController.textView, matches: &sortedMatches)
44+
}
45+
46+
textViewController.textView.textStorage.endEditing()
47+
textViewController.textView.undoManager?.endUndoGrouping()
4048

41-
updateMatches([])
42-
} else {
43-
replaceMatch(index: currentFindMatchIndex, textView: textViewController.textView, matches: &findMatches)
44-
updateMatches(findMatches)
49+
if let lastMatch = sortedMatches.last {
50+
target.setCursorPositions(
51+
[CursorPosition(range: NSRange(location: lastMatch.location, length: 0))],
52+
scrollToVisible: true
53+
)
4554
}
4655

56+
self.findMatches = []
57+
self.currentFindMatchIndex = nil
58+
4759
// Update the emphases
4860
addMatchEmphases(flashCurrent: true)
4961
}

Sources/CodeEditSourceEditor/Find/ViewModel/FindPanelViewModel.swift

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,6 @@ class FindPanelViewModel: ObservableObject {
5858
}
5959
}
6060

61-
// MARK: - Update Matches
62-
63-
func updateMatches(_ newMatches: [NSRange]) {
64-
findMatches = newMatches
65-
currentFindMatchIndex = newMatches.isEmpty ? nil : 0
66-
}
67-
6861
// MARK: - Text Listeners
6962

7063
/// Find target's text content changed, we need to re-search the contents and emphasize results.

0 commit comments

Comments
 (0)