summaryrefslogtreecommitdiffstats
path: root/contrib/python/mdit-py-plugins/mdit_py_plugins/gfm/__init__.py
blob: 5b363621254a89330305947f81709e18717eefdb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
"""Composite GFM (GitHub Flavored Markdown) plugin.

Enables a set of plugins that together approximate GitHub's Markdown rendering:

- Tables (built-in)
- Strikethrough with single and double tildes (built-in)
- Autolinks (gfm_autolink plugin)
- Task lists (built-in, markdown-it-py >= 4.1.0)
- Alerts (built-in, markdown-it-py >= 4.1.0)
- Footnotes (``[^label]`` references and definitions)

Optional extras:

- Dollar math (``$...$`` / ``$$...$$``)
- Front matter (YAML)

.. note::
   Tag filtering (disallowed raw HTML tags) is not yet implemented.

.. seealso::
   - `GitHub Flavored Markdown Spec <https://github.github.com/gfm/>`__
   - `GitHub basic formatting syntax
     <https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax>`__

.. versionadded:: 0.5.0

Requires markdown-it-py >= 4.1.0.
"""

from __future__ import annotations

from functools import lru_cache

from markdown_it import MarkdownIt
from markdown_it import __version__ as _mdit_version

from mdit_py_plugins.dollarmath import dollarmath_plugin
from mdit_py_plugins.footnote import footnote_plugin
from mdit_py_plugins.front_matter import front_matter_plugin
from mdit_py_plugins.gfm_autolink import gfm_autolink_plugin

__all__ = ("gfm_plugin",)

_MIN_VERSION = (4, 1, 0)


@lru_cache(maxsize=8)
def _parse_version(v: str) -> tuple[int, ...]:
    """Parse a version string like '4.1.0' into a tuple of ints."""
    return tuple(int(x) for x in v.split(".")[:3])


def gfm_plugin(
    md: MarkdownIt,
    *,
    dollarmath: bool = False,
    front_matter: bool = False,
    tasklists_editable: bool = False,
) -> None:
    """Enable GFM-like rendering.

    Starts from the current parser configuration and enables the GFM
    components on top.

    :param dollarmath: Enable dollar-delimited math (``$...$``, ``$$...$$``).
    :param front_matter: Enable YAML front matter (``---``).
    :param tasklists_editable: If True, rendered task list checkboxes are not
        disabled (i.e. they are interactive).
    """
    if _parse_version(_mdit_version) < _MIN_VERSION:
        raise RuntimeError(
            f"gfm_plugin requires markdown-it-py >= {'.'.join(str(x) for x in _MIN_VERSION)} "
            f"(installed: {_mdit_version})"
        )

    # Enable table and strikethrough rules (built into markdown-it-py)
    md.enable("table")
    md.enable("strikethrough")

    # GFM options available in markdown-it-py >= 4.1.0
    md.options["tasklists"] = True
    md.options["tasklists_editable"] = tasklists_editable
    md.options["alerts"] = True
    md.options["strikethrough_single_tilde"] = True
    # GFM autolinks
    md.use(gfm_autolink_plugin)

    # Footnotes (inline footnotes ^[...] are not part of GFM)
    md.use(footnote_plugin, inline=False)

    # Dollar math (inline $...$ and block $$...$$)
    if dollarmath:
        md.use(dollarmath_plugin, allow_blank_lines=False)

    # TODO: Tag filter — replace leading `<` with `&lt;` for disallowed raw
    # HTML tags: <title>, <textarea>, <style>, <xmp>, <iframe>, <noembed>,
    # <noframes>, <script>, <plaintext>.
    # See https://github.github.com/gfm/#disallowed-raw-html-extension-

    # Optional plugins
    if front_matter:
        md.use(front_matter_plugin)