Matt Gemmell

TOLL is available now!

An action-thriller novel — book 2 in the KESTREL series.

★★★★★ — Amazon

Replacing styled text

interface 1 min read

I'm a little drunk right now, so this may come out slightly garbled. I want 
to talk a little bit about performing find/replace operations with styled text.

Historically, performing find/replace operations with styled text has always 
caused problems. The issue is that the style-runs (either in "styl" resources 
in Ye Olden Days, or probably in attributes dictionaries in NSAttributedStrings 
nowadays), are <em>separate</em> from the text. Thus, with a na&iuml;ve implementation, 
you get a classic "bug": after a replace operation, either all text in the document 
(for <em>very</em> na&iuml;ve code), or all newly-inserted text, inherits the style 
information of the first character of that section of text. This is the classic 
styled-replace problem.

The question is, do we just accept this behaviour? After all, the user can't reasonably 
expect much more, can they? Actually, they can and do expect more. Clearly, a more intelligent 
implementation is required. There are essentially four scenarios to consider:
  1. The replacing text is the same length as that which it replaces.
  2. The replacing text is shorter.
  3. The replacing text is longer, but has a non-zero length.
  4. The replacing text has zero length.
Let's deal with the above scenarios one by one.


Scenario 1: Same length

This is easy; just maintain the style-runs character-by-character. For situations 
where double-byte text is present, proceed on a "one <em>visual</em> character" basis.

Scenario 2: Replacing text shorter

In this case, proceed as with the "same length" situation, but truncate the style-runs 
after the appropriate number of characters.

Scenario 3: Replacing text longer

This is the trickiest situation. It's probably most intuitive to again maintain the style-runs 
character-by-character until you run out of style information, and then assign the style information 
of the last (old) character to all successive characters in the new text. This makes sense to the user, 
because when you continue typing at the end of some styled text, the new text invariably inherits the 
styles of the previous character.

Scenario 4: Replacing text has zero length

This is obviously a deletion operation. Accordingly, it's important to make sure that the style-runs of 
the deleted text are also removed; it's not acceptable to simply let the remaining text be "bumped along" 
the underlying style-runs, and to simply chop off an appropriate quantity of style information from the 
end. Usually this behaviour is taken care of automatically, but it's still worth mentioning.


So there you have it: sensible and reasonably intuitive styled-replace. Much more work for the developer, 
but fewer bizarre bug-reports after release. Now I'm off to get another beer.