Skip to content

Commit 7d2412c

Browse files
General Performance Improvements (#24)
1 parent e4d4853 commit 7d2412c

File tree

5 files changed

+27
-13
lines changed

5 files changed

+27
-13
lines changed

Sources/CodeEditTextView/Cursors/CursorView.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ open class CursorView: NSView {
2525
true
2626
}
2727

28+
override open func hitTest(_ point: NSPoint) -> NSView? { nil }
29+
2830
/// Create a cursor view.
2931
/// - Parameters:
3032
/// - blinkDuration: The duration to blink, leave as nil to never blink.

Sources/CodeEditTextView/TextLayoutManager/TextLayoutManager.swift

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,17 @@ public class TextLayoutManager: NSObject {
5454
}
5555
}
5656

57+
/// The amount of extra vertical padding used to lay out lines in before they come into view.
58+
///
59+
/// This solves a small problem with layout performance, if you're seeing layout lagging behind while scrolling,
60+
/// adjusting this value higher may help fix that.
61+
/// Defaults to `350`.
62+
public var verticalLayoutPadding: CGFloat = 350 {
63+
didSet {
64+
setNeedsLayout()
65+
}
66+
}
67+
5768
// MARK: - Internal
5869

5970
weak var textStorage: NSTextStorage?
@@ -215,10 +226,12 @@ public class TextLayoutManager: NSObject {
215226
}
216227

217228
/// Ends a transaction. When called, the layout manager will layout any necessary lines.
218-
public func endTransaction() {
229+
public func endTransaction(forceLayout: Bool = false) {
219230
transactionCounter -= 1
220231
if transactionCounter == 0 {
221-
setNeedsLayout()
232+
if forceLayout {
233+
setNeedsLayout()
234+
}
222235
layoutLines()
223236
} else if transactionCounter < 0 {
224237
// swiftlint:disable:next line_length
@@ -237,8 +250,8 @@ public class TextLayoutManager: NSObject {
237250
return
238251
}
239252
CATransaction.begin()
240-
let minY = max(visibleRect.minY, 0)
241-
let maxY = max(visibleRect.maxY, 0)
253+
let minY = max(visibleRect.minY - verticalLayoutPadding, 0)
254+
let maxY = max(visibleRect.maxY + verticalLayoutPadding, 0)
242255
let originalHeight = lineStorage.height
243256
var usedFragmentIDs = Set<UUID>()
244257
var forceLayout: Bool = needsLayout
@@ -283,6 +296,8 @@ public class TextLayoutManager: NSObject {
283296
newVisibleLines.insert(linePosition.data.id)
284297
}
285298

299+
CATransaction.commit()
300+
286301
// Enqueue any lines not used in this layout pass.
287302
viewReuseQueue.enqueueViews(notInSet: usedFragmentIDs)
288303

@@ -302,7 +317,6 @@ public class TextLayoutManager: NSObject {
302317
}
303318

304319
needsLayout = false
305-
CATransaction.commit()
306320
}
307321

308322
/// Lays out a single text line.

Sources/CodeEditTextView/TextLine/LineFragmentView.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ final class LineFragmentView: NSView {
2020
false
2121
}
2222

23+
override func hitTest(_ point: NSPoint) -> NSView? { nil }
24+
2325
/// Prepare the view for reuse, clears the line fragment reference.
2426
override func prepareForReuse() {
2527
super.prepareForReuse()

Sources/CodeEditTextView/TextView/TextView.swift

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -381,15 +381,11 @@ public class TextView: NSView, NSTextContent {
381381
/// - Parameter point: The point to find.
382382
/// - Returns: A view at the given point, if any.
383383
override public func hitTest(_ point: NSPoint) -> NSView? {
384-
// For our purposes, cursor and line fragment views should be transparent from the point of view of
385-
// all other views. So, if the normal hitTest returns one of them, we return `self` instead.
386-
let hitView = super.hitTest(point)
387-
388-
if let hitView, hitView != self,
389-
type(of: hitView) == CursorView.self || type(of: hitView) == LineFragmentView.self {
384+
if visibleRect.contains(point) {
390385
return self
386+
} else {
387+
return super.hitTest(point)
391388
}
392-
return hitView
393389
}
394390

395391
// MARK: - Key Down

Sources/CodeEditTextView/Utils/ViewReuseQueue.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public class ViewReuseQueue<View: NSView, Key: Hashable> {
5252
/// Enqueues all views not in the given set.
5353
/// - Parameter outsideSet: The keys who's views should not be enqueued for reuse.
5454
public func enqueueViews(notInSet keys: Set<Key>) {
55-
// Get all keys that are in "use" but not in the given set.
55+
// Get all keys that are currently in "use" but not in the given set, and enqueue them for reuse.
5656
for key in Set(usedViews.keys).subtracting(keys) {
5757
enqueueView(forKey: key)
5858
}

0 commit comments

Comments
 (0)