class Initial<TContext>(scope: TextParserScope<TContext>) : TextParserState<TContext>(scope, listOf(), listOf()) {
override fun processCharacter(char: Char): TextParserState<TContext> {
return if (char == '[')
- OpenTag<TContext>(scope, "", insideTags, insideDirectTags)
+ OpenTag(scope, "", insideTags, insideDirectTags)
else
- PlainText<TContext>(scope, "$char", insideTags, insideDirectTags)
+ PlainText(scope, "$char", insideTags, insideDirectTags)
}
override fun processEndOfText() {
override fun processCharacter(char: Char): TextParserState<TContext> {
return if (char == '[') {
appendText(text)
- OpenTag<TContext>(scope, "", insideTags, insideDirectTags)
+ OpenTag(scope, "", insideTags, insideDirectTags)
} else if (char == '\n' && text.endsWith('\n')) {
appendText(text.removeSuffix("\n"))
"<br/>"
appendTextRaw(newline)
- PlainText<TContext>(scope, "", insideTags, insideDirectTags)
+ PlainText(scope, "", insideTags, insideDirectTags)
} else
- PlainText<TContext>(scope, text + char, insideTags, insideDirectTags)
+ PlainText(scope, text + char, insideTags, insideDirectTags)
}
override fun processEndOfText() {
val newText = text + char
return if (newText.endsWith("[/$NO_FORMAT_TAG]")) {
appendText(newText.removeSuffix("[/$NO_FORMAT_TAG]"))
- PlainText<TContext>(scope, "", insideTags, insideDirectTags)
+ PlainText(scope, "", insideTags, insideDirectTags)
} else if (newText.endsWith('\n')) {
appendText(newText.removeSuffix("\n"))
appendTextRaw("<br/>")
- NoFormatText<TContext>(scope, "", insideTags, insideDirectTags)
+ NoFormatText(scope, "", insideTags, insideDirectTags)
} else
- NoFormatText<TContext>(scope, newText, insideTags, insideDirectTags)
+ NoFormatText(scope, newText, insideTags, insideDirectTags)
}
override fun processEndOfText() {
} else
PlainText(scope, "", insideTags + (tag to null), insideDirectTags)
} else if (char == '/' && tag == "")
- CloseTag<TContext>(scope, tag, insideTags, insideDirectTags)
+ CloseTag(scope, tag, insideTags, insideDirectTags)
else if (char == '=' && tag != "")
- TagParam<TContext>(scope, tag, "", insideTags, insideDirectTags)
+ TagParam(scope, tag, "", insideTags, insideDirectTags)
else
- OpenTag<TContext>(scope, tag + char, insideTags, insideDirectTags)
+ OpenTag(scope, tag + char, insideTags, insideDirectTags)
}
override fun processEndOfText() {
.replace(">", ">")
.replace("&", "&")
- fun <TContext> parseText(text: String, tags: TextParserTags<TContext>, context: TContext): String {
+ fun <TContext> parseText(text: String, tags: TextParserTags<TContext>, context: TContext): ParseOutcome {
val builder = StringBuilder()
try {
val fixedText = text.replace("\r\n", "\n").replace('\r', '\n')
fixedText.fold<TextParserState<TContext>>(Initial(TextParserScope(builder, tags, context))) { state, char -> state.processCharacter(char) }.processEndOfText()
} catch (ex: Exception) {
- return "<p>$builder</p><h1>INTERNAL ERROR</h1><pre>${ex.stackTraceToString()}</pre>"
+ return ParseOutcome("<p>$builder</p><h1>Internal Error!</h1><pre>${ex.stackTraceToString()}</pre>", false)
}
- return "<p>$builder</p>"
+ return ParseOutcome("<p>$builder</p>", true)
}
}
}
+
+data class ParseOutcome(val html: String, val succeeded: Boolean)
enum class TextParserToCBuilderTag(val type: TextParserTagType<TableOfContentsBuilder>) {
H1(
TextParserTagType.Indirect<TableOfContentsBuilder> { _, content, builder ->
- builder.add(headerContentToLabel(content), headerContentToAnchor(content))
- content
+ builder.add(headerContentToLabel(content), 0, headerContentToAnchor(content))
+ "[h1]$content[/h1]"
}
),
H2(
TextParserTagType.Indirect<TableOfContentsBuilder> { _, content, builder ->
- val label = headerContentToLabel(content)
- builder.add("- $label", headerContentToAnchor(content))
- content
+ builder.add(headerContentToLabel(content), 1, headerContentToAnchor(content))
+ "[h2]$content[/h2]"
}
),
H3(
TextParserTagType.Indirect<TableOfContentsBuilder> { _, content, builder ->
- val label = headerContentToLabel(content)
- builder.add("-- $label", headerContentToAnchor(content))
- content
+ builder.add(headerContentToLabel(content), 2, headerContentToAnchor(content))
+ "[h3]$content[/h3]"
}
),
H4(
TextParserTagType.Indirect<TableOfContentsBuilder> { _, content, builder ->
- val label = headerContentToLabel(content)
- builder.add("--- $label", headerContentToAnchor(content))
- content
+ builder.add(headerContentToLabel(content), 3, headerContentToAnchor(content))
+ "[h4]$content[/h4]"
}
),
H5(
TextParserTagType.Indirect<TableOfContentsBuilder> { _, content, builder ->
- val label = headerContentToLabel(content)
- builder.add("---- $label", headerContentToAnchor(content))
- content
+ builder.add(headerContentToLabel(content), 4, headerContentToAnchor(content))
+ "[h5]$content[/h5]"
}
),
H6(
TextParserTagType.Indirect<TableOfContentsBuilder> { _, content, builder ->
- val label = headerContentToLabel(content)
- builder.add("----- $label", headerContentToAnchor(content))
- content
+ builder.add(headerContentToLabel(content), 5, headerContentToAnchor(content))
+ "[h6]$content[/h6]"
}
);
package info.mechyrdia.lore
-@JvmInline
-value class TableOfContentsBuilder private constructor(private val links: MutableList<NavLink>) {
- constructor() : this(mutableListOf())
+class TableOfContentsBuilder {
+ private var title: String? = null
+ private val levels = mutableListOf<Int>()
+ private val links = mutableListOf<NavLink>()
- fun add(text: String, toAnchor: String) = links.plusAssign(NavLink("#$toAnchor", text, aClasses = "left"))
+ fun add(text: String, level: Int, toAnchor: String) {
+ if (level == 0) {
+ title = text
+ return
+ }
+
+ val number = if (level > levels.size) {
+ if (level == levels.size + 1) {
+ levels.add(1)
+ levels.joinToString(separator = ".") { it.toString() }
+ } else
+ throw IllegalArgumentException("[h${level + 1}] cannot come after [h${levels.size + 1}]!")
+ } else {
+ levels.addAll(levels.take(level).also { levels.clear() }.mapIndexed { i, n -> if (i == level - 1) n + 1 else n })
+ levels.joinToString(separator = ".") { it.toString() }
+ }
+
+ links.plusAssign(NavLink("#$toAnchor", "$number. $text", aClasses = "left"))
+ }
+
+ fun toPageTitle() = title!!
fun toNavBar(): List<NavItem> = links.toList()
}