| from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Union |
|
|
| from .block_parser import BlockParser |
| from .core import BaseRenderer, BlockState |
| from .inline_parser import InlineParser |
| from .plugins import Plugin |
|
|
|
|
| class Markdown: |
| """Markdown instance to convert markdown text into HTML or other formats. |
| Here is an example with the HTMLRenderer:: |
| |
| from mistune import HTMLRenderer |
| |
| md = Markdown(renderer=HTMLRenderer(escape=False)) |
| md('hello **world**') |
| |
| :param renderer: a renderer to convert parsed tokens |
| :param block: block level syntax parser |
| :param inline: inline level syntax parser |
| :param plugins: mistune plugins to use |
| """ |
|
|
| def __init__( |
| self, |
| renderer: Optional[BaseRenderer] = None, |
| block: Optional[BlockParser] = None, |
| inline: Optional[InlineParser] = None, |
| plugins: Optional[Iterable[Plugin]] = None, |
| ): |
| if block is None: |
| block = BlockParser() |
|
|
| if inline is None: |
| inline = InlineParser() |
|
|
| self.renderer = renderer |
| self.block: BlockParser = block |
| self.inline: InlineParser = inline |
| self.before_parse_hooks: List[Callable[["Markdown", BlockState], None]] = [] |
| self.before_render_hooks: List[Callable[["Markdown", BlockState], Any]] = [] |
| self.after_render_hooks: List[ |
| Callable[["Markdown", Union[str, List[Dict[str, Any]]], BlockState], Union[str, List[Dict[str, Any]]]] |
| ] = [] |
|
|
| if plugins: |
| for plugin in plugins: |
| plugin(self) |
|
|
| def use(self, plugin: Plugin) -> None: |
| plugin(self) |
|
|
| def render_state(self, state: BlockState) -> Union[str, List[Dict[str, Any]]]: |
| data = self._iter_render(state.tokens, state) |
| if self.renderer: |
| return self.renderer(data, state) |
| return list(data) |
|
|
| def _iter_render(self, tokens: Iterable[Dict[str, Any]], state: BlockState) -> Iterable[Dict[str, Any]]: |
| for tok in tokens: |
| if "children" in tok: |
| children = self._iter_render(tok["children"], state) |
| tok["children"] = list(children) |
| elif "text" in tok: |
| text = tok.pop("text") |
| |
| |
| tok["children"] = self.inline(text.strip(" \r\n\t\f"), state.env) |
| yield tok |
|
|
| def parse(self, s: str, state: Optional[BlockState] = None) -> Tuple[Union[str, List[Dict[str, Any]]], BlockState]: |
| """Parse and convert the given markdown string. If renderer is None, |
| the returned **result** will be parsed markdown tokens. |
| |
| :param s: markdown string |
| :param state: instance of BlockState |
| :returns: result, state |
| """ |
| if state is None: |
| state = self.block.state_cls() |
|
|
| |
| s = s.replace("\r\n", "\n") |
| s = s.replace("\r", "\n") |
| if not s.endswith("\n"): |
| s += "\n" |
|
|
| state.process(s) |
|
|
| for hook in self.before_parse_hooks: |
| hook(self, state) |
|
|
| self.block.parse(state) |
|
|
| for hook2 in self.before_render_hooks: |
| hook2(self, state) |
|
|
| result = self.render_state(state) |
|
|
| for hook3 in self.after_render_hooks: |
| result = hook3(self, result, state) |
| return result, state |
|
|
| def read( |
| self, filepath: str, encoding: str = "utf-8", state: Optional[BlockState] = None |
| ) -> Tuple[Union[str, List[Dict[str, Any]]], BlockState]: |
| if state is None: |
| state = self.block.state_cls() |
|
|
| state.env["__file__"] = filepath |
| with open(filepath, "rb") as f: |
| s = f.read() |
|
|
| s2 = s.decode(encoding) |
| return self.parse(s2, state) |
|
|
| def __call__(self, s: str) -> Union[str, List[Dict[str, Any]]]: |
| if s is None: |
| s = "\n" |
| return self.parse(s)[0] |
|
|