⚠ This page is served via a proxy. Original site: https://github.com
This service does not collect credentials or authentication data.
Skip to content

Conversation

@dahlia
Copy link

@dahlia dahlia commented Jan 18, 2026

Summary

This PR fixes an issue where fenced code blocks inside blockquotes were not rendered correctly. Previously, the following Markdown:

> ```python
> def hello():
>     print("Hello, world!")
> ```

Would render the code as inline <code> elements or plain text instead of a proper <pre><code> block.

Problem

The FencedBlockPreprocessor runs once at the beginning of the parsing pipeline, before any block-level processing occurs. At this point, blockquote lines still have their > prefixes, so the fenced code regex pattern (which expects the fence at the start of a line) doesn't match.

When the BlockQuoteProcessor later strips the > prefixes and recursively parses the content via parseChunk(), only block processors run—not preprocessors. Since fenced code detection was only implemented as a preprocessor, it was never invoked for blockquote content.

Indented code blocks work correctly because they are handled by CodeBlockProcessor, which is a block processor that runs during recursive parsing.

Solution

Add a new FencedCodeBlockProcessor class that handles fenced code blocks as a BlockProcessor. This processor runs during recursive parsing, allowing it to detect fenced code blocks inside blockquotes and other nested contexts.

To avoid code duplication between the existing FencedBlockPreprocessor and the new FencedCodeBlockProcessor, common functionality has been extracted into a FencedCodeMixin class:

  • _check_for_deps() — Check for CodeHilite and AttrList extensions
  • _handle_attrs() — Parse attributes from the fence line
  • _generate_html() — Generate HTML output (with or without syntax highlighting)
  • _escape() — Basic HTML escaping

The preprocessor is retained for top-level fenced code blocks, as it processes them efficiently in a single pass. The block processor complements it by handling nested contexts.

Testing

Added TestFencedCodeInBlockquote test class with 5 test cases:

  • Basic fenced code with backticks in blockquote
  • Basic fenced code with tildes in blockquote
  • Fenced code with language specifier in blockquote
  • Fenced code with surrounding text in blockquote
  • Fenced code in nested blockquotes

The fenced code preprocessor only runs once before block parsing,
so fenced code blocks inside blockquotes were not detected after
the blockquote processor stripped the '>' prefixes.

Add a new FencedCodeBlockProcessor (BlockProcessor) that handles
fenced code blocks in nested contexts like blockquotes. Extract
common functionality into FencedCodeMixin to avoid code duplication
between the preprocessor and block processor.
@dahlia dahlia force-pushed the fix/fenced-code-in-blockquote branch from 4339b68 to a13c849 Compare January 18, 2026 22:07
dahlia added a commit to dahlia/dojang that referenced this pull request Jan 18, 2026
The fenced_code extension doesn't properly render code blocks inside
blockquotes.  This uses a forked version with a fix until the upstream
PR is merged and released:

Python-Markdown/markdown#1585
@waylan
Copy link
Member

waylan commented Jan 20, 2026

I don't have time to review this right now, but have you reviewed #53? There are references to various tests and goals of a working solution.

Also, I am curious why you left the current solution in place. Why not just provide a single working solution?

Finally, what does this provide that the superfences extension doesn't or can't? See our documentation here.

@waylan waylan added the needs-review Needs to be reviewed and/or approved. label Jan 20, 2026
@dahlia
Copy link
Author

dahlia commented Jan 20, 2026

Thank you for the feedback and for pointing me to #53. I should have reviewed it before submitting this PR.

After reading through the issue history, I now understand that:

  1. This is a documented limitation, not a bug
  2. There's a larger refactoring plan that was intended to address this properly
  3. SuperFences already provides this functionality as the recommended third-party solution

My implementation only addresses blockquotes (not lists), and keeping both the preprocessor and block processor adds complexity without providing a complete solution.

Given that SuperFences already solves this comprehensively and is the officially recommended approach, I'll close this PR. I apologize for not doing proper research beforehand.

@dahlia dahlia closed this Jan 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-review Needs to be reviewed and/or approved.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants