diff --git a/pyproject.toml b/pyproject.toml index cbe52d7..001c794 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "mkdocs-include-markdown-plugin" -version = "7.1.7" +version = "7.1.8" description = "Mkdocs Markdown includer plugin." readme = "README.md" license = "Apache-2.0" diff --git a/src/mkdocs_include_markdown_plugin/event.py b/src/mkdocs_include_markdown_plugin/event.py index 5924927..e621ad6 100644 --- a/src/mkdocs_include_markdown_plugin/event.py +++ b/src/mkdocs_include_markdown_plugin/event.py @@ -28,6 +28,11 @@ ) from mkdocs_include_markdown_plugin.files_watcher import FilesWatcher from mkdocs_include_markdown_plugin.logger import logger +from mkdocs_include_markdown_plugin.placeholders import ( + escape_placeholders, + save_placeholder, + unescape_placeholders, +) if TYPE_CHECKING: # pragma: no cover @@ -46,30 +51,6 @@ ) -# Placeholders (taken from Python-Markdown) -STX = '\u0002' -''' "Start of Text" marker for placeholder templates. ''' -ETX = '\u0003' -''' "End of Text" marker for placeholder templates. ''' -INLINE_PLACEHOLDER_PREFIX = f'{STX}klzzwxh:' - - -def build_placeholder(num: int) -> str: - """Return a placeholder.""" - return f'{INLINE_PLACEHOLDER_PREFIX}{num}{ETX}' - - -def save_placeholder( - placeholders_contents: list[tuple[str, str]], - text_to_include: str, -) -> str: - """Save the included text and return the placeholder.""" - inclusion_index = len(placeholders_contents) - placeholder = build_placeholder(inclusion_index) - placeholders_contents.append((placeholder, text_to_include)) - return placeholder - - @dataclass class Settings: # noqa: D101 exclude: list[str] | None @@ -105,6 +86,7 @@ def get_file_content( # noqa: PLR0913, PLR0915 else: settings_ignore_paths = [] + markdown = escape_placeholders(markdown) placeholders_contents: list[tuple[str, str]] = [] def found_include_tag( # noqa: PLR0912, PLR0915 @@ -624,7 +606,7 @@ def found_include_markdown_tag( # noqa: PLR0912, PLR0915 # Replace placeholders by contents for placeholder, text in placeholders_contents: markdown = markdown.replace(placeholder, text, 1) - return markdown + return unescape_placeholders(markdown) def on_page_markdown( diff --git a/src/mkdocs_include_markdown_plugin/placeholders.py b/src/mkdocs_include_markdown_plugin/placeholders.py new file mode 100644 index 0000000..4b1e7a1 --- /dev/null +++ b/src/mkdocs_include_markdown_plugin/placeholders.py @@ -0,0 +1,37 @@ +"""Module for placeholders processing.""" + +# Placeholders (taken from Python-Markdown) +from __future__ import annotations + + +STX = '\u0002' +''' "Start of Text" marker for placeholder templates. ''' +ETX = '\u0003' +''' "End of Text" marker for placeholder templates. ''' +INLINE_PLACEHOLDER_PREFIX = f'{STX}klzzwxh:' + + +def build_placeholder(num: int) -> str: + """Return a placeholder.""" + return f'{INLINE_PLACEHOLDER_PREFIX}{num}{ETX}' + + +def escape_placeholders(text: str) -> str: + """Escape placeholders in the given text.""" + return text.replace(STX, f'\\{STX}').replace(ETX, f'\\{ETX}') + + +def unescape_placeholders(text: str) -> str: + """Unescape placeholders in the given text.""" + return text.replace(f'\\{STX}', STX).replace(f'\\{ETX}', ETX) + + +def save_placeholder( + placeholders_contents: list[tuple[str, str]], + text_to_include: str, +) -> str: + """Save the included text and return the placeholder.""" + inclusion_index = len(placeholders_contents) + placeholder = build_placeholder(inclusion_index) + placeholders_contents.append((placeholder, text_to_include)) + return placeholder diff --git a/tests/test_unit/test_include_markdown.py b/tests/test_unit/test_include_markdown.py index 3d5ca94..f5a9717 100644 --- a/tests/test_unit/test_include_markdown.py +++ b/tests/test_unit/test_include_markdown.py @@ -3,6 +3,7 @@ import pytest from mkdocs_include_markdown_plugin.event import on_page_markdown +from mkdocs_include_markdown_plugin.placeholders import build_placeholder @pytest.mark.parametrize( @@ -776,6 +777,27 @@ [], id='internal-anchor', ), + + # Placeholder collision + pytest.param( + '''# Header + +''' + build_placeholder(0) + ''' + +{% + include-markdown "{filepath}" +%} +''', + 'Content to include', + '''# Header + +''' + build_placeholder(0) + ''' + +Content to include +''', + [], + id='placeholder-collision', + ), ), ) def test_include_markdown(