Exemplo n.º 1
0
def test_footnote_inline():

    md = MarkdownIt().use(footnote_plugin)
    src = r"^[a]"
    tokens = []
    state = StateInline(src, md, {}, tokens)
    state.env = {"footnotes": {"refs": {":a": -1}}}
    index.footnote_inline(state, False)
    # print([t.as_dict() for t in tokens])
    assert [t.as_dict() for t in tokens] == [{
        "type": "footnote_ref",
        "tag": "",
        "nesting": 0,
        "attrs": None,
        "map": None,
        "level": 0,
        "children": None,
        "content": "",
        "markup": "",
        "info": "",
        "meta": {
            "id": 0
        },
        "block": False,
        "hidden": False,
    }]
    assert state.env == {
        "footnotes": {
            "refs": {
                ":a": -1
            },
            "list": {
                0: {
                    "content":
                    "a",
                    "tokens": [
                        Token(
                            type="text",
                            tag="",
                            nesting=0,
                            attrs=None,
                            map=None,
                            level=0,
                            children=None,
                            content="a",
                            markup="",
                            info="",
                            meta={},
                            block=False,
                            hidden=False,
                        )
                    ],
                }
            },
        }
    }
Exemplo n.º 2
0
def test_inline_func():

    inline_func = main.make_inline_func(main.rules.dollars.inline[0])

    md = MarkdownIt()
    src = r"$a=1$ $b=2$"
    tokens = []
    state = StateInline(src, md, {}, tokens)
    inline_func(state, False)
    assert tokens[0].as_dict() == {
        "type": "math_inline",
        "tag": "math",
        "nesting": 0,
        "attrs": None,
        "map": None,
        "level": 0,
        "children": None,
        "content": "a=1",
        "markup": "$",
        "info": "",
        "meta": {},
        "block": False,
        "hidden": False,
    }
    assert state.pos == 5
Exemplo n.º 3
0
def footnote_inline(state: StateInline, silent: bool):
    """Process inline footnotes (^[...])"""

    maximum = state.posMax
    start = state.pos

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

    labelStart = start + 2
    labelEnd = parseLinkLabel(state, start + 1)

    # parser failed to find ']', so it's not a valid note
    if labelEnd < 0:
        return False

    # We found the end of the link, and know for a fact it's a valid link
    # so all that's left to do is to call tokenizer.
    #
    if not silent:
        refs = state.env.setdefault("footnotes", {}).setdefault("list", {})
        footnoteId = len(refs)

        tokens = []
        state.md.inline.parse(state.src[labelStart:labelEnd], state.md,
                              state.env, tokens)

        token = state.push("footnote_ref", "", 0)
        token.meta = {"id": footnoteId}

        refs[footnoteId] = {
            "content": state.src[labelStart:labelEnd],
            "tokens": tokens
        }

    state.pos = labelEnd + 1
    state.posMax = maximum
    return True
Exemplo n.º 4
0
def myst_role(state: StateInline, silent: bool):

    # check name
    match = VALID_NAME_PATTERN.match(state.src[state.pos:])
    if not match:
        return False
    name = match.group(1)

    # check for starting backslash escape
    try:
        if state.srcCharCode[state.pos - 1] == 0x5C:  # /* \ */
            # escaped (this could be improved in the case of edge case '\\{')
            return False
    except IndexError:
        pass

    # scan opening tick length
    start = pos = state.pos + match.end()
    try:
        while state.src[pos] == "`":
            pos += 1
    except IndexError:
        return False

    tick_length = pos - start
    if not tick_length:
        return False

    # search for closing ticks
    match = re.search("`" * tick_length, state.src[pos + 1:])
    if not match:
        return False
    content = state.src[pos:pos + match.start() + 1].replace("\n", " ")

    if not silent:
        token = state.push("myst_role", "", 0)
        token.meta = {"name": name}
        token.content = content

    state.pos = pos + match.end() + 1

    return True
Exemplo n.º 5
0
def test_footnote_ref():

    md = MarkdownIt()
    src = r"[^a]"
    tokens = []
    state = StateInline(src, md, {}, tokens)
    state.env = {"footnotes": {"refs": {":a": -1}}}
    index.footnote_ref(state, False)
    # print([t.as_dict() for t in tokens])
    assert [t.as_dict() for t in tokens] == [{
        "type": "footnote_ref",
        "tag": "",
        "nesting": 0,
        "attrs": None,
        "map": None,
        "level": 0,
        "children": None,
        "content": "",
        "markup": "",
        "info": "",
        "meta": {
            "id": 0,
            "subId": 0,
            "label": "a"
        },
        "block": False,
        "hidden": False,
    }]
    assert state.env == {
        "footnotes": {
            "refs": {
                ":a": 0
            },
            "list": {
                0: {
                    "label": "a",
                    "count": 1
                }
            }
        }
    }
Exemplo n.º 6
0
    def _substitution_inline(state: StateInline, silent: bool):
        try:
            if (state.srcCharCode[state.pos] != start_char
                    or state.srcCharCode[state.pos + 1] != start_char):
                return False
        except IndexError:
            return False

        pos = state.pos + 2
        found_closing = False
        while True:
            try:
                end = state.srcCharCode.index(end_char, pos)
            except ValueError:
                return False
            try:
                if state.srcCharCode[end + 1] == end_char:
                    found_closing = True
                    break
            except IndexError:
                return False
            pos = end + 2

        if not found_closing:
            return False

        text = state.src[state.pos + 2:end].strip()
        state.pos = end + 2

        if silent:
            return True

        token = state.push("substitution_inline", "span", 0)
        token.block = False
        token.content = text
        token.attrSet("class", "substitution")
        token.attrSet("text", text)
        token.markup = f"{start_delimiter}{end_delimiter}"

        return True
Exemplo n.º 7
0
def footnote_ref(state: StateInline, silent: bool):
    """Process footnote references ([^...])"""

    maximum = state.posMax
    start = state.pos

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

    if "footnotes" not in state.env or "refs" not in state.env["footnotes"]:
        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] == 0x0A:
            return False
        if state.srcCharCode[pos] == 0x5D:  # /* ] */
            break
        pos += 1

    if pos == start + 2:  # no empty footnote labels
        return False
    if pos >= maximum:
        return False
    pos += 1

    label = state.src[start + 2:pos - 1]
    if (":" + label) not in state.env["footnotes"]["refs"]:
        return False

    if not silent:
        if "list" not in state.env["footnotes"]:
            state.env["footnotes"]["list"] = {}

        if state.env["footnotes"]["refs"][":" + label] < 0:
            footnoteId = len(state.env["footnotes"]["list"])
            state.env["footnotes"]["list"][footnoteId] = {
                "label": label,
                "count": 0
            }
            state.env["footnotes"]["refs"][":" + label] = footnoteId
        else:
            footnoteId = state.env["footnotes"]["refs"][":" + label]

        footnoteSubId = state.env["footnotes"]["list"][footnoteId]["count"]
        state.env["footnotes"]["list"][footnoteId]["count"] += 1

        token = state.push("footnote_ref", "", 0)
        token.meta = {"id": footnoteId, "subId": footnoteSubId, "label": label}

    state.pos = pos
    state.posMax = maximum
    return True
Exemplo n.º 8
0
def parseLinkLabel(state: StateInline,
                   start: int,
                   disableNested: bool = False) -> int:

    labelEnd = -1
    oldPos = state.pos
    found = False

    state.pos = start + 1
    level = 1

    while state.pos < state.posMax:
        marker = state.srcCharCode[state.pos]
        if marker == 0x5D:  # /* ] */)
            level -= 1
            if level == 0:
                found = True
                break

        prevPos = state.pos
        state.md.inline.skipToken(state)
        if marker == 0x5B:  # /* [ */)
            if prevPos == state.pos - 1:
                # increase level if we find text `[`,
                # which is not a part of any token
                level += 1
            elif disableNested:
                state.pos = oldPos
                return -1
    if found:
        labelEnd = state.pos

    # restore old state
    state.pos = oldPos

    return labelEnd
Exemplo n.º 9
0
def myst_role(state: StateInline, silent: bool):
    try:
        if state.srcCharCode[state.pos - 1] == 0x5C:  # /* \ */
            # escaped (this could be improved in the case of edge case '\\{')
            return False
    except IndexError:
        pass

    match = PATTERN.search(state.src[state.pos:])
    if not match:
        return False
    state.pos += match.end()

    if not silent:
        token = state.push("myst_role", "", 0)
        token.meta = {"name": match.group(1)}
        token.content = match.group(3)

    return True
Exemplo n.º 10
0
    def _math_inline_dollar(state: StateInline, silent: bool) -> bool:
        """Inline dollar rule.

        - Initial check:
            - check if first character is a $
            - check if the first character is escaped
            - check if the next character is a space (if not allow_space)
            - check if the next character is a digit (if not allow_digits)
        - Advance one, if allow_double
        - Find closing (advance one, if allow_double)
        - Check closing:
            - check if the previous character is a space (if not allow_space)
            - check if the next character is a digit (if not allow_digits)
        - Check empty content
        """

        # TODO options:
        # even/odd backslash escaping

        if state.srcCharCode[state.pos] != 0x24:  # /* $ */
            return False

        if not allow_space:
            # whitespace not allowed straight after opening $
            try:
                if isWhiteSpace(state.srcCharCode[state.pos + 1]):
                    return False
            except IndexError:
                return False

        if not allow_digits:
            # digit not allowed straight before opening $
            try:
                if state.src[state.pos - 1].isdigit():
                    return False
            except IndexError:
                pass

        if is_escaped(state, state.pos):
            return False

        try:
            is_double = allow_double and state.srcCharCode[state.pos +
                                                           1] == 0x24
        except IndexError:
            return False

        # find closing $
        pos = state.pos + 1 + (1 if is_double else 0)
        found_closing = False
        while not found_closing:
            try:
                end = state.srcCharCode.index(0x24, pos)
            except ValueError:
                return False

            if is_escaped(state, end):
                pos = end + 1
                continue

            try:
                if is_double and not state.srcCharCode[end + 1] == 0x24:
                    pos = end + 1
                    continue
            except IndexError:
                return False

            if is_double:
                end += 1

            found_closing = True

        if not found_closing:
            return False

        if not allow_space:
            # whitespace not allowed straight before closing $
            try:
                if isWhiteSpace(state.srcCharCode[end - 1]):
                    return False
            except IndexError:
                return False

        if not allow_digits:
            # digit not allowed straight after closing $
            try:
                if state.src[end + 1].isdigit():
                    return False
            except IndexError:
                pass

        text = (state.src[state.pos + 2:end -
                          1] if is_double else state.src[state.pos + 1:end])

        # ignore empty
        if not text:
            return False

        if not silent:
            token = state.push(
                "math_inline_double" if is_double else "math_inline", "math",
                0)
            token.content = text
            token.markup = "$$" if is_double else "$"

        state.pos = end + 1

        return True
Exemplo n.º 11
0
    def _math_inline_dollar(state: StateInline, silent: bool):

        # TODO options:
        # even/odd backslash escaping
        # allow $$ blocks

        if state.srcCharCode[state.pos] != 0x24:  # /* $ */
            return False

        if not allow_space:
            # whitespace not allowed straight after opening $
            try:
                if isWhiteSpace(state.srcCharCode[state.pos + 1]):
                    return False
            except IndexError:
                return False

        if not allow_digits:
            # digit not allowed straight before opening $
            try:
                if state.src[state.pos - 1].isdigit():
                    return False
            except IndexError:
                pass

        if is_escaped(state, state.pos):
            return False

        # find closing $
        pos = state.pos + 1
        found_closing = False
        while True:
            try:
                end = state.srcCharCode.index(0x24, pos)
            except ValueError:
                return False

            if is_escaped(state, end):
                pos = end + 1
            else:
                found_closing = True
                break

        if not found_closing:
            return False

        if not allow_space:
            # whitespace not allowed straight before closing $
            try:
                if isWhiteSpace(state.srcCharCode[end - 1]):
                    return False
            except IndexError:
                return False

        if not allow_digits:
            # digit not allowed straight after closing $
            try:
                if state.src[end + 1].isdigit():
                    return False
            except IndexError:
                pass

        text = state.src[state.pos + 1 : end]

        # ignore empty
        if not text:
            return False

        if not silent:
            token = state.push("math_inline", "math", 0)
            token.content = text
            token.markup = "$"

        state.pos = end + 1

        return True