From 4201cb12a913316455af4df79ea67859ab250d6b Mon Sep 17 00:00:00 2001 From: Ilia Permiashkin Date: Tue, 27 Oct 2026 12:34:51 +0200 Subject: [PATCH] feat: Parse an ATX heading followed by `---` or `===` as a heading (for IJPL-94630) --- CHANGELOG.md | 1 + .../providers/SetextHeaderProvider.kt | 6 ++++++ .../resources/data/parser/hruleAndSetext.md | 4 ++++ .../resources/data/parser/hruleAndSetext.txt | 17 +++++++++++++++++ 4 files changed, 28 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89fd12d5..af5c66e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## [Unreleased] - Decode character references above U+FFFF, such as `😀` or `𝔄`, to the right character instead of a truncated one, and replace `�`, surrogates and out of range numeric references with U+FFFD as required by CommonMark +- Parse an ATX heading followed by `---` or `===` as a heading, not as setext content (IJPL-94630) ## [0.7.18] diff --git a/src/commonMain/kotlin/org/intellij/markdown/parser/markerblocks/providers/SetextHeaderProvider.kt b/src/commonMain/kotlin/org/intellij/markdown/parser/markerblocks/providers/SetextHeaderProvider.kt index bf20e06f..14e28afa 100644 --- a/src/commonMain/kotlin/org/intellij/markdown/parser/markerblocks/providers/SetextHeaderProvider.kt +++ b/src/commonMain/kotlin/org/intellij/markdown/parser/markerblocks/providers/SetextHeaderProvider.kt @@ -22,6 +22,10 @@ class SetextHeaderProvider : MarkerBlockProvider { if (stateInfo.nextConstraints != currentConstaints) { return emptyList() } + // An ATX heading can't be the content of a setext heading + if (ATX_HEADER_PROVIDER.interruptsParagraph(pos, currentConstaints)) { + return emptyList() + } if (MarkerBlockProvider.isStartOfLineWithConstraints(pos, currentConstaints) && getNextLineFromConstraints(pos, currentConstaints)?.let { REGEX.matches(it) } == true) { return listOf(SetextHeaderMarkerBlock(currentConstaints, productionHolder)) @@ -50,5 +54,7 @@ class SetextHeaderProvider : MarkerBlockProvider { companion object { val REGEX: Regex = Regex("^ {0,3}(-+|=+) *$") + + private val ATX_HEADER_PROVIDER = AtxHeaderProvider() } } diff --git a/src/fileBasedTest/resources/data/parser/hruleAndSetext.md b/src/fileBasedTest/resources/data/parser/hruleAndSetext.md index 9d66e7d8..706fc52c 100644 --- a/src/fileBasedTest/resources/data/parser/hruleAndSetext.md +++ b/src/fileBasedTest/resources/data/parser/hruleAndSetext.md @@ -1,3 +1,7 @@ *** --- ___ +# atx +--- +# atx +=== diff --git a/src/fileBasedTest/resources/data/parser/hruleAndSetext.txt b/src/fileBasedTest/resources/data/parser/hruleAndSetext.txt index 72750697..006ba75c 100644 --- a/src/fileBasedTest/resources/data/parser/hruleAndSetext.txt +++ b/src/fileBasedTest/resources/data/parser/hruleAndSetext.txt @@ -4,4 +4,21 @@ Markdown:MARKDOWN_FILE Markdown:HORIZONTAL_RULE('---') Markdown:EOL('\n') Markdown:HORIZONTAL_RULE('___') + Markdown:EOL('\n') + Markdown:ATX_1 + Markdown:ATX_HEADER('#') + Markdown:ATX_CONTENT + WHITE_SPACE(' ') + Markdown:TEXT('atx') + Markdown:EOL('\n') + Markdown:HORIZONTAL_RULE('---') + Markdown:EOL('\n') + Markdown:ATX_1 + Markdown:ATX_HEADER('#') + Markdown:ATX_CONTENT + WHITE_SPACE(' ') + Markdown:TEXT('atx') + Markdown:EOL('\n') + Markdown:PARAGRAPH + Markdown:TEXT('===') Markdown:EOL('\n') \ No newline at end of file