annotate content/Coding/003-nl2br-markdown-ext.rst @ 4:7ce6393e6d30

Adding converted blog posts from old blog.
author Brian Neal <bgneal@gmail.com>
date Thu, 30 Jan 2014 21:45:03 -0600
parents
children
rev   line source
bgneal@4 1 A newline-to-break Python-Markdown extension
bgneal@4 2 ############################################
bgneal@4 3
bgneal@4 4 :date: 2011-05-09 22:40
bgneal@4 5 :tags: Markdown, Python
bgneal@4 6 :slug: a-newline-to-break-python-markdown-extension
bgneal@4 7 :author: Brian Neal
bgneal@4 8
bgneal@4 9 When I launched a new version of my website, I decided the new forums would use
bgneal@4 10 Markdown_ instead of BBCode_ for the markup. This decision was mainly a personal
bgneal@4 11 one for aesthetic reasons. I felt that Markdown was more natural to write compared
bgneal@4 12 to the clunky square brackets of BBCode.
bgneal@4 13
bgneal@4 14 My new site is coded in Python_ using the Django_ framework. For a Markdown implementation
bgneal@4 15 I chose `Python-Markdown`_.
bgneal@4 16
bgneal@4 17 My mainly non-technical users seemed largely ambivalent to the change from
bgneal@4 18 BBCode to Markdown. This was probably because I gave them a nice Javascript editor
bgneal@4 19 (`MarkItUp!`_) which inserted the correct markup for them.
bgneal@4 20
bgneal@4 21 However, shortly after launch, one particular feature of Markdown really riled up
bgneal@4 22 some users: the default line break behavior. In strict Markdown, to create a new
bgneal@4 23 paragraph, you must insert a blank line between paragraphs. Hard returns (newlines)
bgneal@4 24 are simply ignored, just like they are in HTML. You can, however, force a break by
bgneal@4 25 ending a line with two blank spaces. This isn't very intuitive, unlike the rest of
bgneal@4 26 Markdown.
bgneal@4 27
bgneal@4 28 Now I agree the default behavior is useful if you are creating an online document, like a blog post.
bgneal@4 29 However, non-technical users really didn't understand this behavior at all in the context
bgneal@4 30 of a forum post. For example, many of my users post radio-show playlists, formatted with
bgneal@4 31 one song per line. When such a playlist was pasted into a forum post, Markdown made it
bgneal@4 32 all one giant run-together paragraph. This did not please my users. Arguably, they should
bgneal@4 33 have used a Markdown list. But it became clear teaching people the new syntax wasn't
bgneal@4 34 going to work, especially when it used to work just fine in BBCode and they had created
bgneal@4 35 their playlists in the same way for several years.
bgneal@4 36
bgneal@4 37 It turns out I am not alone in my observations (or on the receiving end of user wrath). Other,
bgneal@4 38 much larger sites, like StackOverflow_ and GitHub_, have altered their Markdown parsers
bgneal@4 39 to treat newlines as hard breaks. How can this be done with Python-Markdown?
bgneal@4 40
bgneal@4 41 It turns out this is really easy. Python-Markdown was designed with user customization
bgneal@4 42 in mind by offering an extension facility. The `extension documentation`_ is good,
bgneal@4 43 and you can find extension writing help on the friendly `mailing list`_.
bgneal@4 44
bgneal@4 45 Here is a simple extension for Python-Markdown that turns newlines into HTML <br /> tags.
bgneal@4 46
bgneal@4 47 .. sourcecode:: python
bgneal@4 48
bgneal@4 49 """
bgneal@4 50 A python-markdown extension to treat newlines as hard breaks; like
bgneal@4 51 StackOverflow and GitHub flavored Markdown do.
bgneal@4 52
bgneal@4 53 """
bgneal@4 54 import markdown
bgneal@4 55
bgneal@4 56
bgneal@4 57 BR_RE = r'\n'
bgneal@4 58
bgneal@4 59 class Nl2BrExtension(markdown.Extension):
bgneal@4 60
bgneal@4 61 def extendMarkdown(self, md, md_globals):
bgneal@4 62 br_tag = markdown.inlinepatterns.SubstituteTagPattern(BR_RE, 'br')
bgneal@4 63 md.inlinePatterns.add('nl', br_tag, '_end')
bgneal@4 64
bgneal@4 65
bgneal@4 66 def makeExtension(configs=None):
bgneal@4 67 return Nl2BrExtension(configs)
bgneal@4 68
bgneal@4 69 I saved this code in a file called ``mdx_nl2br.py`` and put it on my ``PYTHONPATH``. You can then use
bgneal@4 70 it in a Django template like this:
bgneal@4 71
bgneal@4 72 .. sourcecode:: django
bgneal@4 73
bgneal@4 74 {{ value|markdown:"nl2br" }}
bgneal@4 75
bgneal@4 76 To use the extension in Python code, something like this should do the trick:
bgneal@4 77
bgneal@4 78 .. sourcecode:: python
bgneal@4 79
bgneal@4 80 import markdown
bgneal@4 81 md = markdown.Markdown(safe_mode=True, extensions=['nl2br'])
bgneal@4 82 converted_text = md.convert(text)
bgneal@4 83
bgneal@4 84 **Update (June 21, 2011):** This extension is now being distributed with
bgneal@4 85 Python-Markdown! See `issue 13 on github`_ for the details. Thanks to Waylan
bgneal@4 86 Limberg for the help in creating the extension and for including it with
bgneal@4 87 Python-Markdown.
bgneal@4 88
bgneal@4 89
bgneal@4 90 .. _Markdown: http://daringfireball.net/projects/markdown/
bgneal@4 91 .. _BBCode: http://en.wikipedia.org/wiki/BBCode
bgneal@4 92 .. _Python: http://python.org
bgneal@4 93 .. _Django: http://djangoproject.com
bgneal@4 94 .. _MarkItUp!: http://markitup.jaysalvat.com/home/
bgneal@4 95 .. _StackOverflow: http://blog.stackoverflow.com/2009/10/markdown-one-year-later/
bgneal@4 96 .. _GitHub: http://github.github.com/github-flavored-markdown/
bgneal@4 97 .. _Python-Markdown: http://www.freewisdom.org/projects/python-markdown/
bgneal@4 98 .. _extension documentation: http://www.freewisdom.org/projects/python-markdown/Writing_Extensions
bgneal@4 99 .. _mailing list: http://lists.sourceforge.net/lists/listinfo/python-markdown-discuss
bgneal@4 100 .. _issue 13 on github: https://github.com/waylan/Python-Markdown/issues/13