- The Foundation AppKit Split
- Semantic Attributes
- Transforming to Presentation
- Generating XML
- Alternatives
Transforming to Presentation
Source code isn't the only kind of thing that benefits from this separation. Doing any kind of transform on an attributed string typically involves a loop like this:
do { NSDictionary *attrs = [source attributesAtIndex: i longestEffectiveRange: &r inRange: NSMakeRange(i, end-i)]; i = r.location + r.length; // Process attributes } while(i < end)
The -attributesAtIndex:longestEffectiveRange:inRange: method returns a dictionary of all of the attributes at the specified index, along with the range over which these attributes apply. Then you have several options. The simplest is to replace the attributes in this range with some presentation attributes. For example, to make every keyword red, you would do something like this:
if ([attrs objectForKey: kSCKTextTokenType] == SCKTextTokenTypeKeyword) { [source addAttribute: NSForegroundColorAttributeName value: [NSColor redColor] range: r]; }
This example sets the foreground color attribute for the range to red. Of course, the attributed string for output doesn't have to be the same as the string for input. You can take one attributed string that contains semantic attributes about a string, create a new attributed string object with the same text, and apply presentation markup to it.
The only slightly unfortunate design decision with regard to attributed strings is that two mutable attributed strings cannot be represented by the same string. Creating an attributed string with -initWithString: copies the string. If it's an immutable string, the -copy method just returns self. If it's mutable, you get a new string object. This is a shame, because having two distinct sets of attributes on the same string would be convenient. For example, you could allow explicit annotations on an attributed string by the user (perhaps to put fonts or hyperlinks in comments)a set extracted by parsing the text, and a final set generated by applying the semantic attributes. You can work around this limitation by providing a subclass of NSMutableAttributedString that wraps two (or more) attributed strings, passes text modification operations to both, and generates attributes by combining the two.