diff --git a/CDMarkdownKitTests/TestCode.swift b/CDMarkdownKitTests/TestCode.swift index e8b63018..632f8432 100644 --- a/CDMarkdownKitTests/TestCode.swift +++ b/CDMarkdownKitTests/TestCode.swift @@ -104,6 +104,16 @@ final class TestCode: XCTestCase { XCTAssertTrue(TestHelpers.isMonospaced(testString: parsed, at: 6)) } + func testEmojiInsideCode() throws { + let parser = getParser() + + let parsed = parser.parse("`test 👋 abc`") + XCTAssertEqual(parsed.string, "test 👋 abc") + XCTAssertTrue(TestHelpers.isMonospaced(testString: parsed, at: 1)) + XCTAssertTrue(TestHelpers.isMonospaced(testString: parsed, at: 9)) + XCTAssertTrue(TestHelpers.isMonospaced(testString: parsed, at: 10)) + } + /* // Expected to fail currently, because the CodeEscaping does not differentiate between code and syntax and always allows new lines func testCodeMultiline() throws { diff --git a/CDMarkdownKitTests/TestSyntax.swift b/CDMarkdownKitTests/TestSyntax.swift index b30372e0..31dfe81b 100644 --- a/CDMarkdownKitTests/TestSyntax.swift +++ b/CDMarkdownKitTests/TestSyntax.swift @@ -137,4 +137,15 @@ final class TestSyntax: XCTestCase { XCTAssertTrue(TestHelpers.isMonospaced(testString: parsed, at: 4)) } + func testEmojiInsideSyntax() throws { + let parser = getParser() + + let parsed = parser.parse("```\nsyntax\n👍ABC\n```") + XCTAssertEqual(parsed.string, "syntax\n👍ABC\n") + XCTAssertTrue(TestHelpers.isMonospaced(testString: parsed, at: 4)) + XCTAssertTrue(TestHelpers.isMonospaced(testString: parsed, at: 10)) + XCTAssertTrue(TestHelpers.isMonospaced(testString: parsed, at: 11)) + XCTAssertTrue(TestHelpers.isMonospaced(testString: parsed, at: 12)) + } + } diff --git a/Source/CDMarkdownCode.swift b/Source/CDMarkdownCode.swift index 8f341e9a..5c23bc93 100644 --- a/Source/CDMarkdownCode.swift +++ b/Source/CDMarkdownCode.swift @@ -68,10 +68,13 @@ open class CDMarkdownCode: CDMarkdownCommonElement { guard let unescapedString = matchString.fromBase64() else { return } attributedString.replaceCharacters(in: range, with: unescapedString) + + // Since we use NSRange here, we need to count based on UTF16, alternatively could use NSString length property let range = NSRange(location: range.location, - length: unescapedString.characterCount()) + length: unescapedString.utf16.count) attributedString.addAttributes(attributes, range: range) + let mutableString = attributedString.mutableString // Remove \n if in string, not valid in Code element // Use Syntax element for \n to parse in string diff --git a/Source/CDMarkdownSyntax.swift b/Source/CDMarkdownSyntax.swift index 7ae699ae..a7ea5ae3 100644 --- a/Source/CDMarkdownSyntax.swift +++ b/Source/CDMarkdownSyntax.swift @@ -75,8 +75,9 @@ open class CDMarkdownSyntax: CDMarkdownCommonElement { attributedString.replaceCharacters(in: range, with: unescapedString) + // Since we use NSRange here, we need to count based on UTF16, alternatively could use NSString length property let range = NSRange(location: range.location, - length: unescapedString.characterCount()) + length: unescapedString.utf16.count) attributedString.addAttributes(attributes, range: range) // If the previous character was a newline then parser doesn't have to worry about diff --git a/Source/String+CDMarkdownKit.swift b/Source/String+CDMarkdownKit.swift index a3ba2f0a..57a99b54 100644 --- a/Source/String+CDMarkdownKit.swift +++ b/Source/String+CDMarkdownKit.swift @@ -95,10 +95,6 @@ internal extension String { return from ..< to } - func characterCount() -> Int { - return self.count - } - func sizeWithAttributes(_ attributes: [CDAttributedStringKey: Any]? = nil) -> CGSize { return self.size(withAttributes: attributes) }