Skip to content

Commit 8985e21

Browse files
Highlighter Highlights Text in Minimap (#308)
### Description The highlighter should now highlight all ‘visible’ text, including text that is visible in the minimap but not in the TextView. This PR merges the visible text in the minimap with the visible text in the TextView to highlight both. If the minimap is hidden, the highlighter will behave as before and only highlight the text visible in the TextView. ### Related Issues * #33 ### Checklist - [x] I read and understood the [contributing guide](https://github.com/CodeEditApp/CodeEdit/blob/main/CONTRIBUTING.md) as well as the [code of conduct](https://github.com/CodeEditApp/CodeEdit/blob/main/CODE_OF_CONDUCT.md) - [x] The issues this PR addresses are related to each other - [x] My changes generate no new warnings - [x] My code builds and runs on my machine - [x] My changes are all related to the related issue above - [x] I documented my code ### Screenshots https://github.com/user-attachments/assets/4bb7ead0-947d-41bc-96c1-7c7c4df3ad8b
1 parent bb2cbf5 commit 8985e21

File tree

6 files changed

+27
-35
lines changed

6 files changed

+27
-35
lines changed

Sources/CodeEditSourceEditor/Controller/TextViewController+Highlighter.swift

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ extension TextViewController {
1717

1818
let highlighter = Highlighter(
1919
textView: textView,
20+
minimapView: minimapView,
2021
providers: highlightProviders,
2122
attributeProvider: self,
2223
language: language

Sources/CodeEditSourceEditor/Highlighting/Highlighter.swift

+3-2
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ class Highlighter: NSObject {
8585

8686
init(
8787
textView: TextView,
88+
minimapView: MinimapView?,
8889
providers: [HighlightProviding],
8990
attributeProvider: ThemeAttributesProviding,
9091
language: CodeLanguage
@@ -93,7 +94,7 @@ class Highlighter: NSObject {
9394
self.textView = textView
9495
self.attributeProvider = attributeProvider
9596

96-
self.visibleRangeProvider = VisibleRangeProvider(textView: textView)
97+
self.visibleRangeProvider = VisibleRangeProvider(textView: textView, minimapView: minimapView)
9798

9899
let providerIds = providers.indices.map({ $0 })
99100
self.styleContainer = StyledRangeContainer(documentLength: textView.length, providers: providerIds)
@@ -244,7 +245,7 @@ extension Highlighter: NSTextStorageDelegate {
244245
visibleRangeProvider.visibleSet.insert(range: editedRange)
245246
}
246247

247-
visibleRangeProvider.updateVisibleSet(textView: textView)
248+
visibleRangeProvider.visibleTextChanged()
248249

249250
let providerRange = NSRange(location: editedRange.location, length: editedRange.length - delta)
250251
highlightProviders.forEach { $0.storageDidUpdate(range: providerRange, delta: delta) }

Sources/CodeEditSourceEditor/Highlighting/VisibleRangeProvider.swift

+18-29
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ protocol VisibleRangeProviderDelegate: AnyObject {
1818
@MainActor
1919
class VisibleRangeProvider {
2020
private weak var textView: TextView?
21+
private weak var minimapView: MinimapView?
2122
weak var delegate: VisibleRangeProviderDelegate?
2223

2324
var documentRange: NSRange {
@@ -29,56 +30,44 @@ class VisibleRangeProvider {
2930
return IndexSet(integersIn: textView?.visibleTextRange ?? NSRange())
3031
}()
3132

32-
init(textView: TextView) {
33+
init(textView: TextView, minimapView: MinimapView?) {
3334
self.textView = textView
35+
self.minimapView = minimapView
3436

3537
if let scrollView = textView.enclosingScrollView {
3638
NotificationCenter.default.addObserver(
3739
self,
38-
selector: #selector(visibleTextChanged(_:)),
40+
selector: #selector(visibleTextChanged),
3941
name: NSView.frameDidChangeNotification,
4042
object: scrollView
4143
)
4244

4345
NotificationCenter.default.addObserver(
4446
self,
45-
selector: #selector(visibleTextChanged(_:)),
47+
selector: #selector(visibleTextChanged),
4648
name: NSView.boundsDidChangeNotification,
4749
object: scrollView.contentView
4850
)
49-
} else {
50-
NotificationCenter.default.addObserver(
51-
self,
52-
selector: #selector(visibleTextChanged(_:)),
53-
name: NSView.frameDidChangeNotification,
54-
object: textView
55-
)
5651
}
57-
}
5852

59-
func updateVisibleSet(textView: TextView) {
60-
if let newVisibleRange = textView.visibleTextRange {
61-
visibleSet = IndexSet(integersIn: newVisibleRange)
62-
}
53+
NotificationCenter.default.addObserver(
54+
self,
55+
selector: #selector(visibleTextChanged),
56+
name: NSView.frameDidChangeNotification,
57+
object: textView
58+
)
6359
}
6460

6561
/// Updates the view to highlight newly visible text when the textview is scrolled or bounds change.
66-
@objc func visibleTextChanged(_ notification: Notification) {
67-
let textView: TextView
68-
if let clipView = notification.object as? NSClipView,
69-
let documentView = clipView.enclosingScrollView?.documentView as? TextView {
70-
textView = documentView
71-
} else if let scrollView = notification.object as? NSScrollView,
72-
let documentView = scrollView.documentView as? TextView {
73-
textView = documentView
74-
} else if let documentView = notification.object as? TextView {
75-
textView = documentView
76-
} else {
62+
@objc func visibleTextChanged() {
63+
guard let textViewVisibleRange = textView?.visibleTextRange else {
7764
return
7865
}
79-
80-
updateVisibleSet(textView: textView)
81-
66+
var visibleSet = IndexSet(integersIn: textViewVisibleRange)
67+
if !(minimapView?.isHidden ?? true), let minimapVisibleRange = minimapView?.visibleTextRange {
68+
visibleSet.formUnion(IndexSet(integersIn: minimapVisibleRange))
69+
}
70+
self.visibleSet = visibleSet
8271
delegate?.visibleSetDidUpdate(visibleSet)
8372
}
8473

Tests/CodeEditSourceEditorTests/Highlighting/HighlightProviderStateTest.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ final class HighlightProviderStateTest: XCTestCase {
3030
override func setUp() async throws {
3131
try await super.setUp()
3232
textView = Mock.textView()
33-
rangeProvider = MockVisibleRangeProvider(textView: textView)
33+
rangeProvider = MockVisibleRangeProvider(textView: textView, minimapView: nil)
3434
delegate = EmptyHighlightProviderStateDelegate()
3535
}
3636

Tests/CodeEditSourceEditorTests/Highlighting/VisibleRangeProviderTests.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ final class VisibleRangeProviderTests: XCTestCase {
88
textView.string = Array(repeating: "\n", count: 400).joined()
99
textView.layout()
1010

11-
let rangeProvider = VisibleRangeProvider(textView: textView)
11+
let rangeProvider = VisibleRangeProvider(textView: textView, minimapView: nil)
1212
let originalSet = rangeProvider.visibleSet
1313

1414
scrollView.contentView.scroll(to: NSPoint(x: 0, y: 250))
@@ -25,7 +25,7 @@ final class VisibleRangeProviderTests: XCTestCase {
2525
textView.string = Array(repeating: "\n", count: 400).joined()
2626
textView.layout()
2727

28-
let rangeProvider = VisibleRangeProvider(textView: textView)
28+
let rangeProvider = VisibleRangeProvider(textView: textView, minimapView: nil)
2929
let originalSet = rangeProvider.visibleSet
3030

3131
scrollView.setFrameSize(NSSize(width: 250, height: 450))
@@ -46,7 +46,7 @@ final class VisibleRangeProviderTests: XCTestCase {
4646
textView.string = Array(repeating: "\n", count: 400).joined()
4747
textView.layout()
4848

49-
let rangeProvider = VisibleRangeProvider(textView: textView)
49+
let rangeProvider = VisibleRangeProvider(textView: textView, minimapView: nil)
5050
let originalSet = rangeProvider.visibleSet
5151

5252
textView.setFrameSize(NSSize(width: 350, height: 450))

Tests/CodeEditSourceEditorTests/Mock.swift

+1
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ enum Mock {
129129
) -> Highlighter {
130130
Highlighter(
131131
textView: textView,
132+
minimapView: nil,
132133
providers: highlightProviders,
133134
attributeProvider: attributeProvider,
134135
language: language

0 commit comments

Comments
 (0)