mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 14:03:30 +00:00 
			
		
		
		
	fenced_code: Refactor to avoid nested classes.
Nested classes are kind of expensive in Python, particularly when you throw in mypy annotations. Also, flatter is arguably better, although it is kind of a pain here not to have closures.
This commit is contained in:
		@@ -125,18 +125,6 @@ class FencedCodeExtension(markdown.Extension):
 | 
			
		||||
                             position)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FencedBlockPreprocessor(markdown.preprocessors.Preprocessor):
 | 
			
		||||
    def __init__(self, md: markdown.Markdown) -> None:
 | 
			
		||||
        markdown.preprocessors.Preprocessor.__init__(self, md)
 | 
			
		||||
 | 
			
		||||
        self.checked_for_codehilite = False
 | 
			
		||||
        self.codehilite_conf = {}  # type: Dict[str, List[Any]]
 | 
			
		||||
 | 
			
		||||
    def run(self, lines: Iterable[str]) -> List[str]:
 | 
			
		||||
        """ Match and store Fenced Code Blocks in the HtmlStash. """
 | 
			
		||||
 | 
			
		||||
        output = []  # type: List[str]
 | 
			
		||||
 | 
			
		||||
class BaseHandler:
 | 
			
		||||
    def handle_line(self, line: str) -> None:
 | 
			
		||||
        raise NotImplementedError()
 | 
			
		||||
@@ -144,45 +132,38 @@ class FencedBlockPreprocessor(markdown.preprocessors.Preprocessor):
 | 
			
		||||
    def done(self) -> None:
 | 
			
		||||
        raise NotImplementedError()
 | 
			
		||||
 | 
			
		||||
        processor = self
 | 
			
		||||
        handlers = []  # type: List[BaseHandler]
 | 
			
		||||
def generic_handler(processor: Any, output: MutableSequence[str], fence: str, lang: str) -> BaseHandler:
 | 
			
		||||
    if lang in ('quote', 'quoted'):
 | 
			
		||||
        return QuoteHandler(processor, output, fence)
 | 
			
		||||
    elif lang in ('math', 'tex', 'latex'):
 | 
			
		||||
        return TexHandler(processor, output, fence)
 | 
			
		||||
    else:
 | 
			
		||||
        return CodeHandler(processor, output, fence, lang)
 | 
			
		||||
 | 
			
		||||
        def push(handler: BaseHandler) -> None:
 | 
			
		||||
            handlers.append(handler)
 | 
			
		||||
 | 
			
		||||
        def pop() -> None:
 | 
			
		||||
            handlers.pop()
 | 
			
		||||
 | 
			
		||||
        def check_for_new_fence(output: MutableSequence[str], line: str) -> None:
 | 
			
		||||
def check_for_new_fence(processor: Any, output: MutableSequence[str], line: str) -> None:
 | 
			
		||||
    m = FENCE_RE.match(line)
 | 
			
		||||
    if m:
 | 
			
		||||
        fence = m.group('fence')
 | 
			
		||||
        lang = m.group('lang')
 | 
			
		||||
                handler = generic_handler(output, fence, lang)
 | 
			
		||||
                push(handler)
 | 
			
		||||
        handler = generic_handler(processor, output, fence, lang)
 | 
			
		||||
        processor.push(handler)
 | 
			
		||||
    else:
 | 
			
		||||
        output.append(line)
 | 
			
		||||
 | 
			
		||||
class OuterHandler(BaseHandler):
 | 
			
		||||
            def __init__(self, output: MutableSequence[str]) -> None:
 | 
			
		||||
    def __init__(self, processor: Any, output: MutableSequence[str]) -> None:
 | 
			
		||||
        self.output = output
 | 
			
		||||
        self.processor = processor
 | 
			
		||||
 | 
			
		||||
    def handle_line(self, line: str) -> None:
 | 
			
		||||
                check_for_new_fence(self.output, line)
 | 
			
		||||
        check_for_new_fence(self.processor, self.output, line)
 | 
			
		||||
 | 
			
		||||
    def done(self) -> None:
 | 
			
		||||
                pop()
 | 
			
		||||
 | 
			
		||||
        def generic_handler(output: MutableSequence[str], fence: str, lang: str) -> BaseHandler:
 | 
			
		||||
            if lang in ('quote', 'quoted'):
 | 
			
		||||
                return QuoteHandler(output, fence)
 | 
			
		||||
            elif lang in ('math', 'tex', 'latex'):
 | 
			
		||||
                return TexHandler(output, fence)
 | 
			
		||||
            else:
 | 
			
		||||
                return CodeHandler(output, fence, lang)
 | 
			
		||||
        self.processor.pop()
 | 
			
		||||
 | 
			
		||||
class CodeHandler(BaseHandler):
 | 
			
		||||
            def __init__(self, output: MutableSequence[str], fence: str, lang: str) -> None:
 | 
			
		||||
    def __init__(self, processor: Any, output: MutableSequence[str], fence: str, lang: str) -> None:
 | 
			
		||||
        self.processor = processor
 | 
			
		||||
        self.output = output
 | 
			
		||||
        self.fence = fence
 | 
			
		||||
        self.lang = lang
 | 
			
		||||
@@ -196,16 +177,17 @@ class FencedBlockPreprocessor(markdown.preprocessors.Preprocessor):
 | 
			
		||||
 | 
			
		||||
    def done(self) -> None:
 | 
			
		||||
        text = '\n'.join(self.lines)
 | 
			
		||||
                text = processor.format_code(self.lang, text)
 | 
			
		||||
                text = processor.placeholder(text)
 | 
			
		||||
        text = self.processor.format_code(self.lang, text)
 | 
			
		||||
        text = self.processor.placeholder(text)
 | 
			
		||||
        processed_lines = text.split('\n')
 | 
			
		||||
        self.output.append('')
 | 
			
		||||
        self.output.extend(processed_lines)
 | 
			
		||||
        self.output.append('')
 | 
			
		||||
                pop()
 | 
			
		||||
        self.processor.pop()
 | 
			
		||||
 | 
			
		||||
class QuoteHandler(BaseHandler):
 | 
			
		||||
            def __init__(self, output: MutableSequence[str], fence: str) -> None:
 | 
			
		||||
    def __init__(self, processor: Any, output: MutableSequence[str], fence: str) -> None:
 | 
			
		||||
        self.processor = processor
 | 
			
		||||
        self.output = output
 | 
			
		||||
        self.fence = fence
 | 
			
		||||
        self.lines = []  # type: List[str]
 | 
			
		||||
@@ -214,19 +196,20 @@ class FencedBlockPreprocessor(markdown.preprocessors.Preprocessor):
 | 
			
		||||
        if line.rstrip() == self.fence:
 | 
			
		||||
            self.done()
 | 
			
		||||
        else:
 | 
			
		||||
                    check_for_new_fence(self.lines, line)
 | 
			
		||||
            check_for_new_fence(self.processor, self.lines, line)
 | 
			
		||||
 | 
			
		||||
    def done(self) -> None:
 | 
			
		||||
        text = '\n'.join(self.lines)
 | 
			
		||||
                text = processor.format_quote(text)
 | 
			
		||||
        text = self.processor.format_quote(text)
 | 
			
		||||
        processed_lines = text.split('\n')
 | 
			
		||||
        self.output.append('')
 | 
			
		||||
        self.output.extend(processed_lines)
 | 
			
		||||
        self.output.append('')
 | 
			
		||||
                pop()
 | 
			
		||||
        self.processor.pop()
 | 
			
		||||
 | 
			
		||||
class TexHandler(BaseHandler):
 | 
			
		||||
            def __init__(self, output: MutableSequence[str], fence: str) -> None:
 | 
			
		||||
    def __init__(self, processor: Any, output: MutableSequence[str], fence: str) -> None:
 | 
			
		||||
        self.processor = processor
 | 
			
		||||
        self.output = output
 | 
			
		||||
        self.fence = fence
 | 
			
		||||
        self.lines = []  # type: List[str]
 | 
			
		||||
@@ -239,22 +222,44 @@ class FencedBlockPreprocessor(markdown.preprocessors.Preprocessor):
 | 
			
		||||
 | 
			
		||||
    def done(self) -> None:
 | 
			
		||||
        text = '\n'.join(self.lines)
 | 
			
		||||
                text = processor.format_tex(text)
 | 
			
		||||
                text = processor.placeholder(text)
 | 
			
		||||
        text = self.processor.format_tex(text)
 | 
			
		||||
        text = self.processor.placeholder(text)
 | 
			
		||||
        processed_lines = text.split('\n')
 | 
			
		||||
        self.output.append('')
 | 
			
		||||
        self.output.extend(processed_lines)
 | 
			
		||||
        self.output.append('')
 | 
			
		||||
                pop()
 | 
			
		||||
        self.processor.pop()
 | 
			
		||||
 | 
			
		||||
        handler = OuterHandler(output)
 | 
			
		||||
        push(handler)
 | 
			
		||||
 | 
			
		||||
class FencedBlockPreprocessor(markdown.preprocessors.Preprocessor):
 | 
			
		||||
    def __init__(self, md: markdown.Markdown) -> None:
 | 
			
		||||
        markdown.preprocessors.Preprocessor.__init__(self, md)
 | 
			
		||||
 | 
			
		||||
        self.checked_for_codehilite = False
 | 
			
		||||
        self.codehilite_conf = {}  # type: Dict[str, List[Any]]
 | 
			
		||||
 | 
			
		||||
    def push(self, handler: BaseHandler) -> None:
 | 
			
		||||
        self.handlers.append(handler)
 | 
			
		||||
 | 
			
		||||
    def pop(self) -> None:
 | 
			
		||||
        self.handlers.pop()
 | 
			
		||||
 | 
			
		||||
    def run(self, lines: Iterable[str]) -> List[str]:
 | 
			
		||||
        """ Match and store Fenced Code Blocks in the HtmlStash. """
 | 
			
		||||
 | 
			
		||||
        output = []  # type: List[str]
 | 
			
		||||
 | 
			
		||||
        processor = self
 | 
			
		||||
        self.handlers = []  # type: List[BaseHandler]
 | 
			
		||||
 | 
			
		||||
        handler = OuterHandler(processor, output)
 | 
			
		||||
        self.push(handler)
 | 
			
		||||
 | 
			
		||||
        for line in lines:
 | 
			
		||||
            handlers[-1].handle_line(line)
 | 
			
		||||
            self.handlers[-1].handle_line(line)
 | 
			
		||||
 | 
			
		||||
        while handlers:
 | 
			
		||||
            handlers[-1].done()
 | 
			
		||||
        while self.handlers:
 | 
			
		||||
            self.handlers[-1].done()
 | 
			
		||||
 | 
			
		||||
        # This fiddly handling of new lines at the end of our output was done to make
 | 
			
		||||
        # existing tests pass.  Bugdown is just kind of funny when it comes to new lines,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user