Hi,
I'm interested in creating a font with alternate glyphs that are accessed via Unicode variation selectors, but I'm getting the impression that macOS does not really support these, generally. For example, I'm unable to enter the variation selectors (other than U+FE0F) into a document in Pages or TextEdit using Unicode Hex Input. Is my hunch correct?
I'm interested in using the standardized variations listed here:
http://unicode.org/Public/UNIDATA/StandardizedVariants.txt
Specifically, slashed zero:
0030 FE00; short diagonal stroke form; # DIGIT ZERO
Thanks for any insight you may be able to provide.
TextKit
RSS for tagManage text storage and perform custom layout of text-based content in your app's views using TextKit.
Posts under TextKit tag
45 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
How do you get the cursor to appear programmatically in a custom UITextInput with UITextInteraction?
I have created a custom input field by conforming to UITextInput. It is setup to use UITextInteraction. Everything works very well. If the user taps on the custom field, the cursor (provided by UITextInteraction) appears. The user can type, select, move the cursor, etc.
But I'm stumped trying to get the cursor to appear automatically. With a normal UITextField or UITextView you simply call becomeFirstResponder(). But doing that with my custom UITextInput does not result in the cursor appearing. It only appears if the user taps on the custom field.
I don't know what I'm missing. I don't see any API in UITextInteraction that can be called to say "activate the cursor layer".
Does anyone know what steps are required with a custom UITextInput using UITextInteraction to activate the cursor programmatically without the user needing to tap on the custom field?
Starting with the macOS version 14.x.x and TextKit1, selecting multiple lines of text triggers a text replacement bug: some of the text on one of the selected lines inadvertently replaces a portion of the selected text.
For example, the bug is exhibited when selecting the following lines:
Carnaroli, Maratelli, or Vialone Nano are best
Vialone Nano cooks quickly – watch it! It also absorbs condiments nicely.
Avoid Baldo, Originario, Ribe and Roma
To trigger the bug, select the three line paragraph using either the cursor or shift with arrow keys. Notice that a portion of the selected text was replaced. Command-Z to undo will allow you to repeat the undesired behavior.
In this case, "e Nano cooks quickly - " is replaced by "Baldo, Originario, Ribe."
This does not occur with all strings or selected strings, but in cases where it does occur, it is perfectly reproducible. It does not occur on iOS. Pasteboard contents are irrelevant. After triggering the bug repeatedly, at some point it stops occurring.
Why does this bug occur? How can it be fixed?
Here is some sample code to reproduce the issue.
@end
@implementation TestNoteViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self createTextView];
}
- (void)createTextView {
NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:self.note.text
attributes:nil];
NSTextStorage *textStorage = [NSTextStorage new];
[textStorage appendAttributedString:attrString];
CGRect newTextViewRect = self.view.bounds;
// Create the layout manager
NSLayoutManager *layoutManager = [NSLayoutManager new];
[textStorage addLayoutManager:layoutManager];
// Create a text container
NSTextContainer *container = [[NSTextContainer alloc] initWithSize:CGSizeMake(newTextViewRect.size.width, CGFLOAT_MAX)];
[layoutManager addTextContainer:container];
// Create and place a text view
UITextView *textView = [[UITextView alloc] initWithFrame:newTextViewRect
textContainer:container];
[self.view addSubview:textView];
textView.translatesAutoresizingMaskIntoConstraints = NO;
UILayoutGuide *safeArea = textView.superview.safeAreaLayoutGuide;
[textView.leadingAnchor constraintEqualToAnchor:safeArea.leadingAnchor].active = YES;
[textView.trailingAnchor constraintEqualToAnchor:safeArea.trailingAnchor].active = YES;
[textView.topAnchor constraintEqualToAnchor:safeArea.topAnchor].active = YES;
[textView.bottomAnchor constraintEqualToAnchor:textView.superview.bottomAnchor].active = YES;
}
@end
In TextKit 1 we have the method NSTextStorage.addLayoutManager(_:) that allows to show the same text in multiple text views. This method exists with NSLayoutManager but not with NsTextLayoutManager.
Is there a way to achieve the same thing with TextKit 2?
I've been struggling with this for a while now. To start off with, I am using a custom NSTextLocation as the element range on a NSTextParagraph. NSTextParagraph is a subclass of NSTextElement and both have limited public elements that can be set. From what I can see, the only thing we can set on NSTextParagraph is an NSAttributedString. It has a few other elements it inherits from NSTextElement - primarily textContentManager and elementRange. Seems simple enough...but, there is obviously something wrong with what I am doing.
If we use NSTextStorage as our backing store, then the text ranges it uses is a private type NSCountableTextLocation. Being a private type, I imagine we have to implement our own NSTextLocation to use in the ranges that are set on the NSTextElement.
But, for some reason, when I have multiple text elements, TextKit compares my custom NSTextLocation against a NSCountableTextLocation and crashes.
-[NSCountableTextLocation compare:] receiving unmatching type (3, 1)
(3,1) here being the debug description text of my custom text location (represented by line number and column). I am at a complete loss as to why this is being triggered. I have implemented isEqual, Comparable and compare: on my custom implementation.
Going with the following Text
"""
First
Second
T
"""
I create a NSTextParagraph for each paragraph. So, I have elements
'First\n' - with range (1,1) - (2,1) - length of this range is 6
'\n' - with range (2,1) - (3,1) - length of this range is 1
'Second\n' with range (3,1) - (4,1) with length being 7
'\n' - range (4,1) - (5,1) with length 1
'T' - range (5,1) - (5,2) length 1
This bit renders and lays out fine. If I append a character at the last location, I get the exception and crash.
"""
First
Second
Th
"""
Exception being -[NSCountableTextLocation compare:] receiving unmatching type (3, 1)
The number of text elements and the equivalent lengths match what I would get with NSTextStorage (executed in a different playground). There are a few subtle differences I see when debugging with lldb. When I use NSTextStorage, the value of _attributedString on NSTextParagraph of the first text element (and all) is "First\n\nSecond\n\nTh" - essentially the full text. The value of attributedString is "First\n" essentially the range of text that matches the paragraph. The generated text layout fragment has the correct line fragment "First\n" and not the full text. I don't see a public way to setup the NSTextParagraph this way (nor am I able to do it correctly using setValue:forKey either). I don't know if this difference really matters.
So, my questions really are
Does NSTextParagraph support custom NSTextLocation? If so, how do we set it up correctly?
If not, do we subclass NSTextElement and do the layout ourselves?
I have a full minimal project that reproduces this at https://github.com/georgemp/TextLocationCrash but it's a bit of an involved read :-)
I have also filed reports using Feedback Assistant FB13547274
P.S. This crash only seems to occur on Sonoma (not on Monterrey or Ventura)
P.P.S - Thank you for getting this far in this lengthy read :-)
This WWDC video (https://developer.apple.com/videos/play/wwdc2022/10090/) shows using NSTextList in TextKit 2 on both iOS and macOS to create bulleted lists in UITextView and NSTextView, respectively. The sample code still works on iOS, but doesn't work on macOS
Here's a screenshot from the wwdc talk:
Here's the same sample code running on macOS 14.3:
Anyone know how to make NSTextList work on macOS 14? Is this a regression, did something change with the api, or has the functionality been removed?
Because my MacOS app has a user-programmable interface, my coding creates lots of interface elements programmatically. Soon after an update to MacOS 14.3.1, I found some of these element (NSTextFields) did not draw correctly. I had not changed any code but the appearance changed for the worse (the text in the text field did not appear).
I then noticed:
The problem occurs when I compile in XCode 15.2 (15C500b) Version and run on computer with Sonoma 14.3.1 (23D60)
If I instead compile in XCode Version 14.1 (14B47b) on Ventura 13.0.1 (22A400) and copy the app to my computer with Sonoma 14.3.1 (23D60)all works as expected.
These results seem to imply XCode 15.2 does not compile correctly? Is this known issue or is there a fix?
I'm trying to render a UIView to PDF, while maintaining text elements as actual text and not rasterizing them.
I'm using TextKit 2 backed UITextView and NSTextLayoutManager to provide the contents. However, no matter what I do, UITextView gets rasterized into a bitmap.
Here's the basic code:
let renderer = UIGraphicsPDFRenderer(bounds: pageRect, format: format)
let data = renderer.pdfData { (context) in
for page in self.pageViews {
context.beginPage()
let cgContext = context.cgContext
page.layer.render(in: cgContext)
}
}
A page view usually contains one UITextView, which uses somewhat advanced layout, so unfortunately I can't just toss it into a single NSAttributedString and draw into a CoreText context.
There's a hack to get UILabels to render themselves as non-rasterized text, and if I understand correctly, it works by just actually drawing them on the current context.
Interestingly, when providing UILabel view via NSTextAttachmentViewProvider to a text view using TextKit 2, the UILabels inside a text view won't get rasterized. In the image below, the paragraph is a bitmap, while the heading is real text.
This hinted that the actual text fragments are the ones that get rasterized when drawing, not the whole view, and I was right.
I can enumerate the text fragments and draw them directly on the context, which makes them remain as text rather than become a bitmap:
page.textView?.textLayoutManager?.enumerateTextLayoutFragments(from: location, options: [.ensuresLayout, .estimatesSize, .ensuresExtraLineFragment], using: { fragment in
let frame = fragment.layoutFragmentFrame
fragment.draw(at: frame.origin, in: cgContext)
return true
})
This causes other issues, because layout coordinates will be all over the place and not confined to the text view itself (and even more so for my custom NSTextLayoutFragment class). I can get around this, but my text attachments won't get drawn this way either, but display a skewed placeholder icon:
I can render them correctly on the context manually:
if fragment.textAttachmentViewProviders.count > 0 {
if let view = fragment.textAttachmentViewProviders.first?.view {
view.layer.render(in: cgContext)
return true
}
}
This renders them at 0, 0 though.
Edit: Changing bounds or frame for view/layer has no effect.
I'm wondering if there is a way to make UITextView and NSTextLayoutManager to draw their contents this way automatically, so the fragments would remain as text in the PDF, rather than become a bitmap? It seems weird that the text view doesn't do this by default like it does on macOS, especially as it appears to be entirely possible.
Or, if that's not possible, what's the correct way of drawing my text attachments when enumerating NSTextLayoutFragments?
Hi,
I have used some custom Arabic fonts in UITextView to render some Arabic fonts.
On iOS 17 the following code is not giving me the correct position of the tapped text in some special cases.
Following the code i am using with the TapGestureRecognizer.
@objc func arabicTextViewTapped(_ sender: UITapGestureRecognizer) {
let attributedString = NSMutableAttributedString(attributedString: arabicTextView.attributedText)
attributedString.removeAttribute(.backgroundColor, range: NSRange(location: 0, length: attributedString.length))
let touchPosition = sender.location(in: sender.view)
guard let textPosition = arabicTextView.closestPosition(to: touchPosition),
let textRange = arabicTextView.tokenizer
.rangeEnclosingPosition(textPosition, with: .word, inDirection: .init(rawValue: 1)) else { return }
guard let text = arabicTextView.text(in: textRange) else { return }
}
In the image below
if there is some special character (called Ramos e aukaf) as the first character (which in this case is the small first character on the second line) then this code gives the position on the first line.
guard let textPosition = arabicTextView.closestPosition(to: touchPosition)
In the below case, the above code works perfectly fine as small character is not the first character on the second line. Also this is only happening on ios 17.
Any help is highly appriciated.
I'm having an issue with a TextKit2 NSTextView (AppKit). In my subclass's keyDown, I'm doing a bit of manipulation of the textStorage but it seems that if I try to alter any part of the textStorage where a text paragraph and accompanying fragment have already been created, I then get duplicate paragraphs and fragments.
For example, say I want to insert new text at the end of an existing paragraph. I've tried:
Inserting a new attr string (with attrs matching the preceding text) at the end of the existing paragraph text
Replacing the existing paragraph text with a new attr string that includes the new text
First deleting the existing paragraph text and then inserting the new full attr string including the new text
I am wrapping those edits in a textContentStorage.performEditingTransaction closure.
But in all cases, it seems that TextKit 2 wants to create new NSTextParagraph and NSTextFragment objects and doesn't remove the old ones, resulting in duplicate elements in my UI.
Some sample code:
let editLocation = editRange.location
guard editLocation > 0 else {
break
}
let attrs = textStorage.attributes(at: editLocation, effectiveRange: nil)
// paragraphStartLocation is in an NSAttributedString extension not shown
guard let paragraphStartLoc = textStorage.paragraphStartLocation(from: editLocation) else {
assertionFailure(); return
}
var paragraphRange = NSRange(location: paragraphStartLoc, length: editLocation - paragraphStartLoc + 1)
var fullParagraph = textStorage.attributedSubstring(from: paragraphRange).string
fullParagraph += newText
let newAttrStr = NSAttributedString(string: fullParagraph, attributes: attrs)
textContentStorage.performEditingTransaction {
textStorage.deleteCharacters(in: paragraphRange)
textStorage.insert(newAttrStr, at: paragraphStartLoc)
}
I'm using UITextView.
I set its background color to .white.
Initially, the UITextView appears with a white background color.
However, after I click on the UITextView, a cursor appears and the background color changes to .systemBackground.
I am unable to change this background color by any means.
Basic HTML strings do not display correctly on macOS Sonoma, I am wondering if there is an alternative technique that can be utilized. There was a minor change in macOS 14.2, which fixed some cases but made others much worse.
Consider the following code:
override func viewDidLoad() {
super.viewDidLoad()
let html = """
<table width="100%" border="1" style="color: white">
<tr>
<td align="left">Left</td>
<td align="right">Right</td>
</tr>
</table>
"""
let data = Data(html.utf8)
let definition = try! NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: NSNumber(value: String.Encoding.utf8.rawValue)], documentAttributes: nil)
let frameRect = NSRect(x: 100, y: 0, width: 300, height: 200)
let textView = NSTextView(frame: frameRect)
textView.textStorage?.setAttributedString(definition)
textView.backgroundColor = .clear
view.addSubview(textView)
}
On macOS 14 (23A5312d) it looks like this (FB13170237):
On macOS 14.2 (23C64) it looks like this (FB13465833):
If I use -[NSView dataWithPDFInsideRect:] to create a PDF from an NSTextView, I get a single-page PDF with stuff past the bottom cut off. What do I need to do to get pagination to happen? Would embedding the NSTextView in an NSScrollView help?
With my continued experiments with TextKit2, I'm trying to figure out what sets the properties paragraphSeparatorRange and paragraphContentRange on a NSTextParagraph. These seem to be computed properties (or at least they cannot be directly set via public API).
var paragraph = NSTextParagraph(attributedString: NSAttributedString(string: "It was the best of times.\n"))
print("attributes: \(paragraph.attributedString.attributes(at: 0, effectiveRange: nil))")
print("paragraphSeparatorRange: \(String(describing: paragraph.paragraphSeparatorRange))")
print("paragraphContentRange: \(String(describing: paragraph.paragraphContentRange))")
In the above example, both paragraphSeparatorRange and paragraphContentRange are nil.
However, when using NSTextLayoutManager/NSTextContentStorage they are set.
let layoutManager = NSTextLayoutManager()
let container = NSTextContainer(size: NSSize(width: 400, height: 400))
layoutManager.textContainer = container
let contentStorage = NSTextContentStorage()
contentStorage.textStorage = NSTextStorage(string: "It was the best of times.\n")
contentStorage.addTextLayoutManager(layoutManager)
layoutManager.enumerateTextLayoutFragments(from: contentStorage.documentRange.location, options: .ensuresLayout) { textLayoutFragment in
print("layoutFragment: \(textLayoutFragment)")
print("textElement: \(String(describing: textLayoutFragment.textElement))")
print("textElement.range: \(String(describing: textLayoutFragment.textElement?.elementRange))")
let paragraph = textLayoutFragment.textElement as! NSTextParagraph
print("paragraphContentRange: \(String(describing: paragraph.paragraphContentRange))")
print("paragraphSeparatorRange: \(String(describing: paragraph.paragraphSeparatorRange))")
return true
}
Would appreciate any ideas on how these values are computed/set. Thanks
Hi,
I new in the Apple Development world using Apple Frameworks.
I already got familiar with SwiftUI and I can handle the Swift programming language. However, I need some guidance about what approach I should take to develop a Rich Text Editor for a personal App. I am working on.
I could build the Editor using any HTML & any JS Editor Framework like EditorJS. But I prefer to take the native Apple approach, if there is one framework that I can easily use to implement the following capabilities:
Text Styling
-. Present a paragraph, titles, and subtitle headers with a predefined font size and styles.
-. Bulleted and numbered lists
Indenting and out-denting of text
Formatting
-. Predefined Bold, italic, underline, code, strikethrough, sub- and super-scripting
Embedding
-. Images --> Framework ?
-. Iframes --> Framework ?
-. Videos --> Framework ?
-. Audio --> Framework ?
-. Tables and Predefined tables --> Framework ?
-. Links
-. Drawing canvas with Ipad Pencil --> PencilKit
-. PDF view and reviews. --> pdfKit.
-. Math formulas. --> Framework ?
-. Diagram and flow chart editing --> Framework ?
Any recommendation about what framework to use will be appreciated.
Thanks in advance.
I have an interesting challenge, but I do not know where to start.
given an NSTextView in an NSScrollView, and enough text in the textView to enable scrolling, how do you determine the location of a single word, and jump to it?
we see this sort of behavior in Find panels in Most text editors. So it can be done.
additionally, I would very much like to find some kind of predetermined... elements in the text. as a link or an image is not text but can be inline with the text (in Attributed strings) I would like to put an element in the text that is not text, but is targetable and capable of being tagged with some kind of reference. Almost like a bookmark, in which I can scroll to. I have determined that I could use URL Links. But they are so fragile.
I have a custom subclass to a NSTextContentManager which provides NSTextParagrahs for layout. However, when I have a trailing newline in my content string, the NSTextLayoutFragment does not have a empty NSTextLineFragment indicating a new line. This is in contrast to using the standard NSTextContentStorage. NSTextContentStorage also uses NSTextParagraphs to represent it's text elements.
The code I have for both scenarios are
Using Default NSTextContentStorage
let layoutManager = NSTextLayoutManager()
let container = NSTextContainer(size: NSSize(width: 400, height: 400))
layoutManager.textContainer = container
let contentStorage = NSTextContentStorage()
contentStorage.textStorage?.replaceCharacters(in: NSRange(location: 0, length: 0), with: "It was the best of times.\n")
contentStorage.addTextLayoutManager(layoutManager)
layoutManager.enumerateTextLayoutFragments(from: contentStorage.documentRange.location, options: .ensuresLayout) { textLayoutFragment in
print("defaultTextLineFragments:")
for (index, textLineFragment) in textLayoutFragment.textLineFragments.enumerated() {
print("\(index): \(textLineFragment)")
}
print("\n")
return true
}
This outputs
defaultTextLineFragments:
0: <NSTextLineFragment: 0x123815a80 "It was the best of times.
">
1: <NSTextLineFragment: 0x123825b00 "">
Using custom subclass to NSTextContentManager
class CustomTextLocation: NSObject, NSTextLocation {
let offset: Int
init(offset: Int) {
self.offset = offset
}
func compare(_ location: NSTextLocation) -> ComparisonResult {
guard let location = location as? CustomTextLocation else {
return .orderedAscending
}
if offset < location.offset {
return .orderedAscending
} else if offset > location.offset {
return .orderedDescending
} else {
return .orderedSame
}
}
}
class CustomStorage: NSTextContentManager {
let content = "It was the best of times.\n"
override var documentRange: NSTextRange {
NSTextRange(location: CustomTextLocation(offset: 0), end: CustomTextLocation(offset: content.utf8.count))!
}
override func textElements(for range: NSTextRange) -> [NSTextElement] {
let paragraph = NSTextParagraph(attributedString: NSAttributedString(string: content))
paragraph.textContentManager = self
paragraph.elementRange = documentRange
return [paragraph]
}
override func enumerateTextElements(from textLocation: NSTextLocation?, options: NSTextContentManager.EnumerationOptions = [], using block: (NSTextElement) -> Bool) -> NSTextLocation? {
// Just assuming static text elements for this example
let elements = self.textElements(for: documentRange)
for element in elements {
block(element)
}
return elements.last?.elementRange?.endLocation
}
override func location(_ location: NSTextLocation, offsetBy offset: Int) -> NSTextLocation? {
guard let location = location as? CustomTextLocation,
let documentEnd = documentRange.endLocation as? CustomTextLocation else {
return nil
}
let offset = CustomTextLocation(offset: location.offset + offset)
if offset.compare(documentEnd) == .orderedDescending {
return nil
}
return offset
}
override func offset(from: NSTextLocation, to: NSTextLocation) -> Int {
guard let from = from as? CustomTextLocation,
let to = to as? CustomTextLocation else {
return 0
}
return to.offset - from.offset
}
}
let customLayoutManager = NSTextLayoutManager()
let customContainer = NSTextContainer(size: NSSize(width: 400, height: 400))
customLayoutManager.textContainer = customContainer
let customStorage = CustomStorage()
customStorage.addTextLayoutManager(customLayoutManager)
customLayoutManager.enumerateTextLayoutFragments(from: customStorage.documentRange.location, options: .ensuresLayout) { textLayoutFragment in
print("customStorage textLineFragments:")
for (index, textLineFragment) in textLayoutFragment.textLineFragments.enumerated() {
print("\(index): \(textLineFragment)")
}
print("\n")
return true
}
This output
customStorage textLineFragments:
0: <NSTextLineFragment: 0x13ff0c8d0 "It was the best of times.
">
I am expecting the two outputs to match (as it's impacting my position calculations for carets during text entry). How would I go about getting the text layout manager to add the extra line fragment while using a custom NSTextContentManager
I have been getting crash reports from users of my Mac app on Sonoma 14.0 and 14.1 when typing into an NSTextView subclass. The crash logs I have show involvement of the spell-checking system - NSTestCheckingController, NSSpellChecker, and NSCorrectionPanel. The crash is because of an exception being thrown. The throwing method is either [NSString getParagraphStart:end:contentsEnd:forRange:] or [NSTextStorage ensureAttributesAreFixedInRange:].
I have not yet reproduced the crash. I have tried modifying the reference finding process to simply link every word, via NSStringEnumerationByWords.
The text view in question recognizes certain things in the entered text and adds hyperlinks to the text while the user is typing. It re-parses and re-adds the links on every key press (via overriding the didChangeText method), on a background thread.
From user reports, I have learned that:
The crash only occurs on macOS 14.0 and 14.1, not on previous versions
The call stack always involves the spell checker, and sometimes involves adding recognized links to the text storage (the call to DispatchQueue.main.async in the code below)
The crash stops happening if the user turns off the system spell checker in System Settings -> Keyboard -> Edit on an Input Source -> Correct Spelling Automatically switch
The crash does not happen when there are no links in the text view.
Here is the relevant code:
extension NSMutableAttributedString {
func batchUpdates(_ updates: () -> ()) {
self.beginEditing()
updates()
self.endEditing()
}
}
class MyTextView : NSTextView {
func didChangeText() {
super.didChangeText()
findReferences()
}
var parseToken: CancelationToken? = nil
let parseQueue = DispatchQueue(label: "com.myapp.ref_parser")
private func findReferences() {
guard let storage = self.textStorage else { return }
self.parseToken?.requestCancel()
let token = CancelationToken()
self.parseToken = token
let text = storage.string
self.parseQueue.async {
if token.cancelRequested { return }
let refs = RefParser.findReferences(inText: text, cancelationToken: token)
DispatchQueue.main.async {
if !token.cancelRequested {
storage.batchUpdates {
var linkRanges: [NSRange] = []
storage.enumerateAttribute(.link, in: NSRange(location: 0, length: storage.length)) { linkValue, linkRange, stop in
if let linkUrl = linkValue as? NSURL {
linkRanges.append(linkRange)
}
}
for rng in linkRanges {
storage.removeAttribute(.link, range: rng)
}
for r in refs {
storage.addAttribute(.link, value: r.url, range: r.range)
}
}
self.verseParseToken = nil
}
}
}
}
}
I've filed this as FB13306015 if any engineers see this. Can anyone
This is a tricky one. I have a shipping product which, when compiled under Xcode 14.3.1 works as expected on Sonoma.
If the same project is recompiled with Xcode 15, the subclass of NSTextView will not display correctly (text is same color as background).
I am also using a custom NSLayoutManager (to draw invisibles).
Unfortunately, there is an intermittent aspect to this. I use this subclass in several places and it works on my setup on the main editor, but not with some customers.
Then I found a different use of the same subclass that does not work for me.
When it does not work, it is consistent for that user.
I have manually marked the textViews as using TextKit 1, with no change.
I also tried the Clips Bounds to yes, again no change.
If I change the class to NSTextView, the text displays properly, but I lose existing functionality.
There appears to be some undocumented behavior change in Xcode 15 (or when linking against Sonoma SDK) that for subclasses of NSTextView (stored in XIB files). I know that there is a push to move toward TextKit 2, but it seems TextKit 1 support was possibly changed as well.
The text is there and I can edit it, double click, copy and paste it, it is just invisible, when compiled with Xcode 15 (also 15.1).
It has to be something very subtle that the subclassed TextView from one XIB will work, but from another XIB will not.
Does anyone have any insight into the potential change with TextKit 1 implementation?
Thanks.
This function on NSTextLayoutManager has the following signature
func enumerateTextSegments(
in textRange: NSTextRange,
type: NSTextLayoutManager.SegmentType,
options: NSTextLayoutManager.SegmentOptions = [],
using block: (NSTextRange?, CGRect, CGFloat, NSTextContainer) -> Bool
)
The documentation here doesn't define what the CGRect and CGFloat passed to block are. However, looking at sample code Using TextKit2 To Interact With Text, they seem to be the frame for the textsegment and baselineposition respectively.
But, the textSegmentFrame seems to start at origin.x = 5.0 when text is empty. Is this some starting offset for text segments? I don't seem to be able to find mention of this anywhere.