import os from typing import TYPE_CHECKING, Any, Dict, List, Match, Union from ._base import BaseDirective, DirectivePlugin if TYPE_CHECKING: from ..block_parser import BlockParser from ..core import BaseRenderer, BlockState from ..markdown import Markdown class Include(DirectivePlugin): def parse( self, block: "BlockParser", m: Match[str], state: "BlockState" ) -> Union[Dict[str, Any], List[Dict[str, Any]]]: source_file = state.env.get("__file__") if not source_file: return {"type": "block_error", "raw": "Missing source file"} encoding = "utf-8" options = self.parse_options(m) if options: attrs = dict(options) if "encoding" in attrs: encoding = attrs["encoding"] else: attrs = {} relpath = self.parse_title(m) dest = os.path.join(os.path.dirname(source_file), relpath) dest = os.path.normpath(dest) if dest == source_file: return { "type": "block_error", "raw": "Could not include self: " + relpath, } if not os.path.isfile(dest): return { "type": "block_error", "raw": "Could not find file: " + relpath, } with open(dest, "rb") as f: content = f.read().decode(encoding) ext = os.path.splitext(relpath)[1] if ext in {".md", ".markdown", ".mkd"}: new_state = block.state_cls() new_state.env["__file__"] = dest new_state.process(content) block.parse(new_state) return new_state.tokens elif ext in {".html", ".xhtml", ".htm"}: return {"type": "block_html", "raw": content} attrs["filepath"] = dest return { "type": "include", "raw": content, "attrs": attrs, } def __call__(self, directive: BaseDirective, md: "Markdown") -> None: directive.register("include", self.parse) if md.renderer and md.renderer.NAME == "html": md.renderer.register("include", render_html_include) def render_html_include(renderer: "BaseRenderer", text: str, **attrs: Any) -> str: return '
\n' + text + "\n"