|
|
|
from __future__ import annotations |
|
|
|
import logging |
|
|
|
from ..common.utils import isStrSpace |
|
from .state_block import StateBlock |
|
|
|
LOGGER = logging.getLogger(__name__) |
|
|
|
|
|
def blockquote(state: StateBlock, startLine: int, endLine: int, silent: bool) -> bool: |
|
LOGGER.debug( |
|
"entering blockquote: %s, %s, %s, %s", state, startLine, endLine, silent |
|
) |
|
|
|
oldLineMax = state.lineMax |
|
pos = state.bMarks[startLine] + state.tShift[startLine] |
|
max = state.eMarks[startLine] |
|
|
|
if state.is_code_block(startLine): |
|
return False |
|
|
|
|
|
try: |
|
if state.src[pos] != ">": |
|
return False |
|
except IndexError: |
|
return False |
|
pos += 1 |
|
|
|
|
|
|
|
if silent: |
|
return True |
|
|
|
|
|
initial = offset = state.sCount[startLine] + 1 |
|
|
|
try: |
|
second_char: str | None = state.src[pos] |
|
except IndexError: |
|
second_char = None |
|
|
|
|
|
if second_char == " ": |
|
|
|
|
|
pos += 1 |
|
initial += 1 |
|
offset += 1 |
|
adjustTab = False |
|
spaceAfterMarker = True |
|
elif second_char == "\t": |
|
spaceAfterMarker = True |
|
|
|
if (state.bsCount[startLine] + offset) % 4 == 3: |
|
|
|
|
|
pos += 1 |
|
initial += 1 |
|
offset += 1 |
|
adjustTab = False |
|
else: |
|
|
|
|
|
|
|
adjustTab = True |
|
|
|
else: |
|
spaceAfterMarker = False |
|
|
|
oldBMarks = [state.bMarks[startLine]] |
|
state.bMarks[startLine] = pos |
|
|
|
while pos < max: |
|
ch = state.src[pos] |
|
|
|
if isStrSpace(ch): |
|
if ch == "\t": |
|
offset += ( |
|
4 |
|
- (offset + state.bsCount[startLine] + (1 if adjustTab else 0)) % 4 |
|
) |
|
else: |
|
offset += 1 |
|
|
|
else: |
|
break |
|
|
|
pos += 1 |
|
|
|
oldBSCount = [state.bsCount[startLine]] |
|
state.bsCount[startLine] = ( |
|
state.sCount[startLine] + 1 + (1 if spaceAfterMarker else 0) |
|
) |
|
|
|
lastLineEmpty = pos >= max |
|
|
|
oldSCount = [state.sCount[startLine]] |
|
state.sCount[startLine] = offset - initial |
|
|
|
oldTShift = [state.tShift[startLine]] |
|
state.tShift[startLine] = pos - state.bMarks[startLine] |
|
|
|
terminatorRules = state.md.block.ruler.getRules("blockquote") |
|
|
|
oldParentType = state.parentType |
|
state.parentType = "blockquote" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nextLine = startLine + 1 |
|
while nextLine < endLine: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
isOutdented = state.sCount[nextLine] < state.blkIndent |
|
|
|
pos = state.bMarks[nextLine] + state.tShift[nextLine] |
|
max = state.eMarks[nextLine] |
|
|
|
if pos >= max: |
|
|
|
break |
|
|
|
evaluatesTrue = state.src[pos] == ">" and not isOutdented |
|
pos += 1 |
|
if evaluatesTrue: |
|
|
|
|
|
|
|
initial = offset = state.sCount[nextLine] + 1 |
|
|
|
try: |
|
next_char: str | None = state.src[pos] |
|
except IndexError: |
|
next_char = None |
|
|
|
|
|
if next_char == " ": |
|
|
|
|
|
pos += 1 |
|
initial += 1 |
|
offset += 1 |
|
adjustTab = False |
|
spaceAfterMarker = True |
|
elif next_char == "\t": |
|
spaceAfterMarker = True |
|
|
|
if (state.bsCount[nextLine] + offset) % 4 == 3: |
|
|
|
|
|
pos += 1 |
|
initial += 1 |
|
offset += 1 |
|
adjustTab = False |
|
else: |
|
|
|
|
|
|
|
adjustTab = True |
|
|
|
else: |
|
spaceAfterMarker = False |
|
|
|
oldBMarks.append(state.bMarks[nextLine]) |
|
state.bMarks[nextLine] = pos |
|
|
|
while pos < max: |
|
ch = state.src[pos] |
|
|
|
if isStrSpace(ch): |
|
if ch == "\t": |
|
offset += ( |
|
4 |
|
- ( |
|
offset |
|
+ state.bsCount[nextLine] |
|
+ (1 if adjustTab else 0) |
|
) |
|
% 4 |
|
) |
|
else: |
|
offset += 1 |
|
else: |
|
break |
|
|
|
pos += 1 |
|
|
|
lastLineEmpty = pos >= max |
|
|
|
oldBSCount.append(state.bsCount[nextLine]) |
|
state.bsCount[nextLine] = ( |
|
state.sCount[nextLine] + 1 + (1 if spaceAfterMarker else 0) |
|
) |
|
|
|
oldSCount.append(state.sCount[nextLine]) |
|
state.sCount[nextLine] = offset - initial |
|
|
|
oldTShift.append(state.tShift[nextLine]) |
|
state.tShift[nextLine] = pos - state.bMarks[nextLine] |
|
|
|
nextLine += 1 |
|
continue |
|
|
|
|
|
if lastLineEmpty: |
|
break |
|
|
|
|
|
terminate = False |
|
|
|
for terminatorRule in terminatorRules: |
|
if terminatorRule(state, nextLine, endLine, True): |
|
terminate = True |
|
break |
|
|
|
if terminate: |
|
|
|
|
|
|
|
|
|
state.lineMax = nextLine |
|
|
|
if state.blkIndent != 0: |
|
|
|
|
|
|
|
oldBMarks.append(state.bMarks[nextLine]) |
|
oldBSCount.append(state.bsCount[nextLine]) |
|
oldTShift.append(state.tShift[nextLine]) |
|
oldSCount.append(state.sCount[nextLine]) |
|
state.sCount[nextLine] -= state.blkIndent |
|
|
|
break |
|
|
|
oldBMarks.append(state.bMarks[nextLine]) |
|
oldBSCount.append(state.bsCount[nextLine]) |
|
oldTShift.append(state.tShift[nextLine]) |
|
oldSCount.append(state.sCount[nextLine]) |
|
|
|
|
|
|
|
state.sCount[nextLine] = -1 |
|
|
|
nextLine += 1 |
|
|
|
oldIndent = state.blkIndent |
|
state.blkIndent = 0 |
|
|
|
token = state.push("blockquote_open", "blockquote", 1) |
|
token.markup = ">" |
|
token.map = lines = [startLine, 0] |
|
|
|
state.md.block.tokenize(state, startLine, nextLine) |
|
|
|
token = state.push("blockquote_close", "blockquote", -1) |
|
token.markup = ">" |
|
|
|
state.lineMax = oldLineMax |
|
state.parentType = oldParentType |
|
lines[1] = state.line |
|
|
|
|
|
|
|
for i, item in enumerate(oldTShift): |
|
state.bMarks[i + startLine] = oldBMarks[i] |
|
state.tShift[i + startLine] = item |
|
state.sCount[i + startLine] = oldSCount[i] |
|
state.bsCount[i + startLine] = oldBSCount[i] |
|
|
|
state.blkIndent = oldIndent |
|
|
|
return True |
|
|