Skip to content

Commit b9e6b1e

Browse files
committed
refactor: extract CODE_FENCE content parsing into shared extractCodeFenceContent utility
1 parent 3b3c40a commit b9e6b1e

3 files changed

Lines changed: 26 additions & 21 deletions

File tree

multiplatform-markdown-renderer-latex/src/commonMain/kotlin/com/mikepenz/markdown/latex/MarkdownBlockMath.kt

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import com.mikepenz.markdown.compose.LocalMarkdownColors
1212
import com.mikepenz.markdown.compose.LocalMarkdownTypography
1313
import com.mikepenz.markdown.compose.components.MarkdownComponent
1414
import com.mikepenz.markdown.latex.model.DisplayList
15+
import com.mikepenz.markdown.utils.extractCodeFenceContent
1516
import com.mikepenz.markdown.utils.extractMathContent
1617
import org.intellij.markdown.MarkdownElementTypes
1718
import org.intellij.markdown.ast.ASTNode
@@ -28,13 +29,7 @@ fun MarkdownBlockMath(content: String, node: ASTNode) {
2829
val fontSize = typography.paragraph.fontSize.value
2930

3031
val latex = when (node.type) {
31-
MarkdownElementTypes.CODE_FENCE -> {
32-
if (node.children.size >= 3) {
33-
val start = node.children[2].startOffset
34-
val end = node.children[(node.children.size - 2).coerceAtLeast(2)].endOffset
35-
content.subSequence(start, end).toString().replaceIndent()
36-
} else ""
37-
}
32+
MarkdownElementTypes.CODE_FENCE -> node.extractCodeFenceContent(content)?.second ?: ""
3833
else -> node.extractMathContent(content)
3934
}
4035

multiplatform-markdown-renderer/src/commonMain/kotlin/com/mikepenz/markdown/compose/elements/MarkdownCode.kt

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import com.mikepenz.markdown.compose.LocalMarkdownDimens
2828
import com.mikepenz.markdown.compose.LocalMarkdownPadding
2929
import com.mikepenz.markdown.compose.LocalMarkdownTypography
3030
import com.mikepenz.markdown.compose.elements.material.MarkdownBasicText
31+
import com.mikepenz.markdown.utils.extractCodeFenceContent
3132
import org.intellij.markdown.MarkdownTokenTypes
3233
import org.intellij.markdown.ast.ASTNode
3334
import org.intellij.markdown.ast.findChildOfType
@@ -70,20 +71,8 @@ fun MarkdownCodeFence(
7071
style: TextStyle = LocalMarkdownTypography.current.code,
7172
block: @Composable (String, String?, TextStyle) -> Unit = { code, language, style -> MarkdownCode(code = code, language = language, style = style) },
7273
) {
73-
// CODE_FENCE_START, FENCE_LANG, EOL, {content // CODE_FENCE_CONTENT // x-times}, CODE_FENCE_END
74-
// CODE_FENCE_START, EOL, {content // CODE_FENCE_CONTENT // x-times}, EOL
75-
// CODE_FENCE_START, EOL, {content // CODE_FENCE_CONTENT // x-times}
76-
// CODE_FENCE_START, FENCE_LANG, EOL, {content // CODE_FENCE_CONTENT // x-times}
77-
78-
val language = node.findChildOfType(MarkdownTokenTypes.FENCE_LANG)?.getTextInNode(content)?.toString()
79-
if (node.children.size >= 3) {
80-
val start = node.children[2].startOffset
81-
val minCodeFenceCount = if (language != null && node.children.size > 3) 3 else 2
82-
val end = node.children[(node.children.size - 2).coerceAtLeast(minCodeFenceCount)].endOffset
83-
block(content.subSequence(start, end).toString().replaceIndent(), language, style)
84-
} else {
85-
// invalid code block, skipping
86-
}
74+
val (language, code) = node.extractCodeFenceContent(content) ?: return
75+
block(code, language, style)
8776
}
8877

8978
@Composable

multiplatform-markdown-renderer/src/commonMain/kotlin/com/mikepenz/markdown/utils/Extensions.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,27 @@ fun ASTNode.extractMathContent(content: String): String {
3939
return content.substring(inner.first().startOffset, inner.last().endOffset).trim()
4040
}
4141

42+
/**
43+
* Extracts the content and optional language from a CODE_FENCE node.
44+
* Handles both complete fences (with closing ```) and unclosed fences during live editing.
45+
*
46+
* @return a pair of (language, code), or `null` if the fence has fewer than 3 children.
47+
*/
48+
fun ASTNode.extractCodeFenceContent(content: String): Pair<String?, String>? {
49+
// invalid code block, skipping
50+
if (children.size < 3) return null
51+
// CODE_FENCE_START, FENCE_LANG, EOL, {content // CODE_FENCE_CONTENT // x-times}, CODE_FENCE_END
52+
// CODE_FENCE_START, EOL, {content // CODE_FENCE_CONTENT // x-times}, EOL
53+
// CODE_FENCE_START, EOL, {content // CODE_FENCE_CONTENT // x-times}
54+
// CODE_FENCE_START, FENCE_LANG, EOL, {content // CODE_FENCE_CONTENT // x-times}
55+
val language = findChildOfType(MarkdownTokenTypes.FENCE_LANG)?.getTextInNode(content)?.toString()
56+
val start = children[2].startOffset
57+
val minCodeFenceCount = if (language != null && children.size > 3) 3 else 2
58+
val end = children[(children.size - 2).coerceAtLeast(minCodeFenceCount)].endOffset
59+
val code = content.subSequence(start, end).toString().replaceIndent()
60+
return language to code
61+
}
62+
4263
/**
4364
* Find a child node recursive
4465
*/

0 commit comments

Comments
 (0)