Login

Revisiting Pygments and Markdown

Author:
djypsy
Posted:
August 8, 2007
Language:
Python
Version:
.96
Score:
1 (after 1 ratings)

A variation on a theme, inspired by snippet 39 and snippet 119. The intent is to provide a more generic and simple mechanism for combining Markdown with Pygments. Common scenarios could include blogging or commenting. Snippet 119 seemed too specific and perhaps not as efficient, needing to process the HTML twice to accomplish it's ends. The one snag in the implementation is the need to use a tag other than code as a wrapper. See the comments for details.

You will need the BeautifulSoup module installed.

Sample usage:

from django.db import models

class Blog(models.Model):
    '''Bare bones blogging model'''
    title = models.CharField(maxlength=255)
    slug = models.SlugField(maxlength=255, prepopulate_from=('title',))
    pub_date = models.DateTimeField()

    # the cooked view, cached for quick retrieval 
    blog = models.TextField()

    # the raw markdown-encoded text, saved for subsequent edits
    markdown = models.TextField()

    def save(self):
        from datetime import datetime
        if not self.id and not self.pub_date:
            self.pub_date = datetime.now()

        self.blog = pygmented_markdown(self.markdown)
        super(Blog, self).save()
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from pygments.lexers import LEXERS, get_lexer_by_name
from pygments import highlight
from pygments.formatters import HtmlFormatter
from BeautifulSoup import BeautifulSoup
from markdown import markdown

# a tuple of known lexer names
_lexer_names = reduce(lambda a,b: a + b[2], LEXERS.itervalues(), ())

# default formatter
_formatter = HtmlFormatter(cssclass='source')

def pygmented_markdown(raw):
    '''
    Accepts raw markdown text for markup processing. Using BeatifuleSoup on the
    results of markdown processing, the following constructs will be replaced
    by with pygmented highlighting. E.g.::
    
        <pre class="???">
            ...
        </pre>
        
    Where ``???`` is the name of a supported pygments lexer, e.g.: ``python``, 
    ``css``, ``html``.
    
    Note: Semantically, it would make more sense to wrap the code in a 
    ``<code>...</code>`` tag; however, my tests using markdown.py - as well as 
    markdown.pl from John Gruber - have shown that the inner HTML of the 
    ``<code>`` tag is not immune to translation.
    '''
    soup = BeautifulSoup(markdown(raw))
    for tag in soup.findAll('pre'):
        lexer_name = tag.get('class')
        if lexer_name and lexer_name in _lexer_names:
            lexer = get_lexer_by_name(lexer_name, stripnl=True, encoding='UTF-8')
            tag.replaceWith(highlight(tag.renderContents(), lexer, _formatter))
    
    return unicode(soup)

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 3 months, 1 week ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 3 months, 2 weeks ago
  3. Serializer factory with Django Rest Framework by julio 10 months, 1 week ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 11 months ago
  5. Help text hyperlinks by sa2812 11 months, 3 weeks ago

Comments

djypsy (on August 8, 2007):

@waylan:

Thanks for the feedback. I was unaware of this extension, and will make use of it for my own personal site. However, in a few other work-related scenarios, I don't have this option open to me, so I'm stuck using the brute force mechanism shown here.

#

Please login first before commenting.