Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
blockquote.py369 linesDownload Raw Back to rules_block
1# Block quotes2from __future__ import annotations3 4import logging5 6from ..common.utils import isStrSpace7from .state_block import StateBlock8 9LOGGER = logging.getLogger(__name__)10 11 12def blockquote(state: StateBlock, startLine: int, endLine: int, silent: bool) -> bool:13    LOGGER.debug(14        "entering blockquote: %s, %s, %s, %s", state, startLine, endLine, silent15    )16 17    oldLineMax = state.lineMax18    pos = state.bMarks[startLine] + state.tShift[startLine]19    max = state.eMarks[startLine]20 21    if state.is_code_block(startLine):22        return False23 24    # check the block quote marker25    try:26        if state.src[pos] != ">":27            return False28    except IndexError:29        return False30    pos += 131 32    # we know that it's going to be a valid blockquote,33    # so no point trying to find the end of it in silent mode34    if silent:35        return True36 37    # set offset past spaces and ">"38    initial = offset = state.sCount[startLine] + 139 40    try:41        second_char: str | None = state.src[pos]42    except IndexError:43        second_char = None44 45    # skip one optional space after '>'46    if second_char == " ":47        # ' >   test '48        #     ^ -- position start of line here:49        pos += 150        initial += 151        offset += 152        adjustTab = False53        spaceAfterMarker = True54    elif second_char == "\t":55        spaceAfterMarker = True56 57        if (state.bsCount[startLine] + offset) % 4 == 3:58            # '  >\t  test '59            #       ^ -- position start of line here (tab has width==1)60            pos += 161            initial += 162            offset += 163            adjustTab = False64        else:65            # ' >\t  test '66            #    ^ -- position start of line here + shift bsCount slightly67            #         to make extra space appear68            adjustTab = True69 70    else:71        spaceAfterMarker = False72 73    oldBMarks = [state.bMarks[startLine]]74    state.bMarks[startLine] = pos75 76    while pos < max:77        ch = state.src[pos]78 79        if isStrSpace(ch):80            if ch == "\t":81                offset += (82                    483                    - (offset + state.bsCount[startLine] + (1 if adjustTab else 0)) % 484                )85            else:86                offset += 187 88        else:89            break90 91        pos += 192 93    oldBSCount = [state.bsCount[startLine]]94    state.bsCount[startLine] = (95        state.sCount[startLine] + 1 + (1 if spaceAfterMarker else 0)96    )97 98    lastLineEmpty = pos >= max99 100    oldSCount = [state.sCount[startLine]]101    state.sCount[startLine] = offset - initial102 103    oldTShift = [state.tShift[startLine]]104    state.tShift[startLine] = pos - state.bMarks[startLine]105 106    terminatorRules = state.md.block.ruler.getRules("blockquote")107 108    oldParentType = state.parentType109    state.parentType = "blockquote"110 111    # Search the end of the block112    #113    # Block ends with either:114    #  1. an empty line outside:115    #     ```116    #     > test117    #118    #     ```119    #  2. an empty line inside:120    #     ```121    #     >122    #     test123    #     ```124    #  3. another tag:125    #     ```126    #     > test127    #      - - -128    #     ```129 130    # for (nextLine = startLine + 1; nextLine < endLine; nextLine++) {131    nextLine = startLine + 1132    while nextLine < endLine:133        # check if it's outdented, i.e. it's inside list item and indented134        # less than said list item:135        #136        # ```137        # 1. anything138        #    > current blockquote139        # 2. checking this line140        # ```141        isOutdented = state.sCount[nextLine] < state.blkIndent142 143        pos = state.bMarks[nextLine] + state.tShift[nextLine]144        max = state.eMarks[nextLine]145 146        if pos >= max:147            # Case 1: line is not inside the blockquote, and this line is empty.148            break149 150        evaluatesTrue = state.src[pos] == ">" and not isOutdented151        pos += 1152        if evaluatesTrue:153            # This line is inside the blockquote.154 155            # set offset past spaces and ">"156            initial = offset = state.sCount[nextLine] + 1157 158            try:159                next_char: str | None = state.src[pos]160            except IndexError:161                next_char = None162 163            # skip one optional space after '>'164            if next_char == " ":165                # ' >   test '166                #     ^ -- position start of line here:167                pos += 1168                initial += 1169                offset += 1170                adjustTab = False171                spaceAfterMarker = True172            elif next_char == "\t":173                spaceAfterMarker = True174 175                if (state.bsCount[nextLine] + offset) % 4 == 3:176                    # '  >\t  test '177                    #       ^ -- position start of line here (tab has width==1)178                    pos += 1179                    initial += 1180                    offset += 1181                    adjustTab = False182                else:183                    # ' >\t  test '184                    #    ^ -- position start of line here + shift bsCount slightly185                    #         to make extra space appear186                    adjustTab = True187 188            else:189                spaceAfterMarker = False190 191            oldBMarks.append(state.bMarks[nextLine])192            state.bMarks[nextLine] = pos193 194            while pos < max:195                ch = state.src[pos]196 197                if isStrSpace(ch):198                    if ch == "\t":199                        offset += (200                            4201                            - (202                                offset203                                + state.bsCount[nextLine]204                                + (1 if adjustTab else 0)205                            )206                            % 4207                        )208                    else:209                        offset += 1210                else:211                    break212 213                pos += 1214 215            lastLineEmpty = pos >= max216 217            oldBSCount.append(state.bsCount[nextLine])218            state.bsCount[nextLine] = (219                state.sCount[nextLine] + 1 + (1 if spaceAfterMarker else 0)220            )221 222            oldSCount.append(state.sCount[nextLine])223            state.sCount[nextLine] = offset - initial224 225            oldTShift.append(state.tShift[nextLine])226            state.tShift[nextLine] = pos - state.bMarks[nextLine]227 228            nextLine += 1229            continue230 231        # Case 2: line is not inside the blockquote, and the last line was empty.232        if lastLineEmpty:233            break234 235        # Case 3: another tag found.236        terminate = False237 238        for terminatorRule in terminatorRules:239            if terminatorRule(state, nextLine, endLine, True):240                terminate = True241                break242 243        if terminate:244            # Quirk to enforce "hard termination mode" for paragraphs;245            # normally if you call `tokenize(state, startLine, nextLine)`,246            # paragraphs will look below nextLine for paragraph continuation,247            # but if blockquote is terminated by another tag, they shouldn't248            state.lineMax = nextLine249 250            if state.blkIndent != 0:251                # state.blkIndent was non-zero, we now set it to zero,252                # so we need to re-calculate all offsets to appear as253                # if indent wasn't changed254                oldBMarks.append(state.bMarks[nextLine])255                oldBSCount.append(state.bsCount[nextLine])256                oldTShift.append(state.tShift[nextLine])257                oldSCount.append(state.sCount[nextLine])258                state.sCount[nextLine] -= state.blkIndent259 260            break261 262        oldBMarks.append(state.bMarks[nextLine])263        oldBSCount.append(state.bsCount[nextLine])264        oldTShift.append(state.tShift[nextLine])265        oldSCount.append(state.sCount[nextLine])266 267        # A negative indentation means that this is a paragraph continuation268        #269        state.sCount[nextLine] = -1270 271        nextLine += 1272 273    oldIndent = state.blkIndent274    state.blkIndent = 0275 276    # Detect GitHub-style alert marker on the first content line.277    # Note: `startLine` here refers to the first content line of the278    # blockquote, after the `>` prefix has already been stripped by the279    # blockquote parser above (bMarks/tShift adjusted to skip `> `).280    alert_kind = None281    if state.md.options.get("alerts", False) and nextLine > startLine:282        alert_kind = _detect_alert(state, startLine)283 284    lines = [startLine, 0]285 286    if alert_kind is not None:287        # Emit alert tokens instead of blockquote tokens288        alert_lower = alert_kind.lower()289        token = state.push("alert_open", "div", 1)290        token.markup = ">"291        token.attrSet("class", f"markdown-alert markdown-alert-{alert_lower}")292        token.map = lines293        token.info = alert_kind294        token.meta = {"kind": alert_kind}295 296        # Emit a title paragraph: <p class="markdown-alert-title">Kind</p>297        token = state.push("alert_title_open", "p", 1)298        token.attrSet("class", "markdown-alert-title")299        title_token = state.push("inline", "", 0)300        title_token.content = alert_kind.capitalize()301        title_token.children = []302        token = state.push("alert_title_close", "p", -1)303 304        # Skip the marker line (startLine) and tokenize from startLine + 1.305        contentStart = startLine + 1306        if contentStart < nextLine:307            # tokenize() updates state.line to nextLine as part of its308            # contract, consistent with the blockquote code path below.309            state.md.block.tokenize(state, contentStart, nextLine)310        else:311            state.line = nextLine312 313        token = state.push("alert_close", "div", -1)314        token.markup = ">"315    else:316        token = state.push("blockquote_open", "blockquote", 1)317        token.markup = ">"318        token.map = lines319 320        state.md.block.tokenize(state, startLine, nextLine)321 322        token = state.push("blockquote_close", "blockquote", -1)323        token.markup = ">"324 325    state.lineMax = oldLineMax326    state.parentType = oldParentType327    # Update the opening token map for both alert and blockquote containers.328    lines[1] = state.line329 330    # Restore original tShift; this might not be necessary since the parser331    # has already been here, but just to make sure we can do that.332    for i, item in enumerate(oldTShift):333        state.bMarks[i + startLine] = oldBMarks[i]334        state.tShift[i + startLine] = item335        state.sCount[i + startLine] = oldSCount[i]336        state.bsCount[i + startLine] = oldBSCount[i]337 338    state.blkIndent = oldIndent339 340    return True341 342 343_ALERT_TYPES = {"NOTE", "TIP", "IMPORTANT", "WARNING", "CAUTION"}344 345 346def _detect_alert(state: StateBlock, startLine: int) -> str | None:347    """Detect ``[!TYPE]`` on *startLine* (after ``>`` prefix has been stripped).348 349    Returns the alert type string (e.g. ``"NOTE"``) or ``None``.350    """351    pos = state.bMarks[startLine] + state.tShift[startLine]352    maximum = state.eMarks[startLine]353    src = state.src354 355    # Trim trailing whitespace356    while maximum > pos and src[maximum - 1] in (" ", "\t"):357        maximum -= 1358 359    if maximum - pos < 4:360        return None361    if src[pos] != "[" or src[pos + 1] != "!":362        return None363    if src[maximum - 1] != "]":364        return None365    type_str = src[pos + 2 : maximum - 1].upper()366    if type_str not in _ALERT_TYPES:367        return None368    return type_str369 
codekingpro/portable-devtools · Team Ai