Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Put code fence indents into separate whitespace nodes instead of fence content #112

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,6 @@ internal class HtmlBlockGeneratingProvider : GeneratingProvider {

internal class CodeFenceGeneratingProvider : GeneratingProvider {
override fun processNode(visitor: HtmlGenerator.HtmlGeneratingVisitor, text: String, node: ASTNode) {
val indentBefore = node.getTextInNode(text).commonPrefixWith(" ".repeat(10)).length

visitor.consumeHtml("<pre>")

var state = 0
Expand All @@ -160,7 +158,7 @@ internal class CodeFenceGeneratingProvider : GeneratingProvider {
for (child in childrenToConsider) {
if (state == 1 && child.type in listOf(MarkdownTokenTypes.CODE_FENCE_CONTENT,
MarkdownTokenTypes.EOL)) {
visitor.consumeHtml(HtmlGenerator.trimIndents(HtmlGenerator.leafText(text, child, false), indentBefore))
visitor.consumeHtml(HtmlGenerator.leafText(text, child, false))
lastChildWasContent = child.type == MarkdownTokenTypes.CODE_FENCE_CONTENT
}
if (state == 0 && child.type == MarkdownTokenTypes.FENCE_LANG) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import org.intellij.markdown.parser.constraints.*
import org.intellij.markdown.parser.markerblocks.MarkerBlock
import org.intellij.markdown.parser.markerblocks.MarkerBlockImpl
import org.intellij.markdown.parser.sequentialparsers.SequentialParser
import kotlin.math.min
import kotlin.text.Regex

class CodeFenceMarkerBlock(myConstraints: MarkdownConstraints,
private val productionHolder: ProductionHolder,
private val fenceStart: String) : MarkerBlockImpl(myConstraints, productionHolder.mark()) {
class CodeFenceMarkerBlock(
myConstraints: MarkdownConstraints,
private val productionHolder: ProductionHolder,
private val fenceStart: String,
private val fenceIndent: Int
) : MarkerBlockImpl(myConstraints, productionHolder.mark()) {
override fun allowsSubBlocks(): Boolean = false

override fun isInterestingOffset(pos: LookaheadText.Position): Boolean = true //pos.offsetInCurrentLine == -1
Expand Down Expand Up @@ -54,15 +56,25 @@ class CodeFenceMarkerBlock(myConstraints: MarkdownConstraints,
realInterestingOffset = nextLineOffset

val currentLine = nextLineConstraints.eatItselfFromString(pos.currentLine)
// Skip characters from current constraints and advance position
val charactersToSkip = 1 + constraints.getCharsEaten(pos.currentLine)
val advancedPosition = pos.nextPosition(charactersToSkip) ?: return MarkerBlock.ProcessingResult.CANCEL
// Calculate actual fence indent (it can not exceed the fenceIndent)
val indent = advancedPosition.charsToNonWhitespace()?.coerceAtMost(fenceIndent) ?: 0
val startOffset = advancedPosition.offset + indent
val contentRange = startOffset.coerceAtMost(nextLineOffset)..nextLineOffset
if (endsThisFence(currentLine)) {
productionHolder.addProduction(listOf(SequentialParser.Node(pos.offset + 1..pos.nextLineOrEofOffset,
MarkdownTokenTypes.CODE_FENCE_END)))
productionHolder.addProduction(listOf(SequentialParser.Node(
startOffset..nextLineOffset,
MarkdownTokenTypes.CODE_FENCE_END
)))
scheduleProcessingResult(nextLineOffset, MarkerBlock.ProcessingResult.DEFAULT)
} else {
val contentRange = min(pos.offset + 1 + constraints.getCharsEaten(pos.currentLine), nextLineOffset)..nextLineOffset
if (contentRange.first < contentRange.last) {
productionHolder.addProduction(listOf(SequentialParser.Node(
contentRange, MarkdownTokenTypes.CODE_FENCE_CONTENT)))
contentRange,
MarkdownTokenTypes.CODE_FENCE_CONTENT
)))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,34 @@ class CodeFenceProvider : MarkerBlockProvider<MarkerProcessor.StateInfo> {
override fun createMarkerBlocks(pos: LookaheadText.Position,
productionHolder: ProductionHolder,
stateInfo: MarkerProcessor.StateInfo): List<MarkerBlock> {
val fenceAndInfo = getFenceStartAndInfo(pos, stateInfo.currentConstraints)
if (fenceAndInfo != null) {
createNodesForFenceStart(pos, fenceAndInfo, productionHolder)
return listOf(CodeFenceMarkerBlock(stateInfo.currentConstraints, productionHolder, fenceAndInfo.first))
} else {
return emptyList()
}
val fenceAndInfo = getFenceStartAndInfo(pos, stateInfo.currentConstraints) ?: return emptyList()
val indent = createNodesForFenceStart(pos, fenceAndInfo, productionHolder) ?: return emptyList()
return listOf(CodeFenceMarkerBlock(stateInfo.currentConstraints, productionHolder, fenceAndInfo.first, indent))
}

override fun interruptsParagraph(pos: LookaheadText.Position, constraints: MarkdownConstraints): Boolean {
return getFenceStartAndInfo(pos, constraints) != null
}

private fun createNodesForFenceStart(pos: LookaheadText.Position, fenceAndInfo: Pair<String, String>, productionHolder: ProductionHolder) {
private fun createNodesForFenceStart(
pos: LookaheadText.Position,
fenceAndInfo: Pair<String, String>,
productionHolder: ProductionHolder
): Int? {
val infoStartPosition = pos.nextLineOrEofOffset - fenceAndInfo.second.length
// Count the number of spaces before start element, so we can exclude them from resulting tree element
val indent = pos.charsToNonWhitespace() ?: 0
// If the current fence is indented with more than 3 spaces, it becomes a code block
if (indent > 3) {
return null
}
@Suppress("NAME_SHADOWING")
val pos = pos.nextPosition(indent) ?: return null
productionHolder.addProduction(listOf(SequentialParser.Node(pos.offset..infoStartPosition, MarkdownTokenTypes.CODE_FENCE_START)))
if (fenceAndInfo.second.length > 0) {
if (fenceAndInfo.second.isNotEmpty()) {
productionHolder.addProduction(listOf(SequentialParser.Node(infoStartPosition..pos.nextLineOrEofOffset, MarkdownTokenTypes.FENCE_LANG)))
}
return indent
}

private fun getFenceStartAndInfo(pos: LookaheadText.Position, constraints: MarkdownConstraints): Pair<String, String>? {
Expand All @@ -48,4 +57,4 @@ class CodeFenceProvider : MarkerBlockProvider<MarkerProcessor.StateInfo> {
companion object {
val REGEX: Regex = Regex("^ {0,3}(~~~+|```+)([^`]*)$")
}
}
}
15 changes: 10 additions & 5 deletions src/fileBasedTest/resources/data/parser/codeFence.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,20 @@ Markdown:MARKDOWN_FILE
Markdown:EOL('\n')
Markdown:EOL('\n')
Markdown:CODE_FENCE
Markdown:CODE_FENCE_START(' ```')
WHITE_SPACE(' ')
Markdown:CODE_FENCE_START('```')
Markdown:EOL('\n')
Markdown:CODE_FENCE_CONTENT(' aaa')
WHITE_SPACE(' ')
Markdown:CODE_FENCE_CONTENT('aaa')
Markdown:EOL('\n')
Markdown:CODE_FENCE_CONTENT(' aaa')
WHITE_SPACE(' ')
Markdown:CODE_FENCE_CONTENT(' aaa')
Markdown:EOL('\n')
Markdown:CODE_FENCE_CONTENT(' aaa')
WHITE_SPACE(' ')
Markdown:CODE_FENCE_CONTENT('aaa')
Markdown:EOL('\n')
Markdown:CODE_FENCE_END(' ```')
WHITE_SPACE(' ')
Markdown:CODE_FENCE_END('```')
Markdown:EOL('\n')
Markdown:EOL('\n')
Markdown:CODE_BLOCK
Expand Down
3 changes: 2 additions & 1 deletion src/fileBasedTest/resources/data/parser/example226.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ Markdown:MARKDOWN_FILE
WHITE_SPACE(' ')
Markdown:CODE_FENCE_CONTENT('bar')
Markdown:EOL('\n')
Markdown:CODE_FENCE_END(' ```')
WHITE_SPACE(' ')
Markdown:CODE_FENCE_END('```')
Markdown:EOL('\n')
Markdown:LIST_ITEM
Markdown:LIST_BULLET('-')
Expand Down
6 changes: 4 additions & 2 deletions src/fileBasedTest/resources/data/parser/tightLooseLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ Markdown:MARKDOWN_FILE
WHITE_SPACE(' ')
Markdown:CODE_FENCE_CONTENT(' is not loose at all')
Markdown:EOL('\n')
Markdown:CODE_FENCE_END(' ```')
WHITE_SPACE(' ')
Markdown:CODE_FENCE_END('```')
Markdown:EOL('\n')
Markdown:LIST_ITEM
Markdown:LIST_BULLET('- ')
Expand Down Expand Up @@ -187,7 +188,8 @@ Markdown:MARKDOWN_FILE
WHITE_SPACE(' ')
Markdown:CODE_FENCE_CONTENT('something second')
Markdown:EOL('\n')
Markdown:CODE_FENCE_END(' ```')
WHITE_SPACE(' ')
Markdown:CODE_FENCE_END('```')
Markdown:EOL('\n')
Markdown:LIST_ITEM
Markdown:LIST_BULLET('- ')
Expand Down