diff --git a/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilder.swift b/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilder.swift index 2d8cd2948..7ba62e511 100644 --- a/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilder.swift +++ b/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilder.swift @@ -191,6 +191,13 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol { link.insert(contentsOf: "https://", at: link.startIndex) } + // Don't include punctuation characters at the end of links + // e.g `https://element.io/blog:` <- which is a valid link but the wrong place + while !link.isEmpty, + link.rangeOfCharacter(from: .punctuationCharacters, options: .backwards)?.upperBound == link.endIndex { + link = String(link.dropLast()) + } + return TextParsingMatch(type: .link(urlString: link), range: match.range) }) diff --git a/UnitTests/Sources/AttributedStringBuilderTests.swift b/UnitTests/Sources/AttributedStringBuilderTests.swift index dee091088..6b35264b8 100644 --- a/UnitTests/Sources/AttributedStringBuilderTests.swift +++ b/UnitTests/Sources/AttributedStringBuilderTests.swift @@ -110,6 +110,23 @@ class AttributedStringBuilderTests: XCTestCase { XCTAssertEqual(link?.host, "www.matrix.org") } + func testPunctuationAtTheEndOfPlainStringLinks() { + let plainString = "This text contains a https://www.matrix.org:;., link." + + guard let attributedString = attributedStringBuilder.fromPlain(plainString) else { + XCTFail("Could not build the attributed string") + return + } + + XCTAssertEqual(String(attributedString.characters), plainString) + + XCTAssertEqual(attributedString.runs.count, 3) + + let link = attributedString.runs.first(where: { $0.link != nil })?.link + + XCTAssertEqual(link?.host, "www.matrix.org") + } + func testLinkDefaultScheme() { let plainString = "This text contains a matrix.org link." @@ -177,9 +194,13 @@ class AttributedStringBuilderTests: XCTestCase { } func testLinkWithFragment() { - let string = "https://example.com/#/" - checkLinkIn(attributedString: attributedStringBuilder.fromHTML(string), expectedLink: string, expectedRuns: 1) - checkLinkIn(attributedString: attributedStringBuilder.fromPlain(string), expectedLink: string, expectedRuns: 1) + var string = "https://example.com/#/" + checkLinkIn(attributedString: attributedStringBuilder.fromHTML(string), expectedLink: "https://example.com", expectedRuns: 1) + checkLinkIn(attributedString: attributedStringBuilder.fromPlain(string), expectedLink: "https://example.com", expectedRuns: 1) + + string = "https://example.com/#/some_fragment/" + checkLinkIn(attributedString: attributedStringBuilder.fromHTML(string), expectedLink: "https://example.com/#/some_fragment", expectedRuns: 1) + checkLinkIn(attributedString: attributedStringBuilder.fromPlain(string), expectedLink: "https://example.com/#/some_fragment", expectedRuns: 1) } func testPermalink() {