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:
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) {
|
while (i < len) {
|
||||||
val lineStart = i
|
val lineStart = i
|
||||||
while (i < len && rawContent[i] != '\n') i++
|
while (i < len && rawContent[i] != '\n' && rawContent[i] != '\r') i++
|
||||||
val lineEnd = 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
|
if (lineStart == lineEnd && i >= len) break
|
||||||
|
|
||||||
val line = rawContent.substring(lineStart, lineEnd)
|
val line = rawContent.substring(lineStart, lineEnd)
|
||||||
val trimmed = line.trimEnd()
|
val trimmed = line.trim()
|
||||||
if (trimmed.isEmpty()) continue
|
if (trimmed.isEmpty()) continue
|
||||||
|
|
||||||
if (skippingHeadwords) {
|
if (skippingHeadwords) {
|
||||||
|
|||||||
@@ -24,6 +24,40 @@ object DslAnnotatedParser {
|
|||||||
"ref", "ex", "e", "trn", "com", "lang", "sup", "'"
|
"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(
|
data class ColorScheme(
|
||||||
val secondaryText: Color,
|
val secondaryText: Color,
|
||||||
val labelText: Color,
|
val labelText: Color,
|
||||||
@@ -54,9 +88,9 @@ object DslAnnotatedParser {
|
|||||||
val stack = ArrayDeque<SpanStyle>()
|
val stack = ArrayDeque<SpanStyle>()
|
||||||
val refStack = ArrayDeque<Pair<Int, StringBuilder>>()
|
val refStack = ArrayDeque<Pair<Int, StringBuilder>>()
|
||||||
val lazyRefs = mutableListOf<LazyRef>()
|
val lazyRefs = mutableListOf<LazyRef>()
|
||||||
var lastChar: Char? = null
|
|
||||||
var accentNext = false
|
var accentNext = false
|
||||||
var currentIndent = 0
|
var currentIndent = 0
|
||||||
|
var mClosedPendingBreak = false
|
||||||
val exampleStyle = SpanStyle(color = colorScheme.secondaryText)
|
val exampleStyle = SpanStyle(color = colorScheme.secondaryText)
|
||||||
val labelStyle = SpanStyle(color = colorScheme.labelText)
|
val labelStyle = SpanStyle(color = colorScheme.labelText)
|
||||||
val linkStyle = SpanStyle(color = colorScheme.linkText, textDecoration = TextDecoration.Underline)
|
val linkStyle = SpanStyle(color = colorScheme.linkText, textDecoration = TextDecoration.Underline)
|
||||||
@@ -84,6 +118,20 @@ object DslAnnotatedParser {
|
|||||||
stack.forEach { builder.pushStyle(it) }
|
stack.forEach { builder.pushStyle(it) }
|
||||||
lazyRefs.clear()
|
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 {
|
fun marginIndent(tagName: String): Int {
|
||||||
@@ -99,20 +147,11 @@ object DslAnnotatedParser {
|
|||||||
when (val char = dsl[i]) {
|
when (val char = dsl[i]) {
|
||||||
'\\' -> {
|
'\\' -> {
|
||||||
if (i + 1 < length) {
|
if (i + 1 < length) {
|
||||||
val next = dsl[i + 1]
|
appendChar(dsl[i + 1])
|
||||||
builder.append(next)
|
|
||||||
if (refStack.isNotEmpty()) {
|
|
||||||
refStack.last().second.append(next)
|
|
||||||
}
|
|
||||||
lastChar = next
|
|
||||||
i += 2
|
i += 2
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
builder.append(char)
|
appendChar(char)
|
||||||
if (refStack.isNotEmpty()) {
|
|
||||||
refStack.last().second.append(char)
|
|
||||||
}
|
|
||||||
lastChar = char
|
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
'[' -> {
|
'[' -> {
|
||||||
@@ -148,6 +187,9 @@ object DslAnnotatedParser {
|
|||||||
} else if (tagName == "'") {
|
} else if (tagName == "'") {
|
||||||
accentNext = false
|
accentNext = false
|
||||||
}
|
}
|
||||||
|
if (tagName.startsWith("m")) {
|
||||||
|
mClosedPendingBreak = true
|
||||||
|
}
|
||||||
pop()
|
pop()
|
||||||
} else {
|
} else {
|
||||||
when (tagName) {
|
when (tagName) {
|
||||||
@@ -161,17 +203,15 @@ object DslAnnotatedParser {
|
|||||||
} else {
|
} else {
|
||||||
builder.append("\n")
|
builder.append("\n")
|
||||||
}
|
}
|
||||||
lastChar = '\n'
|
|
||||||
}
|
}
|
||||||
"p" -> {
|
"p" -> {
|
||||||
push(labelStyle)
|
push(labelStyle)
|
||||||
}
|
}
|
||||||
"b" -> push(SpanStyle(fontWeight = FontWeight.Bold))
|
"b" -> push(SpanStyle(fontWeight = FontWeight.Bold))
|
||||||
"m", "m0", "m1", "m2", "m3", "m4", "m5" -> {
|
"m", "m0", "m1", "m2", "m3", "m4", "m5" -> {
|
||||||
if (lastChar != '\n' && lastChar != null) {
|
if (builder.length > 0) {
|
||||||
if (refStack.isEmpty()) flushBlock() else builder.append("\n")
|
if (refStack.isEmpty()) flushBlock() else builder.append("\n")
|
||||||
}
|
}
|
||||||
lastChar = '\n'
|
|
||||||
currentIndent = marginIndent(tagName)
|
currentIndent = marginIndent(tagName)
|
||||||
push(exampleStyle)
|
push(exampleStyle)
|
||||||
}
|
}
|
||||||
@@ -181,7 +221,18 @@ object DslAnnotatedParser {
|
|||||||
refStack.addLast(builder.length to StringBuilder())
|
refStack.addLast(builder.length to StringBuilder())
|
||||||
}
|
}
|
||||||
"ex", "e" -> push(exampleStyle)
|
"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))
|
"com" -> push(SpanStyle(fontStyle = FontStyle.Italic, color = colorScheme.labelText))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,18 +240,11 @@ object DslAnnotatedParser {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
builder.append(char)
|
appendChar(char)
|
||||||
if (refStack.isNotEmpty()) {
|
|
||||||
refStack.last().second.append(char)
|
|
||||||
}
|
|
||||||
lastChar = char
|
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
builder.append(char)
|
appendChar(char)
|
||||||
if (refStack.isNotEmpty()) {
|
|
||||||
refStack.last().second.append(char)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (accentNext) {
|
if (accentNext) {
|
||||||
builder.append('\u0301')
|
builder.append('\u0301')
|
||||||
@@ -210,7 +254,6 @@ object DslAnnotatedParser {
|
|||||||
accentNext = false
|
accentNext = false
|
||||||
}
|
}
|
||||||
|
|
||||||
lastChar = char
|
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user