diff --git a/Sources/Glyph/NSTextContainer+Additions.swift b/Sources/Glyph/NSTextContainer+Additions.swift index 7a1b416..2dc1980 100644 --- a/Sources/Glyph/NSTextContainer+Additions.swift +++ b/Sources/Glyph/NSTextContainer+Additions.swift @@ -85,16 +85,16 @@ extension NSTextContainer { public func lineFragment(for index: Int, offset: Int) -> (CGRect, NSRange)? { var fragment: (CGRect, NSRange)? let forward = offset >= 0 - var targetCount = abs(offset) + var count = abs(offset) enumerateLineFragments(from: index, forward: forward) { rect, range, stop in - if targetCount == 0 { + if count <= 0 { fragment = (rect, range) stop = true return } - targetCount -= 1 + count -= 1 } return fragment diff --git a/Sources/Glyph/NSTextLayoutManager+Additions.swift b/Sources/Glyph/NSTextLayoutManager+Additions.swift index 2e58d79..f540f92 100644 --- a/Sources/Glyph/NSTextLayoutManager+Additions.swift +++ b/Sources/Glyph/NSTextLayoutManager+Additions.swift @@ -69,6 +69,22 @@ extension NSTextLayoutManager { }) } + // the last index in the storage might not return a fragment, and the logic required + // to figure out which one should be in effect is atually quite complex + private func lastTextLayoutFragment() -> NSTextLayoutFragment? { + guard let textContentManager else { return nil } + + if let fragment = textLayoutFragment(for: documentRange.endLocation) { + return fragment + } + + guard let locBefore = textContentManager.location(documentRange.endLocation, offsetBy: -1) else { + return nil + } + + return textLayoutFragment(for: locBefore) + } + private func enumerateTextLineFragments( in range: NSRange, options: NSTextLayoutFragment.EnumerationOptions = [], @@ -84,6 +100,18 @@ extension NSTextLayoutManager { return } + if textContentManager.offset(from: start, to: documentRange.endLocation) == 0 { + guard let fragment = lastTextLayoutFragment() else { return } + + var stop = false + + fragment.enumerateLineFragments(with: textContentManager) { lineFragment, frame, elementRange in + block(fragment, lineFragment, frame, elementRange, &stop) + } + + return + } + enumerateTextLayoutFragments(from: start, options: options) { fragment in let fragmentRange = fragment.rangeInElement