             return nil
         }
 
-        // 1st Paragraph: No List >> Apply
+        // 1st Paragraph: No List >> Apply, skipping paragraphs that currently contain TextLists
         guard let listRange = string.rangeOfTextList(atIndex: paragraphRanges[0].location) else {
-            return applyList(ofStyle: style, toString: string, atRanges: paragraphRanges)
+            let filtered = filterListRanges(paragraphRanges, fromString: string, notMatchingStyle: style)
+            return applyLists(ofStyle: style, toString: string, atNonContiguousRanges: filtered)
         }
 
         // 1st Paragraph: Matching List Style >> Remove

//
private extension TextListFormatter
{
    /// Applies a TextList attribute to the specified paragraph ranges in the
    /// specified string. Each paragraph range is treated as a list item.
    ///

        applyList(ofStyle: nextListAttribute.style, toString: string, atRanges: nextListParagraphs)
    }
}


// MARK: - Private Helpers
//
private extension TextListFormatter
{
    ///
    ///
    func filterListRanges(ranges: [NSRange], fromString string: NSAttributedString, notMatchingStyle style: TextList.Style) -> [NSRange] {
        return ranges.filter { range in
            let list = string.textListAttribute(spanningRange: range)
            return list == nil || list?.style == style
        }
    }


    ///
    ///
    func groupContiguousRanges(ranges: [NSRange]) -> [[NSRange]] {
        var grouped = [[NSRange]]()
        var current = [NSRange]()
        var last: NSRange?

        for range in ranges {
            if let lastLocation = last?.lastLocation where range.location != lastLocation {
                grouped.append(current)
                current.removeAll()
                last = nil
            }

            current.append(range)
            last = range
        }

        if !current.isEmpty {
            grouped.append(current)
        }
        
        return grouped
    }
}
