facelessuser / pymdown-extensions

Extensions for Python Markdown
https://facelessuser.github.io/pymdown-extensions/
Other
949 stars 253 forks source link

Snippet include file brefore/after label #2294

Closed astromatt closed 8 months ago

astromatt commented 8 months ago

Description

I am converting my 5000 pages (yes, 5k pages) Python training materials from ReST to Markdown and I would like to replicate behavior of literalinclude tag:

.. literalinclude:: myfile.py
    :caption: :download:`Solution <myfile.py>`
    :end-before: # Solution

So, that I can include file content from the first line until the desired label (in this case comment "# Solution"). I cannot use numeric slices, because solution lengths are variable for each assignment I have in my materials.

Benefits

Ability to include only part of the file.

Solution Idea

--8<-- "myfile.py" before:"# Solution"

or

--8<-- "myfile.py">"# Solution"

or

--8<-- "myfile.py":>"# Solution"

Also mind, that one-liner (including fence) syntax for Snippets would be nice:

`--8<-- "myfile.py" before:"# Solution"`
astromatt commented 8 months ago

I wrote small extension for SuperFences:

File myproject/extensions/include.py:

import re
from pathlib import Path
from pymdownx.superfences import SuperFencesException

def formatter(source, language, css_class, options, md, **kwargs):
    file = re.search(r'file="(.+)"', source).group(1)
    before = re.search(r'before="(.+)"', source).group(1)
    path = Path(__file__).parent.parent / 'docs' / file
    if not path.exists():
        raise SuperFencesException(f'File {path} does not exist')
    content = path.read_text()
    if before not in content:
        raise SuperFencesException(f'File {path} does not contain {before}')
    assignment, solution = content.split(before)
    return f"<pre><code>{assignment}</code></pre>"

File myproject/mkdocs.yml:

  - pymdownx.superfences:
      custom_fences:
        - name: include
          class: include
          format: !!python/name:extensions.include.formatter

File myproject/docs/myfile.md:

\```include
file="assignments/myfile.py"
before="# Solution"
\```

Of course without escaping the ` (ticks, fences) characters.

It works, but I am struggling with code highlighting, adding title (to work the same as regular title for fence) and getting an absolute path of a file which triggered my function.

If I do:

<div class="language-python highlight">
    <span class="filename">{path.stem}</span>
    <pre>
    <code>{assignment}</code>
    </pre>
</div>

Then in output HTML there is a blank line between title and code block. Code highlighting doesn't work at all.

Any help appreciated :)