         }
     }
 
+    /// Applies the Formatter's Attributes into a given string, at the specified range.
+    ///
+    func applyAttributes(to text: NSMutableAttributedString, at range: NSRange) {
+        var rangeToApply = applicationRange(for: range, in: text)
+
+        if rangeToApply.length == 0 || text.length == 0 {
+            let placeholder = placeholderForEmptyLine(using: placeholderAttributes)
+            text.insert(placeholder, at: rangeToApply.location)
+            rangeToApply = NSMakeRange(text.length - 1, 1)
+        }
+
+        text.enumerateAttributes(in: rangeToApply, options: []) { (attributes, range, stop) in
+            let currentAttributes = text.attributes(at: range.location, effectiveRange: nil)
+            let attributes = apply(to: currentAttributes)
+            text.addAttributes(attributes, range: range)
+        }
+    }
+
+    /// Removes the Formatter's Attributes from a given string, at the specified range.
+    ///
+    func removeAttributes(from text: NSMutableAttributedString, at range: NSRange) {
+        let rangeToApply = applicationRange(for: range, in: text)
+        text.enumerateAttributes(in: rangeToApply, options: []) { (attributes, range, stop) in
+            let currentAttributes = text.attributes(at: range.location, effectiveRange: nil)
+            let attributes = remove(from: currentAttributes)
+
+            let currentKeys = Set(currentAttributes.keys)
+            let newKeys = Set(attributes.keys)
+            let removedKeys = currentKeys.subtracting(newKeys)
+            for key in removedKeys {
+                text.removeAttribute(key, range: range)
+            }
+
+            text.addAttributes(attributes, range: range)
+        }
+    }
+
+    /// Toggles the Attribute Format, into a given string, at the specified range.
+    ///
+    @discardableResult
+    func toggle(in text: NSMutableAttributedString, at range: NSRange) -> NSRange? {
+        //We decide if we need to apply or not the attribute based on the value on the initial position of the range
+        let shouldApply =  shouldApplyAttributes(to: text, at: range)
+
+        if shouldApply {
+            applyAttributes(to: text, at: range)
+        } else {
+            removeAttributes(from: text, at: range)
+        }
+
+        return nil
+    }
 }
 
 

    /// - Returns: the resulting attributes dictionary
    ///
    func remove(from attributes: [String: Any]) -> [String: Any]

    /// Checks if the attribute is present in a dictionary of attributes.
    ///


        return present(in: text, at: range) == false
    }
}


