16516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru#!/usr/bin/env python 26516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 36516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru''' 46516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste QueruWikiLinks Extension for Python-Markdown 56516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru====================================== 66516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 76516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste QueruConverts [[WikiLinks]] to relative links. Requires Python-Markdown 2.0+ 86516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 96516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste QueruBasic usage: 106516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 116516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru >>> import markdown 126516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru >>> text = "Some text with a [[WikiLink]]." 136516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru >>> html = markdown.markdown(text, ['wikilinks']) 146516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru >>> html 156516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru u'<p>Some text with a <a class="wikilink" href="/WikiLink/">WikiLink</a>.</p>' 166516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 176516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste QueruWhitespace behavior: 186516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 196516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru >>> markdown.markdown('[[ foo bar_baz ]]', ['wikilinks']) 206516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru u'<p><a class="wikilink" href="/foo_bar_baz/">foo bar_baz</a></p>' 216516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru >>> markdown.markdown('foo [[ ]] bar', ['wikilinks']) 226516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru u'<p>foo bar</p>' 236516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 246516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste QueruTo define custom settings the simple way: 256516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 266516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru >>> markdown.markdown(text, 276516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru ... ['wikilinks(base_url=/wiki/,end_url=.html,html_class=foo)'] 286516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru ... ) 296516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru u'<p>Some text with a <a class="foo" href="/wiki/WikiLink.html">WikiLink</a>.</p>' 306516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 316516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste QueruCustom settings the complex way: 326516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 336516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru >>> md = markdown.Markdown( 346516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru ... extensions = ['wikilinks'], 356516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru ... extension_configs = {'wikilinks': [ 366516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru ... ('base_url', 'http://example.com/'), 376516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru ... ('end_url', '.html'), 386516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru ... ('html_class', '') ]}, 396516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru ... safe_mode = True) 406516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru >>> md.convert(text) 416516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru u'<p>Some text with a <a href="http://example.com/WikiLink.html">WikiLink</a>.</p>' 426516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 436516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste QueruUse MetaData with mdx_meta.py (Note the blank html_class in MetaData): 446516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 456516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru >>> text = """wiki_base_url: http://example.com/ 466516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru ... wiki_end_url: .html 476516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru ... wiki_html_class: 486516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru ... 496516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru ... Some text with a [[WikiLink]].""" 506516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru >>> md = markdown.Markdown(extensions=['meta', 'wikilinks']) 516516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru >>> md.convert(text) 526516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru u'<p>Some text with a <a href="http://example.com/WikiLink.html">WikiLink</a>.</p>' 536516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 546516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste QueruMetaData should not carry over to next document: 556516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 566516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru >>> md.convert("No [[MetaData]] here.") 576516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru u'<p>No <a class="wikilink" href="/MetaData/">MetaData</a> here.</p>' 586516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 596516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste QueruDefine a custom URL builder: 606516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 616516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru >>> def my_url_builder(label, base, end): 626516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru ... return '/bar/' 636516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru >>> md = markdown.Markdown(extensions=['wikilinks'], 646516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru ... extension_configs={'wikilinks' : [('build_url', my_url_builder)]}) 656516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru >>> md.convert('[[foo]]') 666516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru u'<p><a class="wikilink" href="/bar/">foo</a></p>' 676516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 686516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste QueruFrom the command line: 696516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 706516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru python markdown.py -x wikilinks(base_url=http://example.com/,end_url=.html,html_class=foo) src.txt 716516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 726516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste QueruBy [Waylan Limberg](http://achinghead.com/). 736516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 746516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste QueruLicense: [BSD](http://www.opensource.org/licenses/bsd-license.php) 756516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 766516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste QueruDependencies: 776516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru* [Python 2.3+](http://python.org) 786516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru* [Markdown 2.0+](http://www.freewisdom.org/projects/python-markdown/) 796516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru''' 806516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 816516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queruimport markdown 826516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queruimport re 836516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 846516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Querudef build_url(label, base, end): 856516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ Build a url from the label, a base, and an end. """ 866516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru clean_label = re.sub(r'([ ]+_)|(_[ ]+)|([ ]+)', '_', label) 876516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru return '%s%s%s'% (base, clean_label, end) 886516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 896516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 906516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queruclass WikiLinkExtension(markdown.Extension): 916516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru def __init__(self, configs): 926516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru # set extension defaults 936516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru self.config = { 946516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 'base_url' : ['/', 'String to append to beginning or URL.'], 956516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 'end_url' : ['/', 'String to append to end of URL.'], 966516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 'html_class' : ['wikilink', 'CSS hook. Leave blank for none.'], 976516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 'build_url' : [build_url, 'Callable formats URL from label.'], 986516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru } 996516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1006516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru # Override defaults with user settings 1016516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru for key, value in configs : 1026516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru self.setConfig(key, value) 1036516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1046516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru def extendMarkdown(self, md, md_globals): 1056516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru self.md = md 1066516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1076516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru # append to end of inline patterns 1086516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru WIKILINK_RE = r'\[\[([A-Za-z0-9_ -]+)\]\]' 1096516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru wikilinkPattern = WikiLinks(WIKILINK_RE, self.config) 1106516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru wikilinkPattern.md = md 1116516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru md.inlinePatterns.add('wikilink', wikilinkPattern, "<not_strong") 1126516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1136516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1146516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queruclass WikiLinks(markdown.inlinepatterns.Pattern): 1156516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru def __init__(self, pattern, config): 1166516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru markdown.inlinepatterns.Pattern.__init__(self, pattern) 1176516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru self.config = config 1186516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1196516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru def handleMatch(self, m): 1206516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if m.group(2).strip(): 1216516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru base_url, end_url, html_class = self._getMeta() 1226516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru label = m.group(2).strip() 1236516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru url = self.config['build_url'][0](label, base_url, end_url) 1246516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru a = markdown.etree.Element('a') 1256516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru a.text = label 1266516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru a.set('href', url) 1276516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if html_class: 1286516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru a.set('class', html_class) 1296516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru else: 1306516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru a = '' 1316516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru return a 1326516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1336516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru def _getMeta(self): 1346516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ Return meta data or config data. """ 1356516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru base_url = self.config['base_url'][0] 1366516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru end_url = self.config['end_url'][0] 1376516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru html_class = self.config['html_class'][0] 1386516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if hasattr(self.md, 'Meta'): 1396516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if self.md.Meta.has_key('wiki_base_url'): 1406516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru base_url = self.md.Meta['wiki_base_url'][0] 1416516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if self.md.Meta.has_key('wiki_end_url'): 1426516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru end_url = self.md.Meta['wiki_end_url'][0] 1436516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if self.md.Meta.has_key('wiki_html_class'): 1446516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru html_class = self.md.Meta['wiki_html_class'][0] 1456516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru return base_url, end_url, html_class 1466516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1476516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1486516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Querudef makeExtension(configs=None) : 1496516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru return WikiLinkExtension(configs=configs) 1506516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1516516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1526516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queruif __name__ == "__main__": 1536516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru import doctest 1546516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru doctest.testmod() 1556516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 156