diff --git a/Sources/Ink/API/MarkdownParser.swift b/Sources/Ink/API/MarkdownParser.swift index 7445da7..b8e8911 100644 --- a/Sources/Ink/API/MarkdownParser.swift +++ b/Sources/Ink/API/MarkdownParser.swift @@ -67,9 +67,7 @@ public struct MarkdownParser { let type = fragmentType(for: reader.currentCharacter, nextCharacter: reader.nextCharacter) - #if swift(>=5.4) - #warning("review compiler crash work-around below") - #elseif swift(>=5.3) && os(Linux) + #if swift(>=5.3) && swift(<5.4) && os(Linux) // inline function call to work around https://bugs.swift.org/browse/SR-13645 let fragment: ParsedFragment = try { let startIndex = reader.currentIndex diff --git a/Sources/Ink/Internal/FormattedText.swift b/Sources/Ink/Internal/FormattedText.swift index 311449a..ed244d1 100644 --- a/Sources/Ink/Internal/FormattedText.swift +++ b/Sources/Ink/Internal/FormattedText.swift @@ -109,13 +109,13 @@ private extension FormattedText { break } - guard reader.previousCharacter != "\\" && !(sequentialSpaceCount >= 2) else { + guard reader.previousCharacter != "\\" && sequentialSpaceCount < 2 else { text.components.append(.linebreak) skipCharacter() continue } - guard !nextCharacter.isAny(of: ["\n", "#", "<", "`", "\r\n"]) else { + guard !nextCharacter.isAny(of: ["\n", "#", "<", "`", "-", "\r\n"]) else { break } diff --git a/Sources/Ink/Internal/Link.swift b/Sources/Ink/Internal/Link.swift index 8770093..69ee8c7 100644 --- a/Sources/Ink/Internal/Link.swift +++ b/Sources/Ink/Internal/Link.swift @@ -19,7 +19,7 @@ internal struct Link: Fragment { if reader.currentCharacter == "(" { reader.advanceIndex() - let url = try reader.read(until: ")") + let url = try reader.read(until: ")", balanceAgainst: "(") return Link(target: .url(url), text: text) } else { try reader.read("[") diff --git a/Sources/Ink/Internal/List.swift b/Sources/Ink/Internal/List.swift index d3c9ac0..8b2779e 100644 --- a/Sources/Ink/Internal/List.swift +++ b/Sources/Ink/Internal/List.swift @@ -12,7 +12,15 @@ internal struct List: Fragment { private var items = [Item]() static func read(using reader: inout Reader) throws -> List { - try read(using: &reader, indentationLength: 0) + // Calculate initial indentation + var indentationLength = 0 + while reader.previousCharacter?.isSameLineWhitespace == true { + indentationLength += 1 + reader.rewindIndex() + } + reader.advanceIndex(by: indentationLength) + + return try read(using: &reader, indentationLength: indentationLength) } private static func read(using reader: inout Reader, diff --git a/Sources/Ink/Internal/Reader.swift b/Sources/Ink/Internal/Reader.swift index ef597d2..c0b5264 100644 --- a/Sources/Ink/Internal/Reader.swift +++ b/Sources/Ink/Internal/Reader.swift @@ -37,11 +37,13 @@ extension Reader { mutating func read(until character: Character, required: Bool = true, allowWhitespace: Bool = true, - allowLineBreaks: Bool = false) throws -> Substring { + allowLineBreaks: Bool = false, + balanceAgainst balancingCharacter: Character? = nil) throws -> Substring { let startIndex = currentIndex + var characterBalance = 0 while !didReachEnd { - guard currentCharacter != character else { + guard currentCharacter != character || characterBalance > 0 else { let result = string[startIndex..He_llo

") } + func testLinkWithParenthesis() { + let html = MarkdownParser().html(from: "[Hello](/(hello))") + XCTAssertEqual(html, "

Hello

") + } + + func testLinkWithNestedParenthesis() { + let html = MarkdownParser().html(from: "[Hello](/(h(e(l(l(o()))))))") + XCTAssertEqual(html, "

Hello

") + } + + func testLinkWithParenthesisAndClosingParenthesisInContent() { + let html = MarkdownParser().html(from: "[Hello](/(hello)))") + XCTAssertEqual(html, "

Hello)

") + } + func testUnterminatedLink() { let html = MarkdownParser().html(from: "[Hello]") XCTAssertEqual(html, "

[Hello]

") @@ -81,6 +96,9 @@ extension LinkTests { ("testBoldLinkWithInternalMarkers", testBoldLinkWithInternalMarkers), ("testBoldLinkWithExternalMarkers", testBoldLinkWithExternalMarkers), ("testLinkWithUnderscores", testLinkWithUnderscores), + ("testLinkWithParenthesis", testLinkWithParenthesis), + ("testLinkWithNestedParenthesis", testLinkWithNestedParenthesis), + ("testLinkWithParenthesisAndClosingParenthesisInContent", testLinkWithParenthesisAndClosingParenthesisInContent), ("testUnterminatedLink", testUnterminatedLink), ("testLinkWithEscapedSquareBrackets", testLinkWithEscapedSquareBrackets) ] diff --git a/Tests/InkTests/ListTests.swift b/Tests/InkTests/ListTests.swift index 59a9497..2653535 100644 --- a/Tests/InkTests/ListTests.swift +++ b/Tests/InkTests/ListTests.swift @@ -133,6 +133,25 @@ final class ListTests: XCTestCase { XCTAssertEqual(html, "") } + + func testOrderedIndentedList() { + let html = MarkdownParser().html(from: """ + 1. One + 2. Two + """) + + XCTAssertEqual(html, #"
  1. One
  2. Two
"#) + } + + func testUnorderedIndentedList() { + let html = MarkdownParser().html(from: """ + - One + - Two + - Three + """) + + XCTAssertEqual(html, "") + } } extension ListTests { @@ -148,7 +167,9 @@ extension ListTests { ("testMixedList", testMixedList), ("testUnorderedListWithMultiLineItem", testUnorderedListWithMultiLineItem), ("testUnorderedListWithNestedList", testUnorderedListWithNestedList), - ("testUnorderedListWithInvalidMarker", testUnorderedListWithInvalidMarker) + ("testUnorderedListWithInvalidMarker", testUnorderedListWithInvalidMarker), + ("testOrderedIndentedList", testUnorderedIndentedList), + ("testUnorderedIndentedList", testUnorderedIndentedList), ] } } diff --git a/Tests/InkTests/TextFormattingTests.swift b/Tests/InkTests/TextFormattingTests.swift index 74f5199..3900e52 100644 --- a/Tests/InkTests/TextFormattingTests.swift +++ b/Tests/InkTests/TextFormattingTests.swift @@ -147,6 +147,19 @@ final class TextFormattingTests: XCTestCase { XCTAssertEqual(html, "

# Not a title *Not italic*

") } + + func testListAfterFormattedText() { + let html = MarkdownParser().html(from: """ + This is a test + - One + - Two + """) + + XCTAssertEqual(html, """ +

This is a test

+ """) + } + func testDoubleSpacedHardLinebreak() { let html = MarkdownParser().html(from: "Line 1 \nLine 2") @@ -189,6 +202,7 @@ extension TextFormattingTests { ("testSingleLineBlockquote", testSingleLineBlockquote), ("testMultiLineBlockquote", testMultiLineBlockquote), ("testEscapingSymbolsWithBackslash", testEscapingSymbolsWithBackslash), + ("testListAfterFormattedText", testListAfterFormattedText), ("testDoubleSpacedHardLinebreak", testDoubleSpacedHardLinebreak), ("testEscapedHardLinebreak", testEscapedHardLinebreak) ]