Allow showing only a range of lines for code blocks #2242
-
DescriptionI'm using mkdocstrings and Sybil to extract code examples in the documentation and test by running pylint on them via pytest. This forces me to sometimes add too much boilerplate to examples, which is distracting from the main idea I want to show in an example, but it is also really important that examples stay up to date and (mostly) working. An alternative would be to move the examples to separate files and use the snippet extension line selection feature, but I want to keep the examples in the docstrings, so they are also accessible in code editors, as python include all the docs in the code itself. Related links
Extra: BenefitsBeing able to write examples that are verifiable using linting tools to ensure they stay up to date, but still only being able to show the relevant parts that make sense for the documentation, avoiding distracting, boilerplate code. Solution IdeaI would like code blocks to accept selecting which lines to show, similar to what the snippet line selection or the highlight specific lines feature does. For example: Example:
``` py show_lines="4:"
# Bolierplate setup code
# More boiler plate setup code
# And some more
this is the_juicy_part
# more useful code
``` I'm suggesting the snippet extension syntax (with Optional: There could be some button to expand the example and show also the boilerplate code, so users could copy&paste the whole example and run it if they want. |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments 10 replies
-
The requested feature is quite niche, though I see why you would find it useful for your purposes, and I can see a select amount of people using it as well. One of the reasons I added custom fences to SuperFences was to allow people to create specialized behavior for their code blocks without me having to implement and maintain every niche case that was desired. What I can provide is some guidance as to how you can accomplish what you want with custom fences. You can simply override the code blocks you desire adding in the options to specify the lines to show. Lastly, you'd preprocess the code, stripping out any lines you did not wish to show before passing them along to the highlighter. You may have to wait until I find the time over the weekend to code up an example for you, but you can start reading about custom fences here: https://facelessuser.github.io/pymdown-extensions/extensions/superfences/#custom-fences. |
Beta Was this translation helpful? Give feedback.
-
Here's an example. We override all languages with """Example custom fence."""
import markdown
from pymdownx.superfences import highlight_validator
def remove_validator(language, inputs, options, attrs, md):
"""Highlight validator."""
# Add validation for special new options
for k, v in inputs.items():
if k == 'show_lines':
try:
options[k] = set(int(i) for i in v.split(','))
except Exception:
# Validation failed
return False
# Remove handled option from inputs
del inputs[k]
break
# Run default validator
res = highlight_validator(language, inputs, options, attrs, md)
return res
def remove_formatter(src="", language="", class_name=None, options=None, md="", **kwargs):
"""Formatter wrapper."""
# Alter source here
if 'show_lines' in options:
show = options['show_lines']
lines = []
for e, line in enumerate(src.split('\n'), 1):
if e in show:
lines.append(line)
src = '\n'.join(lines)
# Run through default highlighter
return md.preprocessors['fenced_code_block'].highlight(
src=src,
class_name=class_name,
language=language,
md=md,
options=options,
**kwargs
)
MD = """
``` py show_lines="1,2,3,8"
import something
import something_else
# Some comments
# that we
# want to
# avoid
something.go()
```
"""
html = markdown.markdown(
MD,
extensions=['pymdownx.superfences'],
extension_configs={
"pymdownx.superfences": {
"custom_fences": [
{
'name': '*',
'class': 'highlight',
'validator': remove_validator,
'format': remove_formatter
}
]
}
}
)
print(html) |
Beta Was this translation helpful? Give feedback.
-
Hi @facelessuser, thanks for the explanation and example. I really appreciate it. I will give it a try as soon as possible. I have one more question though, since I want to use this in Thanks again! |
Beta Was this translation helpful? Give feedback.
-
I can show you how I run them: I currently have one in my tools folder: https://github.com/facelessuser/pymdown-extensions/blob/main/tools/pymdownx_md_render.py. I place an I specify it in Lastly, to find local modules I have to run mkdocs with the I don't use Material's docker image, so if you are using that, you might have to ask on The alternative is that you make a pip installable package with your custom code and then you don't have to load local modules, you would just reference it as a normal installed module. Also, the example I provided is just a quick and dirty example. You will have to tweak the code to have it work exactly how you want, but it is a good starting point. |
Beta Was this translation helpful? Give feedback.
-
Just in case anybody else bumps into this, I create a package to implement it: |
Beta Was this translation helpful? Give feedback.
-
Hey @llucax and @facelessuser . Thanks for this post. I just wanted to mention that this is very useful to me as I like to explain python scripts line section by section to show how to run a python script with my custom program (for an example, see https://organisms.readthedocs.io/en/latest/Using_Run.html which was made with sphinx). I am currently using this package from @llucax which is working as expected. This is amazing thanks heaps! I was wondering if the installation requirement for Thanks again for this! |
Beta Was this translation helpful? Give feedback.
Here's an example. We override all languages with
*
and define our custom formatter and validator. In our custom validator we validate our new option and then feed the great of the inputs through the default code validator. Then in our formatter, we check for our new option, modify the source as needed, and send it through the default highlight logic. That's it. It should work on any language then.