Building Project Files
هذا الالتزام موجود في:
111
venv/lib/python3.12/site-packages/mistune/directives/toc.py
Normal file
111
venv/lib/python3.12/site-packages/mistune/directives/toc.py
Normal file
@@ -0,0 +1,111 @@
|
||||
"""
|
||||
TOC directive
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
The TOC directive syntax looks like::
|
||||
|
||||
.. toc:: Title
|
||||
:min-level: 1
|
||||
:max-level: 3
|
||||
|
||||
"Title", "min-level", and "max-level" option can be empty. "min-level"
|
||||
and "max-level" are integers >= 1 and <= 6, which define the allowed
|
||||
heading levels writers want to include in the table of contents.
|
||||
"""
|
||||
|
||||
from typing import TYPE_CHECKING, Any, Dict, Match
|
||||
|
||||
from ..toc import normalize_toc_item, render_toc_ul
|
||||
from ._base import BaseDirective, DirectivePlugin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..block_parser import BlockParser
|
||||
from ..core import BaseRenderer, BlockState
|
||||
from ..markdown import Markdown
|
||||
|
||||
|
||||
class TableOfContents(DirectivePlugin):
|
||||
def __init__(self, min_level: int = 1, max_level: int = 3) -> None:
|
||||
self.min_level = min_level
|
||||
self.max_level = max_level
|
||||
|
||||
def generate_heading_id(self, token: Dict[str, Any], index: int) -> str:
|
||||
return "toc_" + str(index + 1)
|
||||
|
||||
def parse(self, block: "BlockParser", m: Match[str], state: "BlockState") -> Dict[str, Any]:
|
||||
title = self.parse_title(m)
|
||||
options = self.parse_options(m)
|
||||
if options:
|
||||
d_options = dict(options)
|
||||
collapse = "collapse" in d_options
|
||||
min_level = _normalize_level(d_options, "min-level", self.min_level)
|
||||
max_level = _normalize_level(d_options, "max-level", self.max_level)
|
||||
if min_level < self.min_level:
|
||||
raise ValueError(f'"min-level" option MUST be >= {self.min_level}')
|
||||
if max_level > self.max_level:
|
||||
raise ValueError(f'"max-level" option MUST be <= {self.max_level}')
|
||||
if min_level > max_level:
|
||||
raise ValueError('"min-level" option MUST be less than "max-level" option')
|
||||
else:
|
||||
collapse = False
|
||||
min_level = self.min_level
|
||||
max_level = self.max_level
|
||||
|
||||
attrs = {
|
||||
"min_level": min_level,
|
||||
"max_level": max_level,
|
||||
"collapse": collapse,
|
||||
}
|
||||
return {"type": "toc", "text": title or "", "attrs": attrs}
|
||||
|
||||
def toc_hook(self, md: "Markdown", state: "BlockState") -> None:
|
||||
sections = []
|
||||
headings = []
|
||||
|
||||
for tok in state.tokens:
|
||||
if tok["type"] == "toc":
|
||||
sections.append(tok)
|
||||
elif tok["type"] == "heading":
|
||||
headings.append(tok)
|
||||
|
||||
if sections:
|
||||
toc_items = []
|
||||
# adding ID for each heading
|
||||
for i, tok in enumerate(headings):
|
||||
tok["attrs"]["id"] = self.generate_heading_id(tok, i)
|
||||
toc_items.append(normalize_toc_item(md, tok))
|
||||
|
||||
for sec in sections:
|
||||
_min = sec["attrs"]["min_level"]
|
||||
_max = sec["attrs"]["max_level"]
|
||||
toc = [item for item in toc_items if _min <= item[0] <= _max]
|
||||
sec["attrs"]["toc"] = toc
|
||||
|
||||
def __call__(self, directive: BaseDirective, md: "Markdown") -> None:
|
||||
if md.renderer and md.renderer.NAME == "html":
|
||||
# only works with HTML renderer
|
||||
directive.register("toc", self.parse)
|
||||
md.before_render_hooks.append(self.toc_hook)
|
||||
md.renderer.register("toc", render_html_toc)
|
||||
|
||||
|
||||
def render_html_toc(renderer: "BaseRenderer", title: str, collapse: bool = False, **attrs: Any) -> str:
|
||||
if not title:
|
||||
title = "Table of Contents"
|
||||
content = render_toc_ul(attrs["toc"])
|
||||
|
||||
html = '<details class="toc"'
|
||||
if not collapse:
|
||||
html += " open"
|
||||
html += ">\n<summary>" + title + "</summary>\n"
|
||||
return html + content + "</details>\n"
|
||||
|
||||
|
||||
def _normalize_level(options: Dict[str, Any], name: str, default: Any) -> Any:
|
||||
level = options.get(name)
|
||||
if not level:
|
||||
return default
|
||||
try:
|
||||
return int(level)
|
||||
except (ValueError, TypeError):
|
||||
raise ValueError(f'"{name}" option MUST be integer')
|
المرجع في مشكلة جديدة
حظر مستخدم