@@ -265,33 +265,23 @@ open class TextStorage: NSTextStorage {
265265 /// - Returns: the preprocessed string.
266266 ///
267267 fileprivate func preprocessMarkForInsertion( _ attributedString: NSAttributedString , _ range: NSRange ) -> NSAttributedString {
268- guard textStore. length > 0 , attributedString. length > 0 , range. endLocation != range. lowerBound else {
268+ // If the attributed string is empty, return as is
269+ if attributedString. length == 0 {
269270 return attributedString
270271 }
271- var startAt = 0
272-
273- if range. endLocation > range. lowerBound {
274- startAt = range. lowerBound
275- }
276-
277- // Get the attributes of the start of the current string in storage.
278- let currentAttrs = attributes ( at: startAt, effectiveRange: nil )
279-
280- guard
281- // the text currently in storage has a markHtmlRepresentation key
282- let markSize = currentAttrs [ . markHtmlRepresentation] ,
283- // the text coming in doesn't have a markHtmlRepresentation key
284- attributedString. attribute ( . markHtmlRepresentation, at: 0 , effectiveRange: nil ) == nil
285- else {
286- // Either the mark attribute wasn't present in the existing string,
287- // or the attributed string already had it.
288- return attributedString
272+
273+ // Determine the effective range of attributes at the insertion point
274+ var effectiveRange = NSRange ( location: NSNotFound, length: 0 )
275+ let insertionPoint = range. location > 0 ? range. location - 1 : 0
276+ let currentAttrs = attributes ( at: insertionPoint, effectiveRange: & effectiveRange)
277+
278+ // Apply 'markHtmlRepresentation' attribute if present
279+ if let markSize = currentAttrs [ . markHtmlRepresentation] {
280+ let processedString = NSMutableAttributedString ( attributedString: attributedString)
281+ processedString. addAttribute ( . markHtmlRepresentation, value: markSize, range: NSRange ( location: 0 , length: attributedString. length) )
282+ return processedString
289283 }
290-
291- let processedString = NSMutableAttributedString ( attributedString: attributedString)
292- processedString. addAttribute ( . markHtmlRepresentation, value: markSize, range: attributedString. rangeOfEntireString)
293-
294- return processedString
284+ return attributedString
295285 }
296286
297287 fileprivate func detectAttachmentRemoved( in range: NSRange ) {
@@ -363,9 +353,13 @@ open class TextStorage: NSTextStorage {
363353 override open func setAttributes( _ attrs: [ NSAttributedString . Key : Any ] ? , range: NSRange ) {
364354 beginEditing ( )
365355
356+ // Ensure matching styles for the font and paragraph headers
366357 let fixedAttributes = ensureMatchingFontAndParagraphHeaderStyles ( beforeApplying: attrs ?? [ : ] , at: range)
367358
368- textStore. setAttributes ( fixedAttributes, range: range)
359+ // Adjust attributes for 'mark' formatting logic
360+ let adjustedAttributes = adjustAttributesForMark ( fixedAttributes, range: range)
361+
362+ textStore. setAttributes ( adjustedAttributes, range: range)
369363 edited ( . editedAttributes, range: range, changeInLength: 0 )
370364
371365 endEditing ( )
@@ -523,6 +517,34 @@ private extension TextStorage {
523517 }
524518}
525519
520+ // MARK: - Mark Formatting Attribute Fixes
521+ //
522+ private extension TextStorage {
523+ /// Adjusts text attributes to preserve the color of text marked with 'markHtmlRepresentation'.
524+ ///
525+ /// This method checks if the specified range of text has the 'markHtmlRepresentation' attribute.
526+ /// If it does, the method retains the existing color attribute to preserve the 'mark' formatting.
527+ ///
528+ /// - Parameters:
529+ /// - attrs: NSAttributedString attributes that are about to be applied.
530+ /// - range: Range of the text being modified.
531+ ///
532+ /// - Returns: Adjusted collection of attributes, preserving color for 'mark' formatted text.
533+ ///
534+ private func adjustAttributesForMark( _ attrs: [ NSAttributedString . Key : Any ] , range: NSRange ) -> [ NSAttributedString . Key : Any ] {
535+ var adjustedAttributes = attrs
536+
537+ // Check if the range has the 'markHtmlRepresentation' attribute
538+ let hasMarkAttribute = attribute ( . markHtmlRepresentation, at: range. location, effectiveRange: nil ) != nil
539+
540+ // If the 'markHtmlRepresentation' attribute is present, retain the existing color
541+ if hasMarkAttribute, let existingColor = textStore. attribute ( . foregroundColor, at: range. location, effectiveRange: nil ) as? UIColor {
542+ adjustedAttributes [ . foregroundColor] = existingColor
543+ }
544+
545+ return adjustedAttributes
546+ }
547+ }
526548
527549// MARK: - TextStorage: MediaAttachmentDelegate Methods
528550//
0 commit comments