Search code examples
swiftnsattributedstringattributedstring

How to copy all attributes from one AttributedString to another without converting to NSAttributedString?


I have an AttributedString with a set of attributes I don't know until runtime. Now I want to append / prepend another string. How do I get the appended string to have the same attributes as the original AttributedString? Copying the attributes from the first character is fine, as the entire AttributedString has homogenous attributes.

I see I can create a new AttributedString with the new appended text, then call "setAttributes" on it, but see no way to get the AttributeContainer from the original string? Is there a way to do this that doesn't involve copying each attribute individually?

I see this is possible with NSAttributedString, but is it possible without converting to NSAttributedString?

I would hope I could do something like:

let originalText: AttributedString // Some existing string with arbitrary attributes
var newText = AttributedString("text_I_want_to_prepend_to_originalText")
newText.setAttributes(originalText.getAttributes(at: 0))
newText.append(originalText)

Solution

  • The containers are attached to each AttributedString.Run (which is a range of characters with the same attributes). You can access them this way:

    newText.setAttributes(originalText.runs.first!.attributes)
    

    Obviously you should think carefully about how this would work if the string is empty, since that would crash. But the basic approach is to access the runs property.

    There is a subscript on runs that accepts AttributeString.Index, so a version that more precisely matches your original getAttributes(at: 0) would be:

    newText.setAttributes(originalText.runs[originalText.startIndex].attributes)