diff --git a/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilder.swift b/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilder.swift
index efc436e97..d6b49e89a 100644
--- a/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilder.swift
+++ b/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilder.swift
@@ -31,6 +31,7 @@ extension NSAttributedString.Key {
static let MatrixEventOnRoomID: NSAttributedString.Key = .init(rawValue: EventOnRoomIDAttribute.name)
static let MatrixEventOnRoomAlias: NSAttributedString.Key = .init(rawValue: EventOnRoomAliasAttribute.name)
static let MatrixAllUsersMention: NSAttributedString.Key = .init(rawValue: AllUsersMentionAttribute.name)
+ static let CodeBlock: NSAttributedString.Key = .init(rawValue: CodeBlockAttribute.name)
}
struct AttributedStringBuilder: AttributedStringBuilderProtocol {
diff --git a/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilderV2.swift b/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilderV2.swift
index 0a4f93b59..853aa9b2a 100644
--- a/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilderV2.swift
+++ b/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilderV2.swift
@@ -85,6 +85,7 @@ struct AttributedStringBuilderV2: AttributedStringBuilderProtocol {
// MARK: - Private
+ // swiftlint:disable:next function_body_length
func attributedString(from element: Element, preserveFormatting: Bool,
listTag: String?,
listIndex: inout Int,
@@ -162,15 +163,17 @@ struct AttributedStringBuilderV2: AttributedStringBuilderProtocol {
let preserveFormatting = preserveFormatting || tag == "pre"
content = attributedString(from: childElement, preserveFormatting: preserveFormatting, listTag: listTag, listIndex: &childIndex, indentLevel: indentLevel)
content.setFontPreservingSymbolicTraits(UIFont.monospacedSystemFont(ofSize: UIFont.systemFontSize, weight: .regular))
+ content.addAttribute(.CodeBlock, value: true, range: NSRange(location: 0, length: content.length))
content.addAttribute(.backgroundColor, value: UIColor.compound._bgCodeBlock as Any, range: NSRange(location: 0, length: content.length))
- // Don't allow identifiers in code blocks
+ // Don't allow identifiers or links in code blocks
content.removeAttribute(.MatrixRoomID, range: NSRange(location: 0, length: content.length))
content.removeAttribute(.MatrixRoomAlias, range: NSRange(location: 0, length: content.length))
content.removeAttribute(.MatrixUserID, range: NSRange(location: 0, length: content.length))
content.removeAttribute(.MatrixEventOnRoomID, range: NSRange(location: 0, length: content.length))
content.removeAttribute(.MatrixEventOnRoomAlias, range: NSRange(location: 0, length: content.length))
content.removeAttribute(.MatrixAllUsersMention, range: NSRange(location: 0, length: content.length))
+ content.removeAttribute(.link, range: NSRange(location: 0, length: content.length))
case "hr":
content = NSMutableAttributedString(string: "\n")
@@ -295,9 +298,15 @@ struct AttributedStringBuilderV2: AttributedStringBuilderProtocol {
// Sort the links by length so the longest one always takes priority
matches.sorted { $0.range.length > $1.range.length }.forEach { [attributedString] match in
+ // Don't highlight links within codeblocks
+ let isInCodeBlock = attributedString.attribute(.CodeBlock, at: match.range.location, effectiveRange: nil) != nil
+ if isInCodeBlock {
+ return
+ }
+
var hasLink = false
attributedString.enumerateAttribute(.link, in: match.range, options: []) { value, _, stop in
- if value != nil {
+ if value != nil, !isInCodeBlock {
hasLink = true
stop.pointee = true
}
diff --git a/ElementX/Sources/Other/HTMLParsing/ElementXAttributeScope.swift b/ElementX/Sources/Other/HTMLParsing/ElementXAttributeScope.swift
index a4943c96c..02d76c0bd 100644
--- a/ElementX/Sources/Other/HTMLParsing/ElementXAttributeScope.swift
+++ b/ElementX/Sources/Other/HTMLParsing/ElementXAttributeScope.swift
@@ -62,6 +62,11 @@ enum AllUsersMentionAttribute: AttributedStringKey {
static let name = "MXAllUsersMentionAttribute"
}
+enum CodeBlockAttribute: AttributedStringKey {
+ typealias Value = Bool
+ static let name = "MXCodeBlockAttribute"
+}
+
// periphery: ignore - required to make NSAttributedString to AttributedString conversion even if not used directly
extension AttributeScopes {
struct ElementXAttributes: AttributeScope {
@@ -77,6 +82,8 @@ extension AttributeScopes {
let allUsersMention: AllUsersMentionAttribute
+ let codeBlock: CodeBlockAttribute
+
let swiftUI: SwiftUIAttributes
let uiKit: UIKitAttributes
}
diff --git a/ElementX/Sources/Other/HTMLParsing/HTMLFixtures.swift b/ElementX/Sources/Other/HTMLParsing/HTMLFixtures.swift
index d79e20207..277b6ee15 100644
--- a/ElementX/Sources/Other/HTMLParsing/HTMLFixtures.swift
+++ b/ElementX/Sources/Other/HTMLParsing/HTMLFixtures.swift
@@ -89,7 +89,8 @@ enum HTMLFixtures: String, CaseIterable {
Followed by some plain code blocks
Hello, world!
Hello, world!
- Hello, world!
+ This link should not be interpreted as such
+ And this https://www.matrix.org should be not highlighted
"""
case .unorderedList:
"""
diff --git a/UnitTests/Sources/AttributedStringBuilderTests.swift b/UnitTests/Sources/AttributedStringBuilderTests.swift
index 20034d8cc..e09637772 100644
--- a/UnitTests/Sources/AttributedStringBuilderTests.swift
+++ b/UnitTests/Sources/AttributedStringBuilderTests.swift
@@ -590,10 +590,6 @@ class AttributedStringBuilderV1Tests: XCTestCase {
}
func testURLsAreIgnoredInCode() {
- if AttributedStringBuilder.useNextGenHTMLParser {
- return
- }
-
var htmlString = "
test https://matrix.org test"
var attributedStringFromHTML = attributedStringBuilder.fromHTML(htmlString)
XCTAssert(attributedStringFromHTML?.runs.count == 1)
@@ -606,10 +602,6 @@ class AttributedStringBuilderV1Tests: XCTestCase {
}
func testHyperlinksAreIgnoredInCode() {
- if AttributedStringBuilder.useNextGenHTMLParser {
- return
- }
-
let htmlString = "test matrix test"
let attributedStringFromHTML = attributedStringBuilder.fromHTML(htmlString)
XCTAssertNil(attributedStringFromHTML?.link)
@@ -619,11 +611,7 @@ class AttributedStringBuilderV1Tests: XCTestCase {
let htmlString = "test https://matrix.org/#/@test:matrix.org test"
let attributedString = attributedStringBuilder.fromHTML(htmlString)
- if AttributedStringBuilder.useNextGenHTMLParser {
- XCTAssert(attributedString?.runs.count == 3)
- } else {
- XCTAssert(attributedString?.runs.count == 1)
- }
+ XCTAssert(attributedString?.runs.count == 1)
XCTAssertNil(attributedString?.attachment)
}
@@ -632,11 +620,7 @@ class AttributedStringBuilderV1Tests: XCTestCase {
let htmlString = "Hey @some.user.ceriu:matrix.org"
let attributedString = attributedStringBuilder.fromHTML(htmlString)
- if AttributedStringBuilder.useNextGenHTMLParser {
- XCTAssert(attributedString?.runs.count == 2)
- } else {
- XCTAssert(attributedString?.runs.count == 1)
- }
+ XCTAssert(attributedString?.runs.count == 1)
XCTAssertNil(attributedString?.attachment)
}
@@ -645,11 +629,7 @@ class AttributedStringBuilderV1Tests: XCTestCase {
let htmlString = "test @room test"
let attributedString = attributedStringBuilder.fromHTML(htmlString)
- if AttributedStringBuilder.useNextGenHTMLParser {
- XCTAssert(attributedString?.runs.count == 3)
- } else {
- XCTAssert(attributedString?.runs.count == 1)
- }
+ XCTAssert(attributedString?.runs.count == 1)
XCTAssertNil(attributedString?.attachment)
}