Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
cb422bb
Render A Minimap
thecoolwinter Apr 11, 2025
17035f6
Correctly Wrap Lines, Render Line Breaks, Add to ScrollView
thecoolwinter Apr 11, 2025
39867e9
Merge branch 'main' into feat/minimap
thecoolwinter Apr 11, 2025
a8928ed
Start on Scrolling Offset
thecoolwinter Apr 14, 2025
a08aee6
Merge branch 'main' into feat/minimap
thecoolwinter Apr 14, 2025
95e0b91
Scroll Syncing Done!
thecoolwinter Apr 15, 2025
6cf5e5f
Move to Under Scroller, Performance Improvements
thecoolwinter Apr 16, 2025
ef2f8f0
Make Scroller on Top, Utilize Content Insets
thecoolwinter Apr 16, 2025
b7f341f
Overscroll, Finalize Mouse Interaction, Document Everything
thecoolwinter Apr 16, 2025
b5c4f8a
Draw Selections
thecoolwinter Apr 17, 2025
da173ae
Small Bugfix with Selection Drawing
thecoolwinter Apr 17, 2025
98808d5
Toggle Minimap
thecoolwinter Apr 17, 2025
306eed3
Merge branch 'main' into feat/minimap
thecoolwinter Apr 17, 2025
8976e1f
Docs & Linter
thecoolwinter Apr 17, 2025
ffdb740
Fix More Scrolling Edge Cases
thecoolwinter Apr 17, 2025
d6fd1eb
Accidental Blue!
thecoolwinter Apr 17, 2025
00bcea1
Update Positions On Layout, Linting Fixes
thecoolwinter Apr 17, 2025
2fdbed0
Layout on WillAppear
thecoolwinter Apr 18, 2025
4f4de36
Correctly Call Layout
thecoolwinter Apr 18, 2025
58030bb
Docs, Tests
thecoolwinter Apr 18, 2025
fa69a42
Update MinimapView.swift
thecoolwinter Apr 18, 2025
2ca5b03
Highlight Minimap Visible Region
thecoolwinter Apr 18, 2025
3a7fc91
Merge branch 'main' into fix/highlighter-highlight-minimap-viewport
thecoolwinter Apr 21, 2025
f84962f
Optional MinimapView Parameter
thecoolwinter Apr 21, 2025
7ac3c0f
Delete Toolbar.swift
thecoolwinter Apr 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ extension TextViewController {

let highlighter = Highlighter(
textView: textView,
minimapView: minimapView,
providers: highlightProviders,
attributeProvider: self,
language: language
Expand Down
5 changes: 3 additions & 2 deletions Sources/CodeEditSourceEditor/Highlighting/Highlighter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class Highlighter: NSObject {

init(
textView: TextView,
minimapView: MinimapView?,
providers: [HighlightProviding],
attributeProvider: ThemeAttributesProviding,
language: CodeLanguage
Expand All @@ -93,7 +94,7 @@ class Highlighter: NSObject {
self.textView = textView
self.attributeProvider = attributeProvider

self.visibleRangeProvider = VisibleRangeProvider(textView: textView)
self.visibleRangeProvider = VisibleRangeProvider(textView: textView, minimapView: minimapView)

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

visibleRangeProvider.updateVisibleSet(textView: textView)
visibleRangeProvider.visibleTextChanged()

let providerRange = NSRange(location: editedRange.location, length: editedRange.length - delta)
highlightProviders.forEach { $0.storageDidUpdate(range: providerRange, delta: delta) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ protocol VisibleRangeProviderDelegate: AnyObject {
@MainActor
class VisibleRangeProvider {
private weak var textView: TextView?
private weak var minimapView: MinimapView?
weak var delegate: VisibleRangeProviderDelegate?

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

init(textView: TextView) {
init(textView: TextView, minimapView: MinimapView?) {
self.textView = textView
self.minimapView = minimapView

if let scrollView = textView.enclosingScrollView {
NotificationCenter.default.addObserver(
self,
selector: #selector(visibleTextChanged(_:)),
selector: #selector(visibleTextChanged),
name: NSView.frameDidChangeNotification,
object: scrollView
)

NotificationCenter.default.addObserver(
self,
selector: #selector(visibleTextChanged(_:)),
selector: #selector(visibleTextChanged),
name: NSView.boundsDidChangeNotification,
object: scrollView.contentView
)
} else {
NotificationCenter.default.addObserver(
self,
selector: #selector(visibleTextChanged(_:)),
name: NSView.frameDidChangeNotification,
object: textView
)
}
}

func updateVisibleSet(textView: TextView) {
if let newVisibleRange = textView.visibleTextRange {
visibleSet = IndexSet(integersIn: newVisibleRange)
}
NotificationCenter.default.addObserver(
self,
selector: #selector(visibleTextChanged),
name: NSView.frameDidChangeNotification,
object: textView
)
}

/// Updates the view to highlight newly visible text when the textview is scrolled or bounds change.
@objc func visibleTextChanged(_ notification: Notification) {
let textView: TextView
if let clipView = notification.object as? NSClipView,
let documentView = clipView.enclosingScrollView?.documentView as? TextView {
textView = documentView
} else if let scrollView = notification.object as? NSScrollView,
let documentView = scrollView.documentView as? TextView {
textView = documentView
} else if let documentView = notification.object as? TextView {
textView = documentView
} else {
@objc func visibleTextChanged() {
guard let textViewVisibleRange = textView?.visibleTextRange else {
return
}

updateVisibleSet(textView: textView)

var visibleSet = IndexSet(integersIn: textViewVisibleRange)
if !(minimapView?.isHidden ?? true), let minimapVisibleRange = minimapView?.visibleTextRange {
visibleSet.formUnion(IndexSet(integersIn: minimapVisibleRange))
}
self.visibleSet = visibleSet
delegate?.visibleSetDidUpdate(visibleSet)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ final class HighlightProviderStateTest: XCTestCase {
override func setUp() async throws {
try await super.setUp()
textView = Mock.textView()
rangeProvider = MockVisibleRangeProvider(textView: textView)
rangeProvider = MockVisibleRangeProvider(textView: textView, minimapView: nil)
delegate = EmptyHighlightProviderStateDelegate()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ final class VisibleRangeProviderTests: XCTestCase {
textView.string = Array(repeating: "\n", count: 400).joined()
textView.layout()

let rangeProvider = VisibleRangeProvider(textView: textView)
let rangeProvider = VisibleRangeProvider(textView: textView, minimapView: nil)
let originalSet = rangeProvider.visibleSet

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

let rangeProvider = VisibleRangeProvider(textView: textView)
let rangeProvider = VisibleRangeProvider(textView: textView, minimapView: nil)
let originalSet = rangeProvider.visibleSet

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

let rangeProvider = VisibleRangeProvider(textView: textView)
let rangeProvider = VisibleRangeProvider(textView: textView, minimapView: nil)
let originalSet = rangeProvider.visibleSet

textView.setFrameSize(NSSize(width: 350, height: 450))
Expand Down
1 change: 1 addition & 0 deletions Tests/CodeEditSourceEditorTests/Mock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ enum Mock {
) -> Highlighter {
Highlighter(
textView: textView,
minimapView: nil,
providers: highlightProviders,
attributeProvider: attributeProvider,
language: language
Expand Down