Skip to content

Commit ffdb740

Browse files
committed
Fix More Scrolling Edge Cases
1 parent 8976e1f commit ffdb740

File tree

5 files changed

+35
-15
lines changed

5 files changed

+35
-15
lines changed

Sources/CodeEditSourceEditor/Controller/TextViewController.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,8 @@ public class TextViewController: NSViewController {
339339
styleGutterView()
340340

341341
highlighter?.invalidate()
342+
minimapView.updateContentViewHeight()
343+
minimapView.updateDocumentVisibleViewPosition()
342344
}
343345

344346
deinit {

Sources/CodeEditSourceEditor/Extensions/NSScrollView+percentScrolled.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88
import AppKit
99

1010
extension NSScrollView {
11+
/// The maximum `Y` value that can be scrolled to, as the origin of the `documentVisibleRect`.
1112
var documentMaxOriginY: CGFloat {
12-
let totalHeight = (documentView?.frame.height ?? 0.0) + contentInsets.top
13-
return totalHeight - (documentVisibleRect.height - contentInsets.top)
13+
let totalHeight = (documentView?.frame.height ?? 0.0) + contentInsets.vertical
14+
return totalHeight - documentVisibleRect.height
1415
}
1516

17+
/// The percent amount the scroll view has been scrolled. Measured as the available space that can be scrolled.
1618
var percentScrolled: CGFloat {
1719
let currentYPos = documentVisibleRect.origin.y + contentInsets.top
1820
return currentYPos / documentMaxOriginY

Sources/CodeEditSourceEditor/Minimap/MinimapView+DocumentVisibleView.swift

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,23 @@ extension MinimapView {
2929
}
3030

3131
let availableHeight = min(minimapHeight, containerHeight)
32+
let editorScrollViewVisibleRect = (
33+
editorScrollView.documentVisibleRect.height - editorScrollView.contentInsets.vertical
34+
)
3235
let scrollPercentage = editorScrollView.percentScrolled
3336
guard scrollPercentage.isFinite else { return }
3437

38+
let multiplier = if minimapHeight < containerHeight {
39+
editorScrollViewVisibleRect / textView.frame.height
40+
} else {
41+
editorToMinimapHeightRatio
42+
}
43+
3544
// Update Visible Pane, should scroll down slowly as the user scrolls the document, following a similar pace
3645
// as the vertical `NSScroller`.
37-
// Visible pane's height = scrollview visible height * (minimap line height / editor line height)
46+
// Visible pane's height = visible height * multiplier
3847
// Visible pane's position = (container height - visible pane height) * scrollPercentage
39-
let visibleRectHeight = containerHeight * editorToMinimapHeightRatio
48+
let visibleRectHeight = availableHeight * multiplier
4049
guard visibleRectHeight < 1e100 else { return }
4150

4251
let availableContainerHeight = (availableHeight - visibleRectHeight)
@@ -54,14 +63,13 @@ extension MinimapView {
5463
}
5564

5665
private func setScrollViewPosition(scrollPercentage: CGFloat) {
57-
let topInsets = scrollView.contentInsets.top
58-
let totalHeight = contentView.frame.height + topInsets
66+
let totalHeight = contentView.frame.height + scrollView.contentInsets.vertical
67+
let visibleHeight = scrollView.documentVisibleRect.height
68+
let yPos = (totalHeight - visibleHeight) * scrollPercentage
5969
scrollView.contentView.scroll(
6070
to: NSPoint(
6171
x: scrollView.contentView.frame.origin.x,
62-
y: (
63-
scrollPercentage * (totalHeight - (scrollView.documentVisibleRect.height - topInsets))
64-
) - topInsets
72+
y: yPos - scrollView.contentInsets.top
6573
)
6674
)
6775
scrollView.reflectScrolledClipView(scrollView.contentView)

Sources/CodeEditSourceEditor/Minimap/MinimapView+DragVisibleView.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ extension MinimapView {
2929
// Minimum Y value is the top of the scroll view
3030
newScrollViewY = max(-editorScrollView.contentInsets.top, newScrollViewY)
3131
newScrollViewY = min( // Max y value needs to take into account the editor overscroll
32-
editorScrollView.documentMaxOriginY
33-
- editorScrollView.contentInsets.top
34-
+ editorScrollView.contentInsets.bottom,
32+
editorScrollView.documentMaxOriginY - editorScrollView.contentInsets.top, // Relative to the content's top
3533
newScrollViewY
3634
)
3735

Sources/CodeEditSourceEditor/Minimap/MinimapView.swift

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ public class MinimapView: FlippedNSView {
8585

8686
self.contentView = MinimapContentView()
8787
contentView.translatesAutoresizingMaskIntoConstraints = false
88+
contentView.wantsLayer = true
89+
contentView.layer?.borderWidth = 1.0
90+
contentView.layer?.borderColor = NSColor.blue.cgColor
8891

8992
self.documentVisibleView = NSView()
9093
documentVisibleView.translatesAutoresizingMaskIntoConstraints = false
@@ -153,6 +156,7 @@ public class MinimapView: FlippedNSView {
153156
textView: textView,
154157
delegate: self
155158
)
159+
selectionManager?.insertionPointColor = .clear
156160
contentView.textView = textView
157161
contentView.selectionManager = selectionManager
158162
}
@@ -226,9 +230,14 @@ public class MinimapView: FlippedNSView {
226230
fatalError("init(coder:) has not been implemented")
227231
}
228232

233+
deinit {
234+
NotificationCenter.default.removeObserver(self)
235+
}
236+
229237
override public var visibleRect: NSRect {
230238
var rect = scrollView.documentVisibleRect
231239
rect.origin.y += scrollView.contentInsets.top
240+
rect.size.height -= scrollView.contentInsets.vertical
232241
return rect.pixelAligned
233242
}
234243

@@ -264,14 +273,15 @@ public class MinimapView: FlippedNSView {
264273
/// cached height.
265274
func updateContentViewHeight() {
266275
guard let estimatedContentHeight = layoutManager?.estimatedHeight(),
267-
let overscrollAmount = textView?.overscrollAmount else {
276+
let editorEstimatedHeight = textView?.layoutManager.estimatedHeight() else {
268277
return
269278
}
270-
let overscroll = containerHeight * overscrollAmount * editorToMinimapHeightRatio
279+
let overscrollAmount = textView?.overscrollAmount ?? 0.0
280+
let overscroll = containerHeight * overscrollAmount * (estimatedContentHeight / editorEstimatedHeight)
271281
let height = estimatedContentHeight + overscroll
272282

273283
// Only update a frame if needed
274-
if contentView.frame.height != height {
284+
if contentView.frame.height != height && height.isFinite && height < (textView?.frame.height ?? 0.0) {
275285
contentView.frame.size.height = height
276286
}
277287
}

0 commit comments

Comments
 (0)