Martin, Ecir, and Quincey:
Thank you all! All three answers turned out to be helpful. (Quincey, you led me
to learn about how to get attributed substrings, should I ever need to do it.)
Martin, your chief difference from my code seems be calling the layout
manager’s ensureGlyphsForCharacterRange: in order to synch up the layout
manager with the current content of text storage. I took that and ran with it.
Here is the resulting code that works for me, which I donate to the public
domain in case anyone else finds it useful.
The methods below are found in a subclass of NSTextView:
/// Set temporary foreground color for special characters in the given range
-(void)setTemporaryForegroundColor:(NSColor*)color
forSpecialCharacters:(NSCharacterSet*)characterSet
inRange:(NSRange)range
{
HighlightInfo* hi = [[HighlightInfo alloc] initWithColor:color
characterSet:characterSet
range:range];
// If we don't delay for a half-second, Apple's Smart Quotes stop working.
// I think this is a bug: why should altering temporary attributes lock out
substitution?
static double smartQuoteDelay = 0.5;
[self performSelector:@selector(setTemporaryForegroundColor:)
withObject:hi
afterDelay:smartQuoteDelay];
}
/// Set temporary foreground color according to information passed in
HighlightInfo
/// @attention Keep this private and always call via
performSelector:withObject:afterDelay:
-(void)setTemporaryForegroundColor:(HighlightInfo*)hi
{
NSLayoutManager* lm = self.layoutManager;
NSTextStorage* ts = self.textStorage;
NSRange searchRange = hi.range;
NSUInteger beyondIx = searchRange.location + searchRange.length;
// Synchronize layoutManager with textStorage: otherwise temp attribute
ranges don't agree
[lm ensureGlyphsForCharacterRange:searchRange];
[lm removeTemporaryAttribute:NSForegroundColorAttributeName
forCharacterRange:searchRange];
// Repeatedly search and apply temporary attributes to special characters in
search range
NSString* str = ts.string;
//NSLog( @"Searching for special chars in: %@", [str
substringWithRange:searchRange]);
NSCharacterSet* set = hi.characterSet;
NSDictionary* tempAttrs = @{ NSForegroundColorAttributeName : hi.color };
while ( true ) {
NSRange foundRange = [str rangeOfCharacterFromSet:set
options:0
range:searchRange];
if ( foundRange.location == NSNotFound ) {
break;
}
[lm setTemporaryAttributes:tempAttrs forCharacterRange:foundRange];
NSUInteger startIx = foundRange.location + foundRange.length;
if ( startIx >= beyondIx ) {
break;
}
searchRange = NSMakeRange( startIx, beyondIx - startIx );
}
}
The definition of HighlightInfo should be obvious, but here it is anyway:
@interface HighlightInfo : NSObject
@property (nonatomic) NSColor* color;
@property (nonatomic) NSCharacterSet* characterSet;
@property (nonatomic) NSRange range;
-(instancetype)initWithColor:(NSColor*)color
characterSet:(NSCharacterSet*)characterSet
range:(NSRange)range;
@end
Cheers and happy holidays to all!
—
Charles Jenkins
_______________________________________________
Cocoa-dev mailing list ([email protected])
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com
This email sent to [email protected]