@@ -522,19 +522,29 @@ public class TextView: NSView, NSTextContent {
522522
523523 /// Scrolls the upmost selection to the visible rect if `scrollView` is not `nil`.
524524 public func scrollSelectionToVisible( ) {
525- guard let scrollView,
526- let selection = selectionManager. textSelections
527- . sorted ( by: { $0. boundingRect. origin. y < $1. boundingRect. origin. y } ) . first else {
525+ guard let scrollView else {
528526 return
529527 }
528+
529+ // There's a bit of a chicken-and-the-egg issue going on here. We need to know the rect to scroll to, but we
530+ // can't know the exact rect to make visible without laying out the text. Then, once text is laid out the
531+ // selection rect may be different again. To solve this, we loop until the frame doesn't change after a layout
532+ // pass and scroll to that rect.
533+
530534 var lastFrame : CGRect = . zero
531- while lastFrame != selection. boundingRect {
535+ while let selection = selectionManager
536+ . textSelections
537+ . sorted ( by: { $0. boundingRect. origin. y < $1. boundingRect. origin. y } )
538+ . first,
539+ lastFrame != selection. boundingRect {
532540 lastFrame = selection. boundingRect
533541 layoutManager. layoutLines ( )
534542 selectionManager. updateSelectionViews ( )
535543 selectionManager. drawSelections ( in: visibleRect)
536544 }
537- scrollView. contentView. scrollToVisible ( lastFrame)
545+ if lastFrame != . zero {
546+ scrollView. contentView. scrollToVisible ( lastFrame)
547+ }
538548 }
539549
540550 deinit {
0 commit comments