@@ -143,11 +143,11 @@ open class TextStorage: NSTextStorage {
143143
144144 // MARK: - NSAttributedString preprocessing
145145
146- private func preprocessAttributesForInsertion( _ attributedString: NSAttributedString ) -> NSAttributedString {
146+ private func preprocessAttributesForInsertion( _ attributedString: NSAttributedString , _ range : NSRange ) -> NSAttributedString {
147147 let stringWithAttachments = preprocessAttachmentsForInsertion ( attributedString)
148- let preprocessedString = preprocessHeadingsForInsertion ( stringWithAttachments)
148+ let stringWithHeadings = preprocessHeadingsForInsertion ( stringWithAttachments)
149149
150- return preprocessedString
150+ return stringWithHeadings
151151 }
152152
153153 /// Preprocesses an attributed string's attachments for insertion in the storage.
@@ -253,6 +253,35 @@ open class TextStorage: NSTextStorage {
253253 return processedString
254254 }
255255
256+ /// Preprocesses an attributed string that is missing a `markHtmlRepresentation` attribute for insertion in the storage.
257+ /// This method ensures that the `markHtmlRepresentation` attribute, if present in the current text storage,
258+ /// is applied to the new attributed string being inserted. This is particularly useful for maintaining
259+ /// mark formatting in scenarios like autocorrection or predictive text input.
260+ ///
261+ /// - Important: This method adds the `markHtmlRepresentation` attribute to the new string if it's determined
262+ /// that the string should contain it, based on existing attributes in the text storage.
263+ /// This helps to overcome issues where autocorrected text does not carry over the `markHtmlRepresentation` attribute.
264+ ///
265+ /// - Parameters:
266+ /// - attributedString: The new string to be inserted.
267+ /// - range: The range in the current text storage where the new string is to be inserted. This is used to determine
268+ /// if `markHtmlRepresentation` should be applied to the new string.
269+ ///
270+ /// - Returns: The preprocessed attributed string with `markHtmlRepresentation` applied if necessary.
271+ ///
272+ fileprivate func preprocessMarkForInsertion( _ attributedString: NSAttributedString , _ range: NSRange ) -> NSAttributedString {
273+ let mutableAttributedString = NSMutableAttributedString ( attributedString: attributedString)
274+
275+ if range. location < textStore. length && range. length > 0 {
276+ let currentAttrs = textStore. attributes ( at: range. location, effectiveRange: nil )
277+
278+ if let markAttribute = currentAttrs [ . markHtmlRepresentation] {
279+ mutableAttributedString. addAttribute ( . markHtmlRepresentation, value: markAttribute, range: NSRange ( location: 0 , length: mutableAttributedString. length) )
280+ }
281+ }
282+ return mutableAttributedString
283+ }
284+
256285 fileprivate func detectAttachmentRemoved( in range: NSRange ) {
257286 // Ref. https://github.com/wordpress-mobile/AztecEditor-iOS/issues/727:
258287 // If the delegate is not set, we *Explicitly* do not want to crash here.
@@ -304,14 +333,16 @@ open class TextStorage: NSTextStorage {
304333 }
305334
306335 override open func replaceCharacters( in range: NSRange , with attrString: NSAttributedString ) {
307-
308- let preprocessedString = preprocessAttributesForInsertion ( attrString)
336+ let preprocessedString = preprocessAttributesForInsertion ( attrString, range)
309337
310338 beginEditing ( )
311339
312340 detectAttachmentRemoved ( in: range)
313- textStore. replaceCharacters ( in: range, with: preprocessedString)
314341
342+ // Apply mark formatting to the replacement string
343+ let markFormattedString = preprocessMarkForInsertion ( preprocessedString, range)
344+
345+ textStore. replaceCharacters ( in: range, with: markFormattedString)
315346 replaceTextStoreString ( range, with: attrString. string)
316347
317348 edited ( [ . editedAttributes, . editedCharacters] , range: range, changeInLength: attrString. length - range. length)
@@ -322,11 +353,15 @@ open class TextStorage: NSTextStorage {
322353 override open func setAttributes( _ attrs: [ NSAttributedString . Key : Any ] ? , range: NSRange ) {
323354 beginEditing ( )
324355
356+ // Ensure matching styles for the font and paragraph headers
325357 let fixedAttributes = ensureMatchingFontAndParagraphHeaderStyles ( beforeApplying: attrs ?? [ : ] , at: range)
326358
327- 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)
328363 edited ( . editedAttributes, range: range, changeInLength: 0 )
329-
364+
330365 endEditing ( )
331366 }
332367
@@ -482,6 +517,34 @@ private extension TextStorage {
482517 }
483518}
484519
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+ }
485548
486549// MARK: - TextStorage: MediaAttachmentDelegate Methods
487550//
0 commit comments