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'&ndash;',# 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