summaryrefslogtreecommitdiff
path: root/src/main/kotlin/moe/nea/blog/md/ItalicsParser.kt
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin/moe/nea/blog/md/ItalicsParser.kt')
-rw-r--r--src/main/kotlin/moe/nea/blog/md/ItalicsParser.kt91
1 files changed, 91 insertions, 0 deletions
diff --git a/src/main/kotlin/moe/nea/blog/md/ItalicsParser.kt b/src/main/kotlin/moe/nea/blog/md/ItalicsParser.kt
new file mode 100644
index 0000000..afecf79
--- /dev/null
+++ b/src/main/kotlin/moe/nea/blog/md/ItalicsParser.kt
@@ -0,0 +1,91 @@
+package moe.nea.blog.md
+
+object ItalicsParser : InlineParser {
+ override fun detect(lookback: MarkdownFormat, rest: String): Boolean {
+ return lookback is Whitespace && "\\*+[^ ].*".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")
+
+ val isBold = firstStarCount >= 2
+ val isItalics = (firstStarCount % 2) == 1
+
+ val firstSequence = mutableListOf<MarkdownFormat>()
+ var remainingText = text.substring(firstStarCount)
+ var lastToken: MarkdownFormat = Begin() // TODO: dedicated begin token
+ while (true) {
+ val (element, next) = parser.parseInlineTextOnce(lastToken, remainingText)
+ remainingText = next
+ lastToken = element
+ firstSequence.add(element)
+ if (element !is Whitespace && next.startsWith("*")) break
+ }
+
+ 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)
+ if (secondStarCount == 2)
+ firstElement = Bold(firstElement)
+ if (secondStarCount == 1)
+ firstElement = Italics(firstElement)
+ if (secondStarCount == firstStarCount) {
+ if (isBold)
+ firstElement = Bold(firstElement)
+ if (isItalics)
+ firstElement = Italics(firstElement)
+ return Pair(firstElement, remainingText)
+ }
+
+ val secondSequence = mutableListOf<MarkdownFormat>()
+ lastToken = Begin()
+ while (true) {
+ val (element, next) = parser.parseInlineTextOnce(lastToken, remainingText)
+ remainingText = next
+ lastToken = element
+ secondSequence.add(element)
+ if (element !is Whitespace && next.startsWith("*")) break
+ }
+
+ 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")
+ }
+ var secondElement = parser.collapseInlineFormat(secondSequence)
+ var combined: MarkdownFormat = FormatSequence(firstElement, secondElement)
+ if (thirdStarCount == 1)
+ combined = Italics(combined)
+ if (thirdStarCount == 2)
+ combined = Bold(combined)
+ return Pair(combined, remainingText)
+ }
+
+} \ No newline at end of file