Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Pygments in Pelican with Markdown?

TLDR: I am trying to do CSS line numbering in pelican, while writing in markdown. Pygments is used indirectly and you can't pass options to it, so I can't separate the lines and there is no CSS selector for "new line".

Using Markdown in Pelican, I can generate code blocks using the CodeHilite extension. Pelican doesn't support using pygments directly if you are using Markdown...only RST(and ... no to converting everything to RST).

So, what I have tried:

MD_EXTENSIONS = [
'codehilite(css_class=highlight,linenums=False,guess_lang=True,use_pygments=True)',
'extra']

And:

:::python
<div class="line">import __main__ as main</div>

And:

PYGMENTS_RST_OPTIONS = {'classprefix': 'pgcss', 'linenos': 'table'}

Can I get line numbers to show up? Yes. Can I get them to continue to the next code block? No. And that is why I want to use CSS line numbering...its way easier to control when the numbering starts and stops.

Any help would be greatly appreciated, I've been messing with this for a few hours.

like image 867
AtHeartEngineer Avatar asked Jan 08 '23 13:01

AtHeartEngineer


1 Answers

The only way I'm aware of is to fork the CodeHilite Extension (and I'm the developer). First you will need to make a copy of the existing extension (this file), make changes to the code necessary to effect your desired result, and save the file to your PYTHONPATH (probably in the "sitepackages" directory, the exact location of which depends on which system you are on and how Python was installed). Note that you will want to create a unique name for your file so as not to conflict with any other Python packages.

Once you have done that, you need to tell Pelican about it. As Pelican's config file is just Python, import your new extension (use the name of your file without the file extension: yourmodule.py => yourmodule) and include it in the list of extensions.

from yourmodule import CodeHiliteExtension
MD_EXTENSIONS = [
CodeHiliteExtension(css_class='highlight', linenums=False),
'extra']

Note that the call to CodeHiliteExtension is not a string but actually calling the class and passing in the appropriate arguments, which you can adjust as appropriate.

And that should be it. If you would like to set up a easier way to deploy your extension (or distribute it for others to use), you might want to consider creating a setup.py file, which is beyond the scope of this question. See this tutorial for help specific to Markdown extensions.

If you would like specific help with the changes you need to make to the code within the extension, that depends on what you want to accomplish. To get started, the arguments are passing to Pygments on line 117. The simplest approach would be to hardcode your desired options there.


Be ware that if you are trying to replicate the behavior in reStructuredText, you will likely be disappointed. Docutils wraps Pygments with some of its own processing. In fact, a few of the options never get passed to Pygments but are handled by the reStructeredText parser itself. If I recall correctly, CSS line numbering is one such feature. In fact, Pygments does not offer that as an option.

That being the case, you would need to modify your fork of the CodeHilite Extension by having Pygments return non-numbered code, then applying the necessary hooks yourself before the extension returns the highlighted code block. To do so, you would likely need to split on line breaks and then loop through the lines wrapping each line appropriately. Finally, join the newly wrapped lines and return.


I suspect the following (untested) changes will get you started:

diff --git a/markdown/extensions/codehilite.py b/markdown/extensions/codehilite.py
index 0657c37..fbd127d 100644
--- a/markdown/extensions/codehilite.py
+++ b/markdown/extensions/codehilite.py
@@ -115,12 +115,18 @@ class CodeHilite(object):
                 except ValueError:
                     lexer = get_lexer_by_name('text')
             formatter = get_formatter_by_name('html',
-                                              linenos=self.linenums,
+                                              linenos=self.linenums if self.linenumes != 'css' else False,
                                               cssclass=self.css_class,
                                               style=self.style,
                                               noclasses=self.noclasses,
                                               hl_lines=self.hl_lines)
-            return highlight(self.src, lexer, formatter)
+            result = highlight(self.src, lexer, formatter)
+            if self.linenums == 'css':
+                lines = result.split('\n')
+                for i, line in enumerate(lines):
+                    lines[i] = '<div class="line">%s</div>' % line
+                result = '\n'.join(lines)
+            return result
         else:
             # just escape and build markup usable by JS highlighting libs
             txt = self.src.replace('&', '&amp;')

You may have better success in attaining what you want by disabling Pygments and using a JavaScript library to do the highlighting. That depends on which JavaScript Library you choose and what features it has.

like image 190
Waylan Avatar answered Jan 18 '23 23:01

Waylan