Esempio n. 1
0
def footnote_def(state: StateBlock, startLine: int, endLine: int,
                 silent: bool):
    """Process footnote block definition"""

    start = state.bMarks[startLine] + state.tShift[startLine]
    maximum = state.eMarks[startLine]

    # line should be at least 5 chars - "[^x]:"
    if start + 4 > maximum:
        return False

    if state.srcCharCode[start] != 0x5B:  # /* [ */
        return False
    if state.srcCharCode[start + 1] != 0x5E:  # /* ^ */
        return False

    pos = start + 2
    while pos < maximum:
        if state.srcCharCode[pos] == 0x20:
            return False
        if state.srcCharCode[pos] == 0x5D:  # /* ] */
            break
        pos += 1

    if pos == start + 2:  # no empty footnote labels
        return False
    pos += 1
    if pos + 1 >= maximum or state.srcCharCode[pos] != 0x3A:  # /* : */
        return False
    if silent:
        return True
    pos += 1

    label = state.src[start + 2:pos - 2]
    state.env.setdefault("footnotes", {}).setdefault("refs",
                                                     {})[":" + label] = -1

    open_token = Token("footnote_reference_open", "", 1)
    open_token.meta = {"label": label}
    open_token.level = state.level
    state.level += 1
    state.tokens.append(open_token)

    oldBMark = state.bMarks[startLine]
    oldTShift = state.tShift[startLine]
    oldSCount = state.sCount[startLine]
    oldParentType = state.parentType

    posAfterColon = pos
    initial = offset = (state.sCount[startLine] + pos -
                        (state.bMarks[startLine] + state.tShift[startLine]))

    while pos < maximum:
        ch = state.srcCharCode[pos]

        if isSpace(ch):
            if ch == 0x09:
                offset += 4 - offset % 4
            else:
                offset += 1

        else:
            break

        pos += 1

    state.tShift[startLine] = pos - posAfterColon
    state.sCount[startLine] = offset - initial

    state.bMarks[startLine] = posAfterColon
    state.blkIndent += 4
    state.parentType = "footnote"

    if state.sCount[startLine] < state.blkIndent:
        state.sCount[startLine] += state.blkIndent

    state.md.block.tokenize(state, startLine, endLine, True)

    state.parentType = oldParentType
    state.blkIndent -= 4
    state.tShift[startLine] = oldTShift
    state.sCount[startLine] = oldSCount
    state.bMarks[startLine] = oldBMark

    open_token.map = [startLine, state.line]

    token = Token("footnote_reference_close", "", -1)
    state.level -= 1
    token.level = state.level
    state.tokens.append(token)

    return True
Esempio n. 2
0
def footnote_tail(state: StateBlock, *args, **kwargs):
    """Post-processing step, to move footnote tokens to end of the token stream.

    Also removes un-referenced tokens.
    """

    insideRef = False
    refTokens = {}

    if "footnotes" not in state.env:
        return

    current = []
    tok_filter = []
    for tok in state.tokens:

        if tok.type == "footnote_reference_open":
            insideRef = True
            current = []
            currentLabel = tok.meta["label"]
            tok_filter.append(False)
            continue

        if tok.type == "footnote_reference_close":
            insideRef = False
            # prepend ':' to avoid conflict with Object.prototype members
            refTokens[":" + currentLabel] = current
            tok_filter.append(False)
            continue

        if insideRef:
            current.append(tok)

        tok_filter.append((not insideRef))

    state.tokens = [t for t, f in zip(state.tokens, tok_filter) if f]

    if "list" not in state.env.get("footnotes", {}):
        return
    foot_list = state.env["footnotes"]["list"]

    token = Token("footnote_block_open", "", 1)
    state.tokens.append(token)

    for i, foot_note in foot_list.items():
        token = Token("footnote_open", "", 1)
        token.meta = {"id": i, "label": foot_note.get("label", None)}
        # TODO propagate line positions of original foot note
        # (but don't store in token.map, because this is used for scroll syncing)
        state.tokens.append(token)

        if "tokens" in foot_note:
            tokens = []

            token = Token("paragraph_open", "p", 1)
            token.block = True
            tokens.append(token)

            token = Token("inline", "", 0)
            token.children = foot_note["tokens"]
            token.content = foot_note["content"]
            tokens.append(token)

            token = Token("paragraph_close", "p", -1)
            token.block = True
            tokens.append(token)

        elif "label" in foot_note:
            tokens = refTokens[":" + foot_note["label"]]

        state.tokens.extend(tokens)
        if state.tokens[len(state.tokens) - 1].type == "paragraph_close":
            lastParagraph = state.tokens.pop()
        else:
            lastParagraph = None

        t = (foot_note["count"] if
             (("count" in foot_note) and (foot_note["count"] > 0)) else 1)
        j = 0
        while j < t:
            token = Token("footnote_anchor", "", 0)
            token.meta = {
                "id": i,
                "subId": j,
                "label": foot_note.get("label", None)
            }
            state.tokens.append(token)
            j += 1

        if lastParagraph:
            state.tokens.append(lastParagraph)

        token = Token("footnote_close", "", -1)
        state.tokens.append(token)

    token = Token("footnote_block_close", "", -1)
    state.tokens.append(token)