Module

parsing.inline.gfm_autolinks

GFM extended autolink scanning for Patitas.

Implements the GFM "Autolinks (extension)" feature: recognizing bare URLs, www.links, and bare email addresses inside ordinary inline text. This is gated onParseConfig.autolinks_enabledand is entirely separate from the CommonMark angle-bracket autolinks (<https://...>) handled in special.py, which work without any plugin.

Reference: https://github.github.com/gfm/#autolinks-extension-

The public entry point isscan_text_for_autolinks(). It scans the full inline text from a starting offset so that a URL/www.body can include characters that are otherwise inline-special (& ~ $ _ * [ ! {) — these are ubiquitous in real URLs (query separators,~user paths, Foo_(bar) article slugs). The scan follows the GFM rule that a URL body extends until whitespace or<(with one pragmatic exception below), then applies trailing-punctuation / paren-balance / entity trimming. It returns the position at which it stopped so the main inline tokenizer can resume there.

Precedence (GFM: code spans > autolinks > emphasis):

  • A code-span backtick terminates a URL body, sohttp://a.com`code` keeps the higher-precedence code span rather than swallowing it. (CommonMark/GFM give code spans higher precedence than autolinks.)
  • An email local part may contain_(the one emphasis delimiter that is a valid local-part character), e.g.a_b@example.com. The inline tokenizer resolves such a bare email before treating the_as emphasis (via try_email_autolink_at_delimiter()), so the full local part is linked. * and ~are not valid local-part characters, so they never need this.

Thread Safety:

Pure functions over their arguments; no shared mutable state. Safe for
concurrent use.

Functions

_is_left_boundary 1 bool
Return True if *prev_char* is a valid left boundary for an autolink. A valid a…
def _is_left_boundary(prev_char: str | None) -> bool

Return True if prev_char is a valid left boundary for an autolink.

A valid autolink is recognized only when preceded by start-of-line/text (prev_char is None), whitespace, or one of * _ ~ (.

Parameters
Name Type Description
prev_char str | None
Returns
bool
_is_url_terminator 1 bool
Return True if *c* ends a bare URL/www body. GFM extends a URL until whitespac…
def _is_url_terminator(c: str) -> bool

Return True if c ends a bare URL/www body.

GFM extends a URL until whitespace or<. We additionally stop at a backtick so that a code span (higher precedence in CommonMark/GFM) is not swallowed by the URL.

Parameters
Name Type Description
c str
Returns
bool
_trim_trailing_punctuation 1 str
Trim GFM trailing punctuation from a URL/www match. Rules (GFM autolinks exten…
def _trim_trailing_punctuation(match: str) -> str

Trim GFM trailing punctuation from a URL/www match.

Rules (GFM autolinks extension):

  • Strip trailing?!.,:*_~characters.
  • A trailing) is stripped while there are more ) than (in the remaining match.
  • If the match ends in a semicolon that closes an entity-like reference (&...;), strip the whole entity reference.

These rules are applied repeatedly until the match is stable.

Parameters
Name Type Description
match str
Returns
str
_scan_url 3 int
Scan a bare ``http://``/``https://`` URL body starting at *start*. *start* poi…
def _scan_url(text: str, start: int, scheme_len: int) -> int

Scan a barehttp:///https://URL body starting at start.

start points at the first character of the scheme. scheme_len is the length of thehttp:// or https://prefix. Returns the exclusive end index of the raw match (before trailing-punctuation trimming), or start if the authority is not a valid domain.

Parameters
Name Type Description
text str
start int
scheme_len int
Returns
int
_scan_www 2 int
Scan a ``www.`` link starting at *start* (the first ``w``). Returns the exclus…
def _scan_www(text: str, start: int) -> int

Scan awww. link starting at start (the first w).

Returns the exclusive end index of the raw match, or start if the authority is not a valid domain.

Parameters
Name Type Description
text str
start int
Returns
int
_scan_email 3 tuple[int, int] | None
Scan a bare email around the ``@`` at *at_pos*. Returns ``(start, end)`` of th…
def _scan_email(text: str, at_pos: int, min_start: int) -> tuple[int, int] | None

Scan a bare email around the@at at_pos.

Returns(start, end) of the matched email (exclusive end), or None if there is no valid email. The local part is scanned backwards from the @(but no earlier than min_start, the start of the current scan span, so the local part never crosses an inline-special boundary); the domain forwards.

Parameters
Name Type Description
text str
at_pos int
min_start int
Returns
tuple[int, int] | None