flan-t5-base-ai-text-seq2seq / hf-env /lib /python3.12 /site-packages /markdown_it /rules_block /reference.py
| import logging | |
| from ..common.utils import charCodeAt, isSpace, normalizeReference | |
| from .state_block import StateBlock | |
| LOGGER = logging.getLogger(__name__) | |
| def reference(state: StateBlock, startLine: int, _endLine: int, silent: bool) -> bool: | |
| LOGGER.debug( | |
| "entering reference: %s, %s, %s, %s", state, startLine, _endLine, silent | |
| ) | |
| pos = state.bMarks[startLine] + state.tShift[startLine] | |
| maximum = state.eMarks[startLine] | |
| nextLine = startLine + 1 | |
| if state.is_code_block(startLine): | |
| return False | |
| if state.src[pos] != "[": | |
| return False | |
| string = state.src[pos : maximum + 1] | |
| # string = state.getLines(startLine, nextLine, state.blkIndent, False).strip() | |
| maximum = len(string) | |
| labelEnd = None | |
| pos = 1 | |
| while pos < maximum: | |
| ch = charCodeAt(string, pos) | |
| if ch == 0x5B: # /* [ */ | |
| return False | |
| elif ch == 0x5D: # /* ] */ | |
| labelEnd = pos | |
| break | |
| elif ch == 0x0A: # /* \n */ | |
| if (lineContent := getNextLine(state, nextLine)) is not None: | |
| string += lineContent | |
| maximum = len(string) | |
| nextLine += 1 | |
| elif ch == 0x5C: # /* \ */ | |
| pos += 1 | |
| if ( | |
| pos < maximum | |
| and charCodeAt(string, pos) == 0x0A | |
| and (lineContent := getNextLine(state, nextLine)) is not None | |
| ): | |
| string += lineContent | |
| maximum = len(string) | |
| nextLine += 1 | |
| pos += 1 | |
| if ( | |
| labelEnd is None or labelEnd < 0 or charCodeAt(string, labelEnd + 1) != 0x3A | |
| ): # /* : */ | |
| return False | |
| # [label]: destination 'title' | |
| # ^^^ skip optional whitespace here | |
| pos = labelEnd + 2 | |
| while pos < maximum: | |
| ch = charCodeAt(string, pos) | |
| if ch == 0x0A: | |
| if (lineContent := getNextLine(state, nextLine)) is not None: | |
| string += lineContent | |
| maximum = len(string) | |
| nextLine += 1 | |
| elif isSpace(ch): | |
| pass | |
| else: | |
| break | |
| pos += 1 | |
| # [label]: destination 'title' | |
| # ^^^^^^^^^^^ parse this | |
| destRes = state.md.helpers.parseLinkDestination(string, pos, maximum) | |
| if not destRes.ok: | |
| return False | |
| href = state.md.normalizeLink(destRes.str) | |
| if not state.md.validateLink(href): | |
| return False | |
| pos = destRes.pos | |
| # save cursor state, we could require to rollback later | |
| destEndPos = pos | |
| destEndLineNo = nextLine | |
| # [label]: destination 'title' | |
| # ^^^ skipping those spaces | |
| start = pos | |
| while pos < maximum: | |
| ch = charCodeAt(string, pos) | |
| if ch == 0x0A: | |
| if (lineContent := getNextLine(state, nextLine)) is not None: | |
| string += lineContent | |
| maximum = len(string) | |
| nextLine += 1 | |
| elif isSpace(ch): | |
| pass | |
| else: | |
| break | |
| pos += 1 | |
| # [label]: destination 'title' | |
| # ^^^^^^^ parse this | |
| titleRes = state.md.helpers.parseLinkTitle(string, pos, maximum, None) | |
| while titleRes.can_continue: | |
| if (lineContent := getNextLine(state, nextLine)) is None: | |
| break | |
| string += lineContent | |
| pos = maximum | |
| maximum = len(string) | |
| nextLine += 1 | |
| titleRes = state.md.helpers.parseLinkTitle(string, pos, maximum, titleRes) | |
| if pos < maximum and start != pos and titleRes.ok: | |
| title = titleRes.str | |
| pos = titleRes.pos | |
| else: | |
| title = "" | |
| pos = destEndPos | |
| nextLine = destEndLineNo | |
| # skip trailing spaces until the rest of the line | |
| while pos < maximum: | |
| ch = charCodeAt(string, pos) | |
| if not isSpace(ch): | |
| break | |
| pos += 1 | |
| if pos < maximum and charCodeAt(string, pos) != 0x0A and title: | |
| # garbage at the end of the line after title, | |
| # but it could still be a valid reference if we roll back | |
| title = "" | |
| pos = destEndPos | |
| nextLine = destEndLineNo | |
| while pos < maximum: | |
| ch = charCodeAt(string, pos) | |
| if not isSpace(ch): | |
| break | |
| pos += 1 | |
| if pos < maximum and charCodeAt(string, pos) != 0x0A: | |
| # garbage at the end of the line | |
| return False | |
| label = normalizeReference(string[1:labelEnd]) | |
| if not label: | |
| # CommonMark 0.20 disallows empty labels | |
| return False | |
| # Reference can not terminate anything. This check is for safety only. | |
| if silent: | |
| return True | |
| if "references" not in state.env: | |
| state.env["references"] = {} | |
| state.line = nextLine | |
| # note, this is not part of markdown-it JS, but is useful for renderers | |
| if state.md.options.get("inline_definitions", False): | |
| token = state.push("definition", "", 0) | |
| token.meta = { | |
| "id": label, | |
| "title": title, | |
| "url": href, | |
| "label": string[1:labelEnd], | |
| } | |
| token.map = [startLine, state.line] | |
| if label not in state.env["references"]: | |
| state.env["references"][label] = { | |
| "title": title, | |
| "href": href, | |
| "map": [startLine, state.line], | |
| } | |
| else: | |
| state.env.setdefault("duplicate_refs", []).append( | |
| { | |
| "title": title, | |
| "href": href, | |
| "label": label, | |
| "map": [startLine, state.line], | |
| } | |
| ) | |
| return True | |
| def getNextLine(state: StateBlock, nextLine: int) -> None | str: | |
| endLine = state.lineMax | |
| if nextLine >= endLine or state.isEmpty(nextLine): | |
| # empty line or end of input | |
| return None | |
| isContinuation = False | |
| # this would be a code block normally, but after paragraph | |
| # it's considered a lazy continuation regardless of what's there | |
| if state.is_code_block(nextLine): | |
| isContinuation = True | |
| # quirk for blockquotes, this line should already be checked by that rule | |
| if state.sCount[nextLine] < 0: | |
| isContinuation = True | |
| if not isContinuation: | |
| terminatorRules = state.md.block.ruler.getRules("reference") | |
| oldParentType = state.parentType | |
| state.parentType = "reference" | |
| # Some tags can terminate paragraph without empty line. | |
| terminate = False | |
| for terminatorRule in terminatorRules: | |
| if terminatorRule(state, nextLine, endLine, True): | |
| terminate = True | |
| break | |
| state.parentType = oldParentType | |
| if terminate: | |
| # terminated by another block | |
| return None | |
| pos = state.bMarks[nextLine] + state.tShift[nextLine] | |
| maximum = state.eMarks[nextLine] | |
| # max + 1 explicitly includes the newline | |
| return state.src[pos : maximum + 1] | |