summaryrefslogtreecommitdiff
path: root/src/main/kotlin/moe/nea/blog/md/ItalicsParser.kt
blob: 5448f5f7ec6b4941bbbd1ffb82e1cb31e1cf951e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package moe.nea.blog.md

object ItalicsParser : InlineParser {
    override fun detect(lookback: MarkdownFormat, rest: String): Boolean {
        return "\\*+[^* ].*".toRegex().matches(rest)
    }

    override val specialSyntax: Set<Char>
        get() = setOf('*')

    override fun parse(parser: MarkdownParser, text: String): Pair<MarkdownFormat, String> {
        var firstStarCount = 0
        while (firstStarCount in text.indices) {
            if (text[firstStarCount] != '*') break
            firstStarCount++
        }

        if (firstStarCount < 1 || firstStarCount > 3) error("Invalid italics/bold sequence")

        var (firstSequence, remainingText) = parser.parseInlineTextUntil(
            text.substring(firstStarCount),
            Begin()
        ) { lookback, remaining -> lookback !is Whitespace && remaining.startsWith("*") } // TODO: free standing *

        var secondStarCount = 0
        while (secondStarCount in remainingText.indices) {
            if (remainingText[secondStarCount] != '*') break
            secondStarCount++
        }

        if (secondStarCount > firstStarCount)
            secondStarCount = firstStarCount
        if (secondStarCount < 1) error("Invalid italics/bold sequence")

        remainingText = remainingText.substring(secondStarCount)
        var firstElement = parser.collapseInlineFormat(firstSequence, false)
        if (secondStarCount == 2)
            firstElement = Bold(firstElement)
        if (secondStarCount == 1)
            firstElement = Italics(firstElement)
        if (secondStarCount == firstStarCount) {
            return Pair(firstElement, remainingText)
        }

        // TODO: better begin
        val (secondSequence, _remainingText) = parser.parseInlineTextUntil(
            remainingText,
            Begin()
        ) { lookback, remaining ->
            lookback !is Whitespace && remaining.startsWith("*")
        }
        remainingText = _remainingText

        var thirdStarCount = 0
        while (thirdStarCount in remainingText.indices) {
            if (remainingText[thirdStarCount] != '*') break
            thirdStarCount++
        }

        if (thirdStarCount > firstStarCount - secondStarCount)
            thirdStarCount = firstStarCount

        remainingText = remainingText.substring(thirdStarCount)

        if (thirdStarCount != firstStarCount - secondStarCount) {
            error("Invalid italics/bold sequence")
        }
        val secondElement = parser.collapseInlineFormat(secondSequence, false)
        var combined: MarkdownFormat = FormatSequence(firstElement, secondElement)
        if (thirdStarCount == 1)
            combined = Italics(combined)
        if (thirdStarCount == 2)
            combined = Bold(combined)
        return Pair(combined, remainingText)
    }
}