Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
927c0e0
Rewrite emphasis handling
facelessuser Sep 7, 2026
c06c76b
Remove outdated comment
facelessuser Sep 8, 2026
190dda3
If Markdown object is ever left in a bad state reset the stack
facelessuser Sep 8, 2026
6fca854
Consolidate reset behavior and ensure we update our tracked run
facelessuser Sep 8, 2026
fb46bb3
Have other reset locations call the reset function as well
facelessuser Sep 8, 2026
3475564
Add return type
facelessuser Sep 8, 2026
96b9e4b
Fix link errors
facelessuser Sep 8, 2026
f7bb325
Add a changelog item
facelessuser Sep 8, 2026
2bb7e2a
Consolidate duplicate code
facelessuser Sep 9, 2026
70785a6
Fix some edge cases
facelessuser Sep 10, 2026
e8dec3a
Separate cache info defines from reset
facelessuser Sep 10, 2026
b9ffc0d
Fix lint
facelessuser Sep 10, 2026
935733f
Fix a possible scenario where the next region is contiguous
facelessuser Sep 10, 2026
f5145af
Rework how resetting is performed
facelessuser Sep 10, 2026
f8d87d2
Remove unused module
facelessuser Sep 10, 2026
53aca45
Spelling
facelessuser Sep 10, 2026
701a666
Use test harness dedent
facelessuser Sep 10, 2026
3665087
Handle emphasis token chains longer than 3
facelessuser Sep 12, 2026
2ed5eca
Ignore redundant tests
facelessuser Sep 12, 2026
345402e
Remove dead code
facelessuser Sep 12, 2026
b0eedf5
Fixes for if just a double or single token is every used
facelessuser Sep 12, 2026
beec426
A double width only delimiter processor could fail on single width token
facelessuser Sep 12, 2026
f961e43
Avoid flipping strong/em tag nesting for triple emphasis tokens
facelessuser Sep 12, 2026
8a12d53
Forgot to commit last fix, better cache point
facelessuser Sep 13, 2026
606fc24
Another fix that missed getting committed
facelessuser Sep 14, 2026
0901c78
Combine emphasis handling into one processor
facelessuser Sep 14, 2026
572da35
Add punctuation logic
facelessuser Sep 15, 2026
dbda9ff
Fix typo
facelessuser Sep 15, 2026
f37bef3
Don't add a zero length delimiter to the stack
facelessuser Sep 16, 2026
c66cda2
Remove dead code
facelessuser Sep 16, 2026
c9678eb
Minor performance improvement
facelessuser Sep 23, 2026
89ea178
Move delimiter specific options to the delimiter object
facelessuser Oct 13, 2026
89573fd
Revert "Move delimiter specific options to the delimiter object"
facelessuser Oct 13, 2026
0d989f0
Fix typo
waylan Oct 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ See the [Contributing Guide](contributing.md) for details.
same paragraph, instead of splitting the paragraph around it (#1643).
* Fix issue where inline HTML attributes were rejected if they had `<` or `>` in the attribute (#1647).
* Fix issue where an unterminated end tag (`</foo`) could cause all remaining content to be dropped (#1651).
* Complete rework of emphasis handling to improve nested emphasis handling better (#1632).

## [3.11.0] - 2026-09-25

Expand Down
2 changes: 1 addition & 1 deletion docs/extensions/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ Here are some convenience functions and other examples:

| Class | Kind | Description |
| -------------------------------------------------------------------------------------|-----------|---------------------------------------------------------------|
| [`AsteriskProcessor`][markdown.inlinepatterns.AsteriskProcessor] | built-in | Emphasis processor for handling strong and em matches inside asterisks |
| [`DelimiterProcessor`][markdown.inlinepatterns.DelimiterProcessor] | built-in | Emphasis processor for handling strong and em matches |
| [`WikiLinksInlineProcessor`][markdown.extensions.wikilinks.WikiLinksInlineProcessor] | extension | Link `[[article names]]` to wiki given in metadata |
| [`FootnoteInlineProcessor`][markdown.extensions.footnotes.FootnoteInlineProcessor] | extension | Replaces footnote in text with link to footnote div at bottom |

Expand Down
9 changes: 8 additions & 1 deletion markdown/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from .preprocessors import build_preprocessors
from .blockprocessors import build_block_parser
from .treeprocessors import build_treeprocessors
from .inlinepatterns import build_inlinepatterns
from .inlinepatterns import build_inlinepatterns, DelimiterProcessor
from .postprocessors import build_postprocessors
from .extensions import Extension
from .serializers import to_html_string, to_xhtml_string
Expand Down Expand Up @@ -106,6 +106,7 @@ def __init__(self, **kwargs):

"""

self.last_run: float = 0.0
self.tab_length: int = kwargs.get('tab_length', 4)

self.ESCAPED_CHARS: list[str] = [
Expand All @@ -118,6 +119,7 @@ def __init__(self, **kwargs):
self.registeredExtensions: list[Extension] = []
self.docType = "" # TODO: Maybe delete this. It does not appear to be used anymore.
self.stripTopLevelTags: bool = True
self.delimiters: DelimiterProcessor | None = None

self.build_parser()

Expand Down Expand Up @@ -270,6 +272,11 @@ def reset(self) -> Markdown:
self.htmlStash.reset()
self.references.clear()

if self.delimiters is not None:
self.delimiters.reset()
if self.delimiters not in self.inlinePatterns:
self.delimiters = None

for extension in self.registeredExtensions:
if hasattr(extension, 'reset'):
extension.reset()
Expand Down
37 changes: 9 additions & 28 deletions markdown/extensions/legacy_em.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,7 @@
from __future__ import annotations

from . import Extension
from ..inlinepatterns import UnderscoreProcessor, EmStrongItem, EM_STRONG2_RE, STRONG_EM2_RE
import re

# _emphasis_
EMPHASIS_RE = r'(_)([^_]+)\1'

# __strong__
STRONG_RE = r'(_{2})(.+?)\1'

# __strong_em___
STRONG_EM_RE = r'(_)\1(?!\1)([^_]+?)\1(?!\1)(.+?)\1{3}'


class LegacyUnderscoreProcessor(UnderscoreProcessor):
"""Emphasis processor for handling strong and em matches inside underscores."""

PATTERNS = [
EmStrongItem(re.compile(EM_STRONG2_RE, re.DOTALL | re.UNICODE), 'double', 'strong,em'),
EmStrongItem(re.compile(STRONG_EM2_RE, re.DOTALL | re.UNICODE), 'double', 'em,strong'),
EmStrongItem(re.compile(STRONG_EM_RE, re.DOTALL | re.UNICODE), 'double2', 'strong,em'),
EmStrongItem(re.compile(STRONG_RE, re.DOTALL | re.UNICODE), 'single', 'strong'),
EmStrongItem(re.compile(EMPHASIS_RE, re.DOTALL | re.UNICODE), 'single', 'em')
]
from ..inlinepatterns import DelimiterProcessor


class LegacyEmExtension(Extension):
Expand All @@ -45,14 +23,17 @@ class LegacyEmExtension(Extension):
def extendMarkdown(self, md):
""" Register the processor.

| Class Instance | Registry | Name | Priority |
| ------------------------------------------------------------- | ---------------------------------------------------------------- | ------ | :------: |
| [`LegacyUnderscoreProcessor`][markdown.extensions.legacy_em.LegacyUnderscoreProcessor] | [`inlinepatterns`][markdown.inlinepatterns.build_inlinepatterns] | `em_strong2` | `50` |
| Class Instance | Registry | Name | Priority |
| ------------------------------------------------------------------ | ---------------------------------------------------------------- | ------------ | :------: |
| [`DelimiterProcessor`][markdown.inlinepatterns.DelimiterProcessor] | [`inlinepatterns`][markdown.inlinepatterns.build_inlinepatterns] | `em_strong` | `60` |

"""
# flake8: noqa: E501 48-50
md.inlinePatterns.register(LegacyUnderscoreProcessor(r'_'), 'em_strong2', 50)
# flake8: noqa: E501 27-29

if md.delimiters is not None:
md.delimiters.add('_', 'strong,em')
else:
md.inlinePatterns.register(DelimiterProcessor('_', 'strong,em', md), 'em_strong', 60)

def makeExtension(**kwargs): # pragma: no cover
""" Return an instance of the `LegacyEmExtension` """
Expand Down
Loading
Loading