ChimeHQ/Glyph

Abstractions for working with TextKit 1 and 2

Swift

66

49 commits

updated Sep 21, 2026

See the code

README

Build Status Platforms Documentation

Glyph

Make life with TextKit better

Glyph adds features and abstractions for working with TextKit. Some are for performance, some for convenience. You don't even need to know whether your system using 1 or 2. Glyph will not downgrade TextKit 2 views. But, it can be awful nice to swap between 1 and 2 quickly when debugging.

Installation

dependencies: [
    .package(url: "https://github.com/ChimeHQ/Glyph", branch: "main")
],

Usage

NSTextContainer Additions

func characterIndexes(within rect: CGRect) -> IndexSet
func enumerateLineFragments(for rect: CGRect, strictIntersection: Bool, block: (CGRect, NSRange, inout Bool) -> Void)
func enumerateLineFragments(in range: NSRange, block: (CGRect, NSRange, inout Bool) -> Void)
func enumerateLineFragments(from index: Int, forward: Bool = true, block: (CGRect, NSRange, inout Bool) -> Void)
func lineFragment(for index: Int, offset: Int) -> (CGRect, NSRange)?
func boundingRect(for range: NSRange) -> CGRect?

NSTextLayoutManager Additions

func enumerateLineFragments(for rect: CGRect, strictIntersection: Bool = true, options: NSTextLayoutFragment.EnumerationOptions = [], block: (CGRect, NSRange, inout Bool) -> Void)
func enumerateLineFragments(in range: NSRange, options: NSTextLayoutFragment.EnumerationOptions = [], block: (CGRect, NSRange, inout Bool) -> Void)
func enumerateLineFragments(from index: Int, options: NSTextLayoutFragment.EnumerationOptions = [], block: (CGRect, NSRange, inout Bool) -> Void)
func boundingRect(for range: NSRange) -> CGRect? 

NSTextLayoutFragment Additions

func enumerateLineFragments(with provider: NSTextElementProvider, reverse: Bool = false, block: (NSTextLineFragment, CGRect, NSRange, Int) -> Bool)
func enumerateLineFragments(in range: NSRange, with provider: NSTextElementProvider, reverse: Bool = false, block: (NSTextLineFragment, CGRect, NSRange, Int) -> Bool)

NSTextView/UITextView Additions

func characterIndexes(within rect: CGRect) -> IndexSet
var visibleCharacterIndexes: IndexSet
func boundingRect(for range: NSRange) -> CGRect?

func setRenderingAttributes(_ attributes: [NSAttributedString.Key : Any], for range: NSRange)

NSRange and NSTextRange Additions

NSRange.init?(_ textRange: NSTextRange)
NSTextRange.init?(_ range: NSRange)

Contributing and Collaboration

I would love to hear from you! Issues or pull requests work great.

I prefer collaboration, and would love to find ways to work together if you have a similar project.

I prefer indentation with tabs for improved accessibility. But, I'd rather you use the system you want and make a PR than hesitate because of whitespace.

By participating in this project you agree to abide by the Contributor Code of Conduct.

nstextview
swift
textkit
textkit2
uitextview

Contributors

mattmassicotte

49 commits

ChimeHQ/Glyph

Abstractions for working with TextKit 1 and 2

Swift

66

49 commits

updated Sep 21, 2026

See the code

README

Build Status Platforms Documentation

Glyph

Make life with TextKit better

Glyph adds features and abstractions for working with TextKit. Some are for performance, some for convenience. You don't even need to know whether your system using 1 or 2. Glyph will not downgrade TextKit 2 views. But, it can be awful nice to swap between 1 and 2 quickly when debugging.

Installation

dependencies: [
    .package(url: "https://github.com/ChimeHQ/Glyph", branch: "main")
],

Usage

NSTextContainer Additions

func characterIndexes(within rect: CGRect) -> IndexSet
func enumerateLineFragments(for rect: CGRect, strictIntersection: Bool, block: (CGRect, NSRange, inout Bool) -> Void)
func enumerateLineFragments(in range: NSRange, block: (CGRect, NSRange, inout Bool) -> Void)
func enumerateLineFragments(from index: Int, forward: Bool = true, block: (CGRect, NSRange, inout Bool) -> Void)
func lineFragment(for index: Int, offset: Int) -> (CGRect, NSRange)?
func boundingRect(for range: NSRange) -> CGRect?

NSTextLayoutManager Additions

func enumerateLineFragments(for rect: CGRect, strictIntersection: Bool = true, options: NSTextLayoutFragment.EnumerationOptions = [], block: (CGRect, NSRange, inout Bool) -> Void)
func enumerateLineFragments(in range: NSRange, options: NSTextLayoutFragment.EnumerationOptions = [], block: (CGRect, NSRange, inout Bool) -> Void)
func enumerateLineFragments(from index: Int, options: NSTextLayoutFragment.EnumerationOptions = [], block: (CGRect, NSRange, inout Bool) -> Void)
func boundingRect(for range: NSRange) -> CGRect? 

NSTextLayoutFragment Additions

func enumerateLineFragments(with provider: NSTextElementProvider, reverse: Bool = false, block: (NSTextLineFragment, CGRect, NSRange, Int) -> Bool)
func enumerateLineFragments(in range: NSRange, with provider: NSTextElementProvider, reverse: Bool = false, block: (NSTextLineFragment, CGRect, NSRange, Int) -> Bool)

NSTextView/UITextView Additions

func characterIndexes(within rect: CGRect) -> IndexSet
var visibleCharacterIndexes: IndexSet
func boundingRect(for range: NSRange) -> CGRect?

func setRenderingAttributes(_ attributes: [NSAttributedString.Key : Any], for range: NSRange)

NSRange and NSTextRange Additions

NSRange.init?(_ textRange: NSTextRange)
NSTextRange.init?(_ range: NSRange)

Contributing and Collaboration

I would love to hear from you! Issues or pull requests work great.

I prefer collaboration, and would love to find ways to work together if you have a similar project.

I prefer indentation with tabs for improved accessibility. But, I'd rather you use the system you want and make a PR than hesitate because of whitespace.

By participating in this project you agree to abide by the Contributor Code of Conduct.

nstextview
swift
textkit
textkit2
uitextview

Contributors

mattmassicotte

49 commits

Languages

Swift

100.0%