Building Project Files
هذا الالتزام موجود في:
189
venv/lib/python3.12/site-packages/mistune/plugins/table.py
Normal file
189
venv/lib/python3.12/site-packages/mistune/plugins/table.py
Normal file
@@ -0,0 +1,189 @@
|
||||
import re
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
Dict,
|
||||
List,
|
||||
Match,
|
||||
Optional,
|
||||
Tuple,
|
||||
Union,
|
||||
)
|
||||
|
||||
from ..helpers import PREVENT_BACKSLASH
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..block_parser import BlockParser
|
||||
from ..core import BaseRenderer, BlockState
|
||||
from ..markdown import Markdown
|
||||
|
||||
# https://michelf.ca/projects/php-markdown/extra/#table
|
||||
|
||||
__all__ = ["table", "table_in_quote", "table_in_list"]
|
||||
|
||||
|
||||
TABLE_PATTERN = (
|
||||
r"^ {0,3}\|(?P<table_head>.+)\|[ \t]*\n"
|
||||
r" {0,3}\|(?P<table_align> *[-:]+[-| :]*)\|[ \t]*\n"
|
||||
r"(?P<table_body>(?: {0,3}\|.*\|[ \t]*(?:\n|$))*)\n*"
|
||||
)
|
||||
NP_TABLE_PATTERN = (
|
||||
r"^ {0,3}(?P<nptable_head>\S.*\|.*)\n"
|
||||
r" {0,3}(?P<nptable_align>[-:]+ *\|[-| :]*)\n"
|
||||
r"(?P<nptable_body>(?:.*\|.*(?:\n|$))*)\n*"
|
||||
)
|
||||
|
||||
TABLE_CELL = re.compile(r"^ {0,3}\|(.+)\|[ \t]*$")
|
||||
CELL_SPLIT = re.compile(r" *" + PREVENT_BACKSLASH + r"\| *")
|
||||
ALIGN_CENTER = re.compile(r"^ *:-+: *$")
|
||||
ALIGN_LEFT = re.compile(r"^ *:-+ *$")
|
||||
ALIGN_RIGHT = re.compile(r"^ *-+: *$")
|
||||
|
||||
|
||||
def parse_table(block: "BlockParser", m: Match[str], state: "BlockState") -> Optional[int]:
|
||||
pos = m.end()
|
||||
header = m.group("table_head")
|
||||
align = m.group("table_align")
|
||||
thead, aligns = _process_thead(header, align)
|
||||
if not thead:
|
||||
return None
|
||||
assert aligns is not None
|
||||
|
||||
rows = []
|
||||
body = m.group("table_body")
|
||||
for text in body.splitlines():
|
||||
m2 = TABLE_CELL.match(text)
|
||||
if not m2: # pragma: no cover
|
||||
return None
|
||||
row = _process_row(m2.group(1), aligns)
|
||||
if not row:
|
||||
return None
|
||||
rows.append(row)
|
||||
|
||||
children = [thead, {"type": "table_body", "children": rows}]
|
||||
state.append_token({"type": "table", "children": children})
|
||||
return pos
|
||||
|
||||
|
||||
def parse_nptable(block: "BlockParser", m: Match[str], state: "BlockState") -> Optional[int]:
|
||||
header = m.group("nptable_head")
|
||||
align = m.group("nptable_align")
|
||||
thead, aligns = _process_thead(header, align)
|
||||
if not thead:
|
||||
return None
|
||||
assert aligns is not None
|
||||
|
||||
rows = []
|
||||
body = m.group("nptable_body")
|
||||
for text in body.splitlines():
|
||||
row = _process_row(text, aligns)
|
||||
if not row:
|
||||
return None
|
||||
rows.append(row)
|
||||
|
||||
children = [thead, {"type": "table_body", "children": rows}]
|
||||
state.append_token({"type": "table", "children": children})
|
||||
return m.end()
|
||||
|
||||
|
||||
def _process_thead(header: str, align: str) -> Union[Tuple[None, None], Tuple[Dict[str, Any], List[str]]]:
|
||||
headers = CELL_SPLIT.split(header)
|
||||
aligns = CELL_SPLIT.split(align)
|
||||
if len(headers) != len(aligns):
|
||||
return None, None
|
||||
|
||||
for i, v in enumerate(aligns):
|
||||
if ALIGN_CENTER.match(v):
|
||||
aligns[i] = "center"
|
||||
elif ALIGN_LEFT.match(v):
|
||||
aligns[i] = "left"
|
||||
elif ALIGN_RIGHT.match(v):
|
||||
aligns[i] = "right"
|
||||
else:
|
||||
aligns[i] = None
|
||||
|
||||
children = [
|
||||
{"type": "table_cell", "text": text.strip(), "attrs": {"align": aligns[i], "head": True}}
|
||||
for i, text in enumerate(headers)
|
||||
]
|
||||
thead = {"type": "table_head", "children": children}
|
||||
return thead, aligns
|
||||
|
||||
|
||||
def _process_row(text: str, aligns: List[str]) -> Optional[Dict[str, Any]]:
|
||||
cells = CELL_SPLIT.split(text)
|
||||
if len(cells) != len(aligns):
|
||||
return None
|
||||
|
||||
children = [
|
||||
{"type": "table_cell", "text": text.strip(), "attrs": {"align": aligns[i], "head": False}}
|
||||
for i, text in enumerate(cells)
|
||||
]
|
||||
return {"type": "table_row", "children": children}
|
||||
|
||||
|
||||
def render_table(renderer: "BaseRenderer", text: str) -> str:
|
||||
return "<table>\n" + text + "</table>\n"
|
||||
|
||||
|
||||
def render_table_head(renderer: "BaseRenderer", text: str) -> str:
|
||||
return "<thead>\n<tr>\n" + text + "</tr>\n</thead>\n"
|
||||
|
||||
|
||||
def render_table_body(renderer: "BaseRenderer", text: str) -> str:
|
||||
return "<tbody>\n" + text + "</tbody>\n"
|
||||
|
||||
|
||||
def render_table_row(renderer: "BaseRenderer", text: str) -> str:
|
||||
return "<tr>\n" + text + "</tr>\n"
|
||||
|
||||
|
||||
def render_table_cell(renderer: "BaseRenderer", text: str, align: Optional[str] = None, head: bool = False) -> str:
|
||||
if head:
|
||||
tag = "th"
|
||||
else:
|
||||
tag = "td"
|
||||
|
||||
html = " <" + tag
|
||||
if align:
|
||||
html += ' style="text-align:' + align + '"'
|
||||
|
||||
return html + ">" + text + "</" + tag + ">\n"
|
||||
|
||||
|
||||
def table(md: "Markdown") -> None:
|
||||
"""A mistune plugin to support table, spec defined at
|
||||
https://michelf.ca/projects/php-markdown/extra/#table
|
||||
|
||||
Here is an example:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
First Header | Second Header
|
||||
------------- | -------------
|
||||
Content Cell | Content Cell
|
||||
Content Cell | Content Cell
|
||||
|
||||
:param md: Markdown instance
|
||||
"""
|
||||
md.block.register("table", TABLE_PATTERN, parse_table, before="paragraph")
|
||||
md.block.register("nptable", NP_TABLE_PATTERN, parse_nptable, before="paragraph")
|
||||
|
||||
if md.renderer and md.renderer.NAME == "html":
|
||||
md.renderer.register("table", render_table)
|
||||
md.renderer.register("table_head", render_table_head)
|
||||
md.renderer.register("table_body", render_table_body)
|
||||
md.renderer.register("table_row", render_table_row)
|
||||
md.renderer.register("table_cell", render_table_cell)
|
||||
|
||||
|
||||
def table_in_quote(md: "Markdown") -> None:
|
||||
"""Enable table plugin in block quotes."""
|
||||
md.block.insert_rule(md.block.block_quote_rules, "table", before="paragraph")
|
||||
md.block.insert_rule(md.block.block_quote_rules, "nptable", before="paragraph")
|
||||
|
||||
|
||||
def table_in_list(md: "Markdown") -> None:
|
||||
"""Enable table plugin in list."""
|
||||
md.block.insert_rule(md.block.list_rules, "table", before="paragraph")
|
||||
md.block.insert_rule(md.block.list_rules, "nptable", before="paragraph")
|
المرجع في مشكلة جديدة
حظر مستخدم