package info.mechyrdia.lore
data class TextParserScope<TContext>(
- val write: Appendable,
+ val write: StringBuilder,
val tags: TextParserTags<TContext>,
- val ctx: TContext
+ val ctx: TContext,
)
+class TextParserInternalState {
+ var suppressEndParagraph: Boolean = false
+}
+
sealed class InsideTag {
abstract val tag: String
sealed class TextParserState<TContext>(
val scope: TextParserScope<TContext>,
- val insideTags: List<InsideTag>
+ val insideTags: List<InsideTag>,
+ protected val internalState: TextParserInternalState,
) {
abstract fun processCharacter(char: Char): TextParserState<TContext>
abstract fun processEndOfText()
protected fun appendText(text: String) {
+ if (text.isEmpty()) return
+
scope.write.append(
insideTags.foldRight(censorText(text)) { insideTag, t ->
if (insideTag is InsideTag.IndirectTag) {
} else t
}
)
+ internalState.suppressEndParagraph = false
}
protected fun appendTextRaw(text: String) {
+ if (text.isEmpty()) return
+
scope.write.append(text)
+ internalState.suppressEndParagraph = false
}
- class Initial<TContext>(scope: TextParserScope<TContext>) : TextParserState<TContext>(scope, listOf()) {
+ protected fun nextParagraph() {
+ val newline = if (insideTags.none { it is InsideTag.DirectTag }) {
+ if (internalState.suppressEndParagraph)
+ "<p>"
+ else
+ "</p><p>"
+ } else
+ "<br/>"
+
+ appendTextRaw(newline)
+ }
+
+ protected fun cancelEndParagraph() {
+ internalState.suppressEndParagraph = true
+ }
+
+ protected fun cancelStartParagraph() {
+ if (scope.write.endsWith("<p>"))
+ scope.write.deleteRange(scope.write.length - 3, scope.write.length)
+ }
+
+ class Initial<TContext>(scope: TextParserScope<TContext>) : TextParserState<TContext>(scope, listOf(), TextParserInternalState()) {
override fun processCharacter(char: Char): TextParserState<TContext> {
return if (char == '[')
- OpenTag(scope, "", insideTags)
- else
- PlainText(scope, "$char", insideTags)
+ OpenTag(scope, "", insideTags, internalState)
+ else {
+ appendTextRaw("<p>")
+ PlainText(scope, "$char", insideTags, internalState)
+ }
}
override fun processEndOfText() {
}
}
- class PlainText<TContext>(scope: TextParserScope<TContext>, private val text: String, insideTags: List<InsideTag>) : TextParserState<TContext>(scope, insideTags) {
+ class PlainText<TContext>(scope: TextParserScope<TContext>, private val text: String, insideTags: List<InsideTag>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
override fun processCharacter(char: Char): TextParserState<TContext> {
return if (char == '[') {
appendText(text)
- OpenTag(scope, "", insideTags)
+ OpenTag(scope, "", insideTags, internalState)
} else if (char == '\n' && text.endsWith('\n')) {
appendText(text.removeSuffix("\n"))
- val newline = if (insideTags.none { it is InsideTag.DirectTag })
- "</p><p>"
- else
- "<br/>"
+ nextParagraph()
- appendTextRaw(newline)
- PlainText(scope, "", insideTags)
+ PlainText(scope, "", insideTags, internalState)
} else
- PlainText(scope, text + char, insideTags)
+ PlainText(scope, text + char, insideTags, internalState)
}
override fun processEndOfText() {
- appendText(text)
+ appendText(text.removeSuffix("\n"))
+ if (text.isNotBlank())
+ appendTextRaw("</p>")
}
}
- class NoFormatText<TContext>(scope: TextParserScope<TContext>, private val text: String, insideTags: List<InsideTag>) : TextParserState<TContext>(scope, insideTags) {
+ class NoFormatText<TContext>(scope: TextParserScope<TContext>, private val text: String, insideTags: List<InsideTag>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
override fun processCharacter(char: Char): TextParserState<TContext> {
val newText = text + char
return if (newText.endsWith("[/$NO_FORMAT_TAG]")) {
appendText(newText.removeSuffix("[/$NO_FORMAT_TAG]"))
- PlainText(scope, "", insideTags)
+ PlainText(scope, "", insideTags, internalState)
} else if (newText.endsWith('\n')) {
appendText(newText.removeSuffix("\n"))
appendTextRaw("<br/>")
- NoFormatText(scope, "", insideTags)
+ NoFormatText(scope, "", insideTags, internalState)
} else
- NoFormatText(scope, newText, insideTags)
+ NoFormatText(scope, newText, insideTags, internalState)
}
override fun processEndOfText() {
- appendText(text)
+ appendText(text.removeSuffix("\n"))
+ if (text.isNotBlank())
+ appendTextRaw("</p>")
}
}
- class OpenTag<TContext>(scope: TextParserScope<TContext>, private val tag: String, insideTags: List<InsideTag>) : TextParserState<TContext>(scope, insideTags) {
+ class OpenTag<TContext>(scope: TextParserScope<TContext>, private val tag: String, insideTags: List<InsideTag>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
override fun processCharacter(char: Char): TextParserState<TContext> {
return if (char == ']') {
if (tag.equals(NO_FORMAT_TAG, ignoreCase = true))
- NoFormatText(scope, "", insideTags)
- else when (val tagType = scope.tags[tag]) {
- is TextParserTagType.Direct<TContext> -> {
- appendTextRaw(tagType.begin(null, scope.ctx))
- PlainText(scope, "", insideTags + InsideTag.DirectTag(tag))
- }
+ NoFormatText(scope, "", insideTags, internalState)
+ else {
+ val tagType = scope.tags[tag]
+ if (tagType?.isBlock == true)
+ cancelStartParagraph()
- is TextParserTagType.Indirect<TContext> -> PlainText(scope, "", insideTags + InsideTag.IndirectTag(tag, null))
-
- else -> PlainText(scope, "[$tag]", insideTags)
+ when (tagType) {
+ is TextParserTagType.Direct<TContext> -> {
+ appendTextRaw(tagType.begin(null, scope.ctx))
+ PlainText(scope, "", insideTags + InsideTag.DirectTag(tag), internalState)
+ }
+
+ is TextParserTagType.Indirect<TContext> -> PlainText(scope, "", insideTags + InsideTag.IndirectTag(tag, null), internalState)
+
+ else -> PlainText(scope, "[$tag]", insideTags, internalState)
+ }
}
} else if (char == '/' && tag == "")
- CloseTag(scope, tag, insideTags)
+ CloseTag(scope, tag, insideTags, internalState)
else if (char == '=' && tag != "")
- TagParam(scope, tag, "", insideTags)
+ TagParam(scope, tag, "", insideTags, internalState)
else
- OpenTag(scope, tag + char, insideTags)
+ OpenTag(scope, tag + char, insideTags, internalState)
}
override fun processEndOfText() {
appendText("[$tag")
+ appendTextRaw("</p>")
}
}
- class TagParam<TContext>(scope: TextParserScope<TContext>, private val tag: String, private val param: String, insideTags: List<InsideTag>) : TextParserState<TContext>(scope, insideTags) {
+ class TagParam<TContext>(scope: TextParserScope<TContext>, private val tag: String, private val param: String, insideTags: List<InsideTag>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
override fun processCharacter(char: Char): TextParserState<TContext> {
- return if (char == ']')
- when (val tagType = scope.tags[tag]) {
+ return if (char == ']') {
+ val tagType = scope.tags[tag]
+ if (tagType?.isBlock == true)
+ cancelStartParagraph()
+
+ when (tagType) {
is TextParserTagType.Direct<TContext> -> {
appendTextRaw(tagType.begin(param, scope.ctx))
- PlainText(scope, "", insideTags + InsideTag.DirectTag(tag))
+ PlainText(scope, "", insideTags + InsideTag.DirectTag(tag), internalState)
}
- is TextParserTagType.Indirect<TContext> -> PlainText(scope, "", insideTags + InsideTag.IndirectTag(tag, param))
+ is TextParserTagType.Indirect<TContext> -> PlainText(scope, "", insideTags + InsideTag.IndirectTag(tag, param), internalState)
- else -> PlainText(scope, "[$tag=$param]", insideTags)
+ else -> PlainText(scope, "[$tag=$param]", insideTags, internalState)
}
- else
- TagParam(scope, tag, param + char, insideTags)
+ } else
+ TagParam(scope, tag, param + char, insideTags, internalState)
}
override fun processEndOfText() {
appendText("[$tag=$param")
+ appendTextRaw("</p>")
}
}
- class CloseTag<TContext>(scope: TextParserScope<TContext>, private val tag: String, insideTags: List<InsideTag>) : TextParserState<TContext>(scope, insideTags) {
+ class CloseTag<TContext>(scope: TextParserScope<TContext>, private val tag: String, insideTags: List<InsideTag>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
override fun processCharacter(char: Char): TextParserState<TContext> {
return if (char == ']') {
val tagType = scope.tags[tag]
- if (tagType is TextParserTagType.Direct<TContext> && insideTags.lastOrNull()?.tag == tag) {
+ val nextState = if (tagType is TextParserTagType.Direct<TContext> && insideTags.lastOrNull()?.tag == tag) {
appendTextRaw(tagType.end(scope.ctx))
- PlainText(scope, "", insideTags.dropLast(1))
+ PlainText(scope, "", insideTags.dropLast(1), internalState)
} else if (insideTags.isNotEmpty() && (insideTags.last() as? InsideTag.IndirectTag)?.tag == tag) {
- PlainText(scope, "", insideTags.dropLast(1))
+ PlainText(scope, "", insideTags.dropLast(1), internalState)
} else {
appendText("[/$tag]")
- PlainText(scope, "", insideTags)
+ PlainText(scope, "", insideTags, internalState)
}
- } else CloseTag(scope, tag + char, insideTags)
+
+ if (tagType?.isBlock == true)
+ cancelEndParagraph()
+
+ nextState
+ } else CloseTag(scope, tag + char, insideTags, internalState)
}
override fun processEndOfText() {
appendText("[/$tag")
+ appendTextRaw("</p>")
}
}
.fold<TextParserState<TContext>>(Initial(TextParserScope(builder, tags, context))) { state, char ->
state.processCharacter(char)
}.processEndOfText()
- return "<p>$builder</p>"
+ return "$builder"
}
}
}
package info.mechyrdia.lore
private val plainTextFormattingTag = TextParserTagType.Direct<Unit>(
+ false,
{ _, _ -> "" },
{ "" },
)
private val spacedFormattingTag = TextParserTagType.Direct<Unit>(
+ true,
{ _, _ -> " " },
{ " " },
)
-private val embeddedFormattingTag = TextParserTagType.Indirect<Unit> { _, _, _ -> "" }
+private val embeddedFormattingTag = TextParserTagType.Indirect<Unit>(false) { _, _, _ -> "" }
+private val embeddedBlockFormattingTag = TextParserTagType.Indirect<Unit>(true) { _, _, _ -> "" }
enum class TextParserFormattingTagPlainText(val type: TextParserTagType<Unit>) {
// Basic formatting
I(plainTextFormattingTag),
U(plainTextFormattingTag),
S(plainTextFormattingTag),
- SUP(spacedFormattingTag),
- SUB(spacedFormattingTag),
+ SUP(plainTextFormattingTag),
+ SUB(plainTextFormattingTag),
COLOR(plainTextFormattingTag),
IPA(plainTextFormattingTag),
CODE(plainTextFormattingTag),
IMAGE(embeddedFormattingTag),
MODEL(embeddedFormattingTag),
AUDIO(embeddedFormattingTag),
- QUIZ(embeddedFormattingTag),
+ QUIZ(embeddedBlockFormattingTag),
// Lists
UL(spacedFormattingTag),
// Conlangs
LANG(plainTextFormattingTag),
- ALPHABET(embeddedFormattingTag),
- VOCAB(embeddedFormattingTag),
+ ALPHABET(embeddedBlockFormattingTag),
+ VOCAB(embeddedBlockFormattingTag),
;
companion object {
REPLY(
TextParserTagType.Direct(
+ false,
{ _, _ -> ">>" },
- { "" },
+ { _ -> "" },
)
),
enum class TextParserReplyCounterTag(val type: TextParserTagType<CommentRepliesBuilder>) {
REPLY(
- TextParserTagType.Indirect { _, content, builder ->
+ TextParserTagType.Indirect(false) { _, content, builder ->
sanitizeId(content)?.let { id ->
builder.addReplyTag(Id(id))
}
import java.io.File
sealed class TextParserTagType<TContext> {
- data class Direct<TContext>(val beginFunc: (String?, TContext) -> String, val endFunc: (TContext) -> String) : TextParserTagType<TContext>() {
+ abstract val isBlock: Boolean
+
+ data class Direct<TContext>(override val isBlock: Boolean, val beginFunc: (String?, TContext) -> String, val endFunc: (TContext) -> String) : TextParserTagType<TContext>() {
fun begin(param: String?, context: TContext) = beginFunc(param, context)
fun end(context: TContext) = endFunc(context)
}
- data class Indirect<TContext>(val processFunc: (String?, String, TContext) -> String) : TextParserTagType<TContext>() {
+ data class Indirect<TContext>(override val isBlock: Boolean, val processFunc: (String?, String, TContext) -> String) : TextParserTagType<TContext>() {
fun process(param: String?, content: String, context: TContext) = processFunc(param, content, context)
}
}
fun <TContext> byIgnoringContext(tags: TextParserTags<Unit>) = TextParserTags<TContext>(tags.tags.mapValues { (_, tag) ->
when (tag) {
is TextParserTagType.Direct -> TextParserTagType.Direct(
+ tag.isBlock,
{ param, _ -> tag.begin(param, Unit) },
{ _ -> tag.end(Unit) }
)
- is TextParserTagType.Indirect -> TextParserTagType.Indirect { param, content, _ ->
+ is TextParserTagType.Indirect -> TextParserTagType.Indirect(tag.isBlock) { param, content, _ ->
tag.process(param, content, Unit)
}
}
// Basic formatting
B(
TextParserTagType.Direct(
+ false,
{ _, _ -> "<span style='font-weight: bold'>" },
- { "</span>" },
+ { _ -> "</span>" },
)
),
I(
TextParserTagType.Direct(
+ false,
{ _, _ -> "<span style='font-style: italic'>" },
- { "</span>" },
+ { _ -> "</span>" },
)
),
U(
TextParserTagType.Direct(
+ false,
{ _, _ -> "<span style='text-decoration: underline'>" },
- { "</span>" },
+ { _ -> "</span>" },
)
),
S(
TextParserTagType.Direct(
+ false,
{ _, _ -> "<span style='text-decoration: line-through'>" },
- { "</span>" },
+ { _ -> "</span>" },
)
),
SUP(
TextParserTagType.Direct(
+ false,
{ _, _ -> "<sup>" },
- { "</sup>" },
+ { _ -> "</sup>" },
)
),
SUB(
TextParserTagType.Direct(
+ false,
{ _, _ -> "<sub>" },
- { "</sub>" },
+ { _ -> "</sub>" },
)
),
COLOR(
TextParserTagType.Direct(
+ false,
{ tagParam, _ ->
val color = tagParam?.toIntOrNull(16)?.toString(16)?.padStart(6, '0')
val style = color?.let { " style=\"color: #$it\"" } ?: ""
"<span$style>"
},
- { "</span>" },
+ { _ -> "</span>" },
)
),
IPA(
TextParserTagType.Direct(
+ false,
{ _, _ -> "<span style='font-family: DejaVu Sans'>" },
- { "</span>" },
+ { _ -> "</span>" },
)
),
CODE(
TextParserTagType.Direct(
+ false,
{ _, _ -> "<span style='font-family: JetBrains Mono'><pre>" },
- { "</pre></span>" },
+ { _ -> "</pre></span>" },
)
),
H1(
- TextParserTagType.Indirect { _, content, _ ->
+ TextParserTagType.Indirect(true) { _, content, _ ->
"<h1>$content</h1><script>window.checkRedirectTarget('');</script>"
}
),
H2(
- TextParserTagType.Indirect { _, content, _ ->
+ TextParserTagType.Indirect(true) { _, content, _ ->
val anchor = headerContentToAnchor(content)
"</section><section><h2><a id='$anchor'></a>$content</h2><script>window.checkRedirectTarget('#$anchor');</script>"
}
),
H3(
- TextParserTagType.Indirect { _, content, _ ->
+ TextParserTagType.Indirect(true) { _, content, _ ->
val anchor = headerContentToAnchor(content)
"<h3><a id='$anchor'></a>$content</h3><script>window.checkRedirectTarget('#$anchor');</script>"
}
),
H4(
- TextParserTagType.Indirect { _, content, _ ->
+ TextParserTagType.Indirect(true) { _, content, _ ->
val anchor = headerContentToAnchor(content)
"<h4><a id='$anchor'></a>$content</h4><script>window.checkRedirectTarget('#$anchor');</script>"
}
),
H5(
- TextParserTagType.Indirect { _, content, _ ->
+ TextParserTagType.Indirect(true) { _, content, _ ->
val anchor = headerContentToAnchor(content)
"<h5><a id='$anchor'></a>$content</h5><script>window.checkRedirectTarget('#$anchor');</script>"
}
),
H6(
- TextParserTagType.Indirect { _, content, _ ->
+ TextParserTagType.Indirect(true) { _, content, _ ->
val anchor = headerContentToAnchor(content)
"<h6><a id='$anchor'></a>$content</h6><script>window.checkRedirectTarget('#$anchor');</script>"
}
),
ALIGN(
TextParserTagType.Direct(
+ true,
{ tagParam, _ ->
val alignments = setOf("left", "center", "right", "justify")
val alignment = tagParam?.takeIf { it in alignments }
val styleAttr = alignment?.let { " style=\"text-align: $it\"" } ?: ""
"<div$styleAttr>"
},
- { "</div>" },
+ { _ -> "</div>" },
)
),
ASIDE(
TextParserTagType.Direct(
+ true,
{ tagParam, _ ->
val floats = setOf("left", "right")
val float = tagParam?.takeIf { it in floats } ?: "right"
"<div style='float: $float; max-width: var(--aside-width)'>"
},
- { "</div>" },
+ { _ -> "</div>" },
)
),
BLOCKQUOTE(
- TextParserTagType.Direct({ _, _ ->
- "<blockquote>"
- }, { _ ->
- "</blockquote>"
- })
+ TextParserTagType.Direct(
+ true,
+ { _, _ -> "<blockquote>" },
+ { _ -> "</blockquote>" }
+ )
),
// Metadata
DESC(
TextParserTagType.Direct(
+ false,
{ _, _ -> "" },
- { "" },
+ { _ -> "" },
)
),
THUMB(
- TextParserTagType.Indirect { _, _, _ -> "" }
+ TextParserTagType.Indirect(true) { _, _, _ -> "" }
),
// Resource showing
IMAGE(
- TextParserTagType.Indirect { tagParam, content, _ ->
+ TextParserTagType.Indirect(false) { tagParam, content, _ ->
val imageUrl = sanitizeLink(content)
val (width, height) = getSizeParam(tagParam)
}
),
MODEL(
- TextParserTagType.Indirect { tagParam, content, _ ->
+ TextParserTagType.Indirect(false) { tagParam, content, _ ->
val modelUrl = sanitizeLink(content)
val (width, height) = getSizeParam(tagParam)
}
),
AUDIO(
- TextParserTagType.Indirect { _, content, _ ->
+ TextParserTagType.Indirect(false) { _, content, _ ->
val audioUrl = sanitizeLink(content)
"<audio src=\"/assets/sounds/$audioUrl\" controls></audio>"
}
),
QUIZ(
- TextParserTagType.Indirect { _, content, _ ->
+ TextParserTagType.Indirect(true) { _, content, _ ->
val quizText = File(Configuration.CurrentConfiguration.quizDir).combineSafe("$content.json").readText()
val quizJson = JsonStorageCodec.encodeToString(String.serializer(), quizText)
// Lists
UL(
TextParserTagType.Direct(
+ true,
{ _, _ -> "<ul>" },
- { "</ul>" },
+ { _ -> "</ul>" },
)
),
OL(
TextParserTagType.Direct(
+ true,
{ _, _ -> "<ol>" },
- { "</ol>" },
+ { _ -> "</ol>" },
)
),
LI(
TextParserTagType.Direct(
+ true,
{ _, _ -> "<li>" },
- { "</li>" },
+ { _ -> "</li>" },
)
),
// Tables
TABLE(
TextParserTagType.Direct(
+ true,
{ _, _ -> "<table>" },
- { "</table>" },
+ { _ -> "</table>" },
)
),
TR(
TextParserTagType.Direct(
+ true,
{ _, _ -> "<tr>" },
- { "</tr>" },
+ { _ -> "</tr>" },
)
),
TD(
TextParserTagType.Direct(
+ true,
{ tagParam, _ ->
val (width, height) = getSizeParam(tagParam)
val sizeAttrs = getTableSizeAttributes(width, height)
"<td$sizeAttrs>"
},
- { "</td>" },
+ { _ -> "</td>" },
)
),
TH(
TextParserTagType.Direct(
+ true,
{ tagParam, _ ->
val (width, height) = getSizeParam(tagParam)
val sizeAttrs = getTableSizeAttributes(width, height)
"<th$sizeAttrs>"
},
- { "</th>" },
+ { _ -> "</th>" },
)
),
// Hyperformatting
LINK(
TextParserTagType.Direct(
+ false,
{ tagParam, _ ->
val param = tagParam?.let { TextParserState.censorText(it) }
val url = param?.let { if (it.startsWith('/')) "/lore$it" else "./$it" }
"<a$attr>"
},
- { "</a>" },
+ { _ -> "</a>" },
)
),
EXTLINK(
TextParserTagType.Direct(
+ false,
{ tagParam, _ ->
val url = tagParam?.let { TextParserState.censorText(it) }
val attr = url?.let { " href=\"$it\"" } ?: ""
"<a$attr>"
},
- { "</a>" },
+ { _ -> "</a>" },
)
),
ANCHOR(
- TextParserTagType.Indirect { _, content, _ ->
+ TextParserTagType.Indirect(false) { _, content, _ ->
val anchor = sanitizeLink(content)
"<a id=\"$anchor\" name=\"$anchor\"></a>"
}
),
REDIRECT(
- TextParserTagType.Indirect { _, content, _ ->
+ TextParserTagType.Indirect(false) { _, content, _ ->
val target = TextParserState.censorText(content)
val url = if (target.startsWith('/')) "/lore$target" else "./$target"
val string = JsonPrimitive(url).toString()
// Conlangs
LANG(
- TextParserTagType.Indirect { tagParam, content, _ ->
+ TextParserTagType.Indirect(false) { tagParam, content, _ ->
if (tagParam?.equals("tylan", ignoreCase = true) == true) {
val uncensored = TextParserState.uncensorText(content)
val tylan = TylanAlphabetFont.tylanToFontAlphabet(uncensored)
}
),
ALPHABET(
- TextParserTagType.Indirect { _, content, _ ->
+ TextParserTagType.Indirect(true) { _, content, _ ->
if (content.equals("mechyrdian", ignoreCase = true)) {
"""
|<div class="mechyrdia-sans-box">
}
),
VOCAB(
- TextParserTagType.Indirect { _, content, _ ->
+ TextParserTagType.Indirect(true) { _, content, _ ->
if (content.isBlank())
""
else {
TH(TextParserFormattingTag.TH.type),
URL(
TextParserTagType.Direct(
+ false,
{ tagParam, _ ->
val url = tagParam?.let { TextParserState.censorText(it) }
val attr = url?.let { " href=\"$it\" rel=\"ugc nofollow\"" } ?: ""
LANG(TextParserFormattingTag.LANG.type),
IMGUR(
- TextParserTagType.Indirect { tagParam, content, _ ->
+ TextParserTagType.Indirect(false) { tagParam, content, _ ->
val imageUrl = sanitizeExtLink(content)
val (width, height) = getSizeParam(tagParam)
}
),
IMGBB(
- TextParserTagType.Indirect { tagParam, content, _ ->
+ TextParserTagType.Indirect(false) { tagParam, content, _ ->
val imageUrl = sanitizeExtLink(content)
val (width, height) = getSizeParam(tagParam)
),
REPLY(
- TextParserTagType.Indirect { _, content, _ ->
+ TextParserTagType.Indirect(false) { _, content, _ ->
sanitizeId(content)?.let { id ->
"<a href=\"/comment/view/$id\" rel=\"ugc\">>>$id</a>"
} ?: "[reply]$content[/reply]"
),
QUOTE(
- TextParserTagType.Direct({ _, _ ->
- "<blockquote>"
- }, { _ ->
- "</blockquote>"
- })
+ TextParserTagType.Direct(
+ true,
+ { _, _ -> "<blockquote>" },
+ { _ -> "</blockquote>" }
+ )
)
;
enum class TextParserToCBuilderTag(val type: TextParserTagType<TableOfContentsBuilder>) {
H1(
- TextParserTagType.Indirect { _, content, builder ->
+ TextParserTagType.Indirect(true) { _, content, builder ->
builder.addHeader(headerContentToLabel(content), 0, headerContentToAnchor(content))
- "[h1]$content[/h1]"
+ content
}
),
H2(
- TextParserTagType.Indirect { _, content, builder ->
+ TextParserTagType.Indirect(true) { _, content, builder ->
builder.addHeader(headerContentToLabel(content), 1, headerContentToAnchor(content))
- "[h2]$content[/h2]"
+ content
}
),
H3(
- TextParserTagType.Indirect { _, content, builder ->
+ TextParserTagType.Indirect(true) { _, content, builder ->
builder.addHeader(headerContentToLabel(content), 2, headerContentToAnchor(content))
- "[h3]$content[/h3]"
+ content
}
),
H4(
- TextParserTagType.Indirect { _, content, builder ->
+ TextParserTagType.Indirect(true) { _, content, builder ->
builder.addHeader(headerContentToLabel(content), 3, headerContentToAnchor(content))
- "[h4]$content[/h4]"
+ content
}
),
H5(
- TextParserTagType.Indirect { _, content, builder ->
+ TextParserTagType.Indirect(true) { _, content, builder ->
builder.addHeader(headerContentToLabel(content), 4, headerContentToAnchor(content))
- "[h5]$content[/h5]"
+ content
}
),
H6(
- TextParserTagType.Indirect { _, content, builder ->
+ TextParserTagType.Indirect(true) { _, content, builder ->
builder.addHeader(headerContentToLabel(content), 5, headerContentToAnchor(content))
- "[h6]$content[/h6]"
+ content
}
),
DESC(
- TextParserTagType.Indirect { _, content, builder ->
+ TextParserTagType.Indirect(false) { _, content, builder ->
builder.addDescription(descriptionContentToPlainText(content))
content
}
),
IMAGE(
- TextParserTagType.Indirect { param, content, builder ->
+ TextParserTagType.Indirect(false) { param, content, builder ->
builder.addImage(imagePathToOpenGraphValue(content))
- "[image=$param]$content[/image]"
+ ""
}
),
THUMB(
- TextParserTagType.Indirect { _, content, builder ->
+ TextParserTagType.Indirect(false) { _, content, builder ->
builder.addImage(imagePathToOpenGraphValue(content), true)
""
}