Files
zulip/zerver/lib/markdown/include.py
Anders Kaseorg 3f0919cc65 markdown: Parse included blocks in a new parser state.
This fixes inclusion of a multi-paragraph file into a list item.

Followup to commit dc33a0ae67 (#22315).

Signed-off-by: Anders Kaseorg <anders@zulip.com>
(cherry picked from commit 869fe60689)
2022-07-07 13:31:32 -07:00

57 lines
1.9 KiB
Python

import os
import re
from typing import List, Match
from xml.etree.ElementTree import Element
from markdown import Extension, Markdown
from markdown.blockparser import BlockParser
from markdown.blockprocessors import BlockProcessor
from zerver.lib.exceptions import InvalidMarkdownIncludeStatement
from zerver.lib.markdown.priorities import BLOCK_PROCESSOR_PRIORITIES
class IncludeExtension(Extension):
def __init__(self, base_path: str) -> None:
super().__init__()
self.base_path = base_path
def extendMarkdown(self, md: Markdown) -> None:
md.parser.blockprocessors.register(
IncludeBlockProcessor(md.parser, self.base_path),
"include",
BLOCK_PROCESSOR_PRIORITIES["include"],
)
class IncludeBlockProcessor(BlockProcessor):
RE = re.compile(r"^ {,3}\{!([^!]+)!\} *$", re.M)
def __init__(self, parser: BlockParser, base_path: str) -> None:
super().__init__(parser)
self.base_path = base_path
def test(self, parent: Element, block: str) -> bool: # type: ignore[override] # https://github.com/python/typeshed/pull/8166
return bool(self.RE.search(block))
def expand_include(self, m: Match[str]) -> str:
try:
with open(os.path.normpath(os.path.join(self.base_path, m[1]))) as f:
lines = f.read().splitlines()
except OSError as e:
raise InvalidMarkdownIncludeStatement(m[0].strip()) from e
for prep in self.parser.md.preprocessors:
lines = prep.run(lines)
return "\n".join(lines)
def run(self, parent: Element, blocks: List[str]) -> None:
self.parser.state.set("include")
self.parser.parseChunk(parent, self.RE.sub(self.expand_include, blocks.pop(0)))
self.parser.state.reset()
def makeExtension(base_path: str) -> IncludeExtension:
return IncludeExtension(base_path=base_path)