1# -*- coding: utf8 -*- 2# 3# Copyright (c) 2006-2021 Andrey Golovizin 4# Copyright (c) 2014 Jorrit Wronski 5# 6# Permission is hereby granted, free of charge, to any person obtaining 7# a copy of this software and associated documentation files (the 8# "Software"), to deal in the Software without restriction, including 9# without limitation the rights to use, copy, modify, merge, publish, 10# distribute, sublicense, and/or sell copies of the Software, and to 11# permit persons to whom the Software is furnished to do so, subject to 12# the following conditions: 13# 14# The above copyright notice and this permission notice shall be 15# included in all copies or substantial portions of the Software. 16# 17# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25 26r""" 27Markdown output backend. 28 29>>> from pybtex.richtext import Tag, HRef 30>>> markdown = Backend() 31>>> print(Tag('em', '').render(markdown)) 32<BLANKLINE> 33>>> print(Tag('em', 'Non-', 'empty').render(markdown)) 34*Non\-empty* 35>>> print(Tag('sup', 'super', 'man').render(markdown)) 36<sup>superman</sup> 37>>> print(HRef('/', '').render(markdown)) 38<BLANKLINE> 39>>> print(HRef('/', 'Non-', 'empty').render(markdown)) 40[Non\-empty](/) 41""" 42from __future__ import unicode_literals 43 44from xml.sax.saxutils import escape 45 46from pybtex.backends import BaseBackend 47 48SPECIAL_CHARS = [ 49 u'\\', # backslash 50 u'`', # backtick 51 u'*', # asterisk 52 u'_', # underscore 53 u'{', # curly braces 54 u'}', # curly braces 55 u'[', # square brackets 56 u']', # square brackets 57 u'(', # parentheses 58 u')', # parentheses 59 u'#', # hash mark 60 u'+', # plus sign 61 u'-', # minus sign (hyphen) 62 u'.', # dot 63 u'!', # exclamation mark 64] 65 66 67class Backend(BaseBackend): 68 u""" A backend to support markdown output. It implements the same 69 features as the HTML backend. 70 71 In addition to that, you can use the keyword php_extra=True to enable 72 the definition list extension of php-markdown. The default is not to use 73 it, since we cannot be sure that this feature is implemented on all 74 systems. 75 76 More information: 77 http://www.michelf.com/projects/php-markdown/extra/#def-list 78 79 """ 80 81 def __init__(self, encoding=None, php_extra=False): 82 super(Backend, self).__init__(encoding=encoding) 83 self.php_extra = php_extra 84 85 default_suffix = '.md' 86 symbols = { 87 'ndash': u'–',# or 'ndash': u'–', 88 'newblock': u'\n', 89 'nbsp': u' ' 90 } 91 tags = { 92 'em' : u'*', # emphasize text 93 'strong': u'**', # emphasize text even more 94 'i' : u'*', # italicize text: be careful, i is not semantic 95 'b' : u'**', # embolden text: be careful, b is not semantic 96 'tt' : u'`', # make text appear as code (typically typewriter text), a little hacky 97 } 98 99 def format_str(self, text): 100 """Format the given string *str_*. 101 Escapes special markdown control characters. 102 """ 103 text = escape(text) 104 for special_char in SPECIAL_CHARS: 105 text = text.replace(special_char, u'\\' + special_char) 106 return text 107 108 def format_tag(self, tag_name, text): 109 tag = self.tags.get(tag_name) 110 if tag is None: # fall back on html tags 111 return r'<{0}>{1}</{0}>'.format(tag_name, text) if text else u'' 112 else: 113 return r'{0}{1}{0}'.format(tag, text) if text else u'' 114 115 def format_href(self, url, text): 116 return r'[%s](%s)' % (text, url) if text else u'' 117 118 def write_entry(self, key, label, text): 119 # Support http://www.michelf.com/projects/php-markdown/extra/#def-list 120 if self.php_extra: 121 self.output(u'%s\n' % label) 122 self.output(u': %s\n\n' % text) 123 else: 124 self.output(u'[%s] ' % label) 125 self.output(u'%s \n' % text) 126