fix(dsl): render articles faithfully

Split lines on LF, CRLF and lone CR like the indexer, strip leading whitespace from body lines, break the paragraph after a closing margin tag, and apply named colors from [c] tags.
This commit is contained in:
OneWay committed 2026-09-18 01:50:00 +08:00
1 parent bddcb99177
commit f51684367a
2 files changed
+77 -29

No files matched your search

@@ -180,14 +180,19 @@ internal fun parseDslArticleContent(rawContent: String): String {
while (i < len) {
val lineStart = i
while (i < len && rawContent[i] != '\n') i++
while (i < len && rawContent[i] != '\n' && rawContent[i] != '\r') i++
val lineEnd = i
if (i < len && rawContent[i] == '\n') i++
if (i < len && rawContent[i] == '\r') {
i++
if (i < len && rawContent[i] == '\n') i++
} else if (i < len && rawContent[i] == '\n') {
i++
}
if (lineStart == lineEnd && i >= len) break
val line = rawContent.substring(lineStart, lineEnd)
val trimmed = line.trimEnd()
val trimmed = line.trim()
if (trimmed.isEmpty()) continue
if (skippingHeadwords) {
@@ -24,6 +24,40 @@ object DslAnnotatedParser {
"ref", "ex", "e", "trn", "com", "lang", "sup", "'"
)
private val DSL_NAMED_COLORS = mapOf(
"black" to Color(0xFF000000),
"silver" to Color(0xFFC0C0C0),
"gray" to Color(0xFF808080),
"grey" to Color(0xFF808080),
"lightgray" to Color(0xFFD3D3D3),
"lightgrey" to Color(0xFFD3D3D3),
"darkgray" to Color(0xFFA9A9A9),
"darkgrey" to Color(0xFFA9A9A9),
"white" to Color(0xFFFFFFFF),
"maroon" to Color(0xFF800000),
"red" to Color(0xFFFF0000),
"darkred" to Color(0xFF8B0000),
"crimson" to Color(0xFFDC143C),
"brown" to Color(0xFFA52A2A),
"orange" to Color(0xFFFFA500),
"pink" to Color(0xFFFFC0CB),
"purple" to Color(0xFF800080),
"violet" to Color(0xFFEE82EE),
"fuchsia" to Color(0xFFFF00FF),
"magenta" to Color(0xFFFF00FF),
"olive" to Color(0xFF808000),
"yellow" to Color(0xFFFFFF00),
"green" to Color(0xFF008000),
"darkgreen" to Color(0xFF006400),
"lime" to Color(0xFF00FF00),
"teal" to Color(0xFF008080),
"aqua" to Color(0xFF00FFFF),
"cyan" to Color(0xFF00FFFF),
"navy" to Color(0xFF000080),
"blue" to Color(0xFF0000FF),
"darkblue" to Color(0xFF00008B),
)
data class ColorScheme(
val secondaryText: Color,
val labelText: Color,
@@ -54,9 +88,9 @@ object DslAnnotatedParser {
val stack = ArrayDeque<SpanStyle>()
val refStack = ArrayDeque<Pair<Int, StringBuilder>>()
val lazyRefs = mutableListOf<LazyRef>()
var lastChar: Char? = null
var accentNext = false
var currentIndent = 0
var mClosedPendingBreak = false
val exampleStyle = SpanStyle(color = colorScheme.secondaryText)
val labelStyle = SpanStyle(color = colorScheme.labelText)
val linkStyle = SpanStyle(color = colorScheme.linkText, textDecoration = TextDecoration.Underline)
@@ -84,6 +118,20 @@ object DslAnnotatedParser {
stack.forEach { builder.pushStyle(it) }
lazyRefs.clear()
}
mClosedPendingBreak = false
}
fun appendChar(char: Char) {
if (mClosedPendingBreak) {
mClosedPendingBreak = false
if (refStack.isEmpty() && !char.isWhitespace()) {
flushBlock()
}
}
builder.append(char)
if (refStack.isNotEmpty()) {
refStack.last().second.append(char)
}
}
fun marginIndent(tagName: String): Int {
@@ -99,20 +147,11 @@ object DslAnnotatedParser {
when (val char = dsl[i]) {
'\\' -> {
if (i + 1 < length) {
val next = dsl[i + 1]
builder.append(next)
if (refStack.isNotEmpty()) {
refStack.last().second.append(next)
}
lastChar = next
appendChar(dsl[i + 1])
i += 2
continue
}
builder.append(char)
if (refStack.isNotEmpty()) {
refStack.last().second.append(char)
}
lastChar = char
appendChar(char)
i++
}
'[' -> {
@@ -148,6 +187,9 @@ object DslAnnotatedParser {
} else if (tagName == "'") {
accentNext = false
}
if (tagName.startsWith("m")) {
mClosedPendingBreak = true
}
pop()
} else {
when (tagName) {
@@ -161,17 +203,15 @@ object DslAnnotatedParser {
} else {
builder.append("\n")
}
lastChar = '\n'
}
"p" -> {
push(labelStyle)
}
"b" -> push(SpanStyle(fontWeight = FontWeight.Bold))
"m", "m0", "m1", "m2", "m3", "m4", "m5" -> {
if (lastChar != '\n' && lastChar != null) {
if (builder.length > 0) {
if (refStack.isEmpty()) flushBlock() else builder.append("\n")
}
lastChar = '\n'
currentIndent = marginIndent(tagName)
push(exampleStyle)
}
@@ -181,7 +221,18 @@ object DslAnnotatedParser {
refStack.addLast(builder.length to StringBuilder())
}
"ex", "e" -> push(exampleStyle)
"c", "t", "trn", "lang", "sup" -> push(SpanStyle())
"c" -> {
val colorName = if (spaceIdx >= 0) {
tagWithParams.substring(spaceIdx + 1).trim().lowercase()
} else {
null
}
push(when {
colorName == null -> labelStyle
else -> DSL_NAMED_COLORS[colorName]?.let { SpanStyle(color = it) } ?: SpanStyle()
})
}
"t", "trn", "lang", "sup" -> push(SpanStyle())
"com" -> push(SpanStyle(fontStyle = FontStyle.Italic, color = colorScheme.labelText))
}
}
@@ -189,18 +240,11 @@ object DslAnnotatedParser {
continue
}
}
builder.append(char)
if (refStack.isNotEmpty()) {
refStack.last().second.append(char)
}
lastChar = char
appendChar(char)
i++
}
else -> {
builder.append(char)
if (refStack.isNotEmpty()) {
refStack.last().second.append(char)
}
appendChar(char)
if (accentNext) {
builder.append('\u0301')
@@ -210,7 +254,6 @@ object DslAnnotatedParser {
accentNext = false
}
lastChar = char
i++
}
}