var suppressEndParagraph: Boolean = false
}
-sealed class InsideTag {
- abstract val tag: String
-
- data class DirectTag(override val tag: String) : InsideTag()
- data class IndirectTag(override val tag: String, val param: String?) : InsideTag()
-}
-
sealed class TextParserState<TContext>(
val scope: TextParserScope<TContext>,
- val insideTags: List<InsideTag>,
+ val insideTags: List<String>,
protected val internalState: TextParserInternalState,
) {
abstract fun processCharacter(char: Char): TextParserState<TContext>
protected fun appendText(text: String) {
if (text.isEmpty()) return
- scope.write.append(
- insideTags.foldRight(censorText(text)) { insideTag, t ->
- if (insideTag is InsideTag.IndirectTag) {
- val (tag, param) = insideTag
- (scope.tags[tag] as? TextParserTagType.Indirect<TContext>)
- ?.process(param, t, scope.ctx)
- ?: "[$tag${param?.let { "=$it" } ?: ""}]$t[/$tag]"
- } else t
- }
- )
+ scope.write.append(censorText(text))
internalState.suppressEndParagraph = false
}
}
protected fun nextParagraph() {
- val newline = if (insideTags.none { it is InsideTag.DirectTag }) {
+ val newline = if (insideTags.isEmpty()) {
if (internalState.suppressEndParagraph)
"<p>"
else
}
}
- class PlainText<TContext>(scope: TextParserScope<TContext>, private val text: String, insideTags: List<InsideTag>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
+ class PlainText<TContext>(scope: TextParserScope<TContext>, private val text: String, insideTags: List<String>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
override fun processCharacter(char: Char): TextParserState<TContext> {
return if (char == '[') {
appendText(text)
}
}
- class NoFormatText<TContext>(scope: TextParserScope<TContext>, private val text: String, insideTags: List<InsideTag>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
+ class NoFormatText<TContext>(scope: TextParserScope<TContext>, private val text: String, insideTags: List<String>, 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]")) {
}
}
- class OpenTag<TContext>(scope: TextParserScope<TContext>, private val tag: String, insideTags: List<InsideTag>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
+ class InsideIndirectTag<TContext>(scope: TextParserScope<TContext>, private val tagName: String, private val tagType: TextParserTagType.Indirect<TContext>, private val param: String?, private val text: String, insideTags: List<String>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
+ override fun processCharacter(char: Char): TextParserState<TContext> {
+ val newText = text + char
+ return if (newText.endsWith("[/$tagName]")) {
+ appendTextRaw(tagType.process(param, censorText(newText.removeSuffix("[/$tagName]")), scope.ctx))
+
+ if (tagType.isBlock)
+ cancelEndParagraph()
+
+ PlainText(scope, "", insideTags, internalState)
+ } else
+ InsideIndirectTag(scope, tagName, tagType, param, newText, insideTags, internalState)
+ }
+
+ override fun processEndOfText() {
+ appendTextRaw(tagType.process(param, censorText(text), scope.ctx))
+ if (text.isNotBlank())
+ lastParagraph()
+ }
+ }
+
+ class OpenTag<TContext>(scope: TextParserScope<TContext>, private val tag: String, insideTags: List<String>, 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))
when (tagType) {
is TextParserTagType.Direct<TContext> -> {
appendTextRaw(tagType.begin(null, scope.ctx))
- PlainText(scope, "", insideTags + InsideTag.DirectTag(tag), internalState)
+ PlainText(scope, "", insideTags + tag, internalState)
}
- is TextParserTagType.Indirect<TContext> -> PlainText(scope, "", insideTags + InsideTag.IndirectTag(tag, null), internalState)
+ is TextParserTagType.Indirect<TContext> -> InsideIndirectTag(scope, tag, tagType, null, "", insideTags, internalState)
else -> PlainText(scope, "[$tag]", insideTags, internalState)
}
}
}
- class TagParam<TContext>(scope: TextParserScope<TContext>, private val tag: String, private val param: String, insideTags: List<InsideTag>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
+ class TagParam<TContext>(scope: TextParserScope<TContext>, private val tag: String, private val param: String, insideTags: List<String>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
override fun processCharacter(char: Char): TextParserState<TContext> {
return if (char == ']') {
val tagType = scope.tags[tag]
when (tagType) {
is TextParserTagType.Direct<TContext> -> {
appendTextRaw(tagType.begin(param, scope.ctx))
- PlainText(scope, "", insideTags + InsideTag.DirectTag(tag), internalState)
+ PlainText(scope, "", insideTags + tag, internalState)
}
- is TextParserTagType.Indirect<TContext> -> PlainText(scope, "", insideTags + InsideTag.IndirectTag(tag, param), internalState)
+ is TextParserTagType.Indirect<TContext> -> InsideIndirectTag(scope, tag, tagType, param, "", insideTags, internalState)
else -> PlainText(scope, "[$tag=$param]", insideTags, internalState)
}
}
}
- class CloseTag<TContext>(scope: TextParserScope<TContext>, private val tag: String, insideTags: List<InsideTag>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
+ class CloseTag<TContext>(scope: TextParserScope<TContext>, private val tag: String, insideTags: List<String>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
override fun processCharacter(char: Char): TextParserState<TContext> {
return if (char == ']') {
val tagType = scope.tags[tag]
- val nextState = if (tagType is TextParserTagType.Direct<TContext> && insideTags.lastOrNull()?.tag == tag) {
+ val nextState = if (tagType is TextParserTagType.Direct<TContext> && insideTags.lastOrNull() == tag) {
appendTextRaw(tagType.end(scope.ctx))
-
- PlainText(scope, "", insideTags.dropLast(1), internalState)
- } else if (insideTags.isNotEmpty() && (insideTags.last() as? InsideTag.IndirectTag)?.tag == tag) {
PlainText(scope, "", insideTags.dropLast(1), internalState)
} else {
appendText("[/$tag]")