Show More
@@ -0,0 +1,129 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """ | |||
|
3 | rhodecode.lib.markup_renderer | |||
|
4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |||
|
5 | ||||
|
6 | ||||
|
7 | Renderer for markup languages with ability to parse using rst or markdown | |||
|
8 | ||||
|
9 | :created_on: Oct 27, 2011 | |||
|
10 | :author: marcink | |||
|
11 | :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com> | |||
|
12 | :license: GPLv3, see COPYING for more details. | |||
|
13 | """ | |||
|
14 | # This program is free software: you can redistribute it and/or modify | |||
|
15 | # it under the terms of the GNU General Public License as published by | |||
|
16 | # the Free Software Foundation, either version 3 of the License, or | |||
|
17 | # (at your option) any later version. | |||
|
18 | # | |||
|
19 | # This program is distributed in the hope that it will be useful, | |||
|
20 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
21 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
22 | # GNU General Public License for more details. | |||
|
23 | # | |||
|
24 | # You should have received a copy of the GNU General Public License | |||
|
25 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
26 | ||||
|
27 | import re | |||
|
28 | import logging | |||
|
29 | ||||
|
30 | from rhodecode.lib import safe_unicode | |||
|
31 | ||||
|
32 | log = logging.getLogger(__name__) | |||
|
33 | ||||
|
34 | class MarkupRenderer(object): | |||
|
35 | RESTRUCTUREDTEXT_DISALLOWED_DIRECTIVES = ['include', 'meta', 'raw'] | |||
|
36 | ||||
|
37 | MARKDOWN_PAT = re.compile(r'md|mkdn?|mdown|markdown',re.IGNORECASE) | |||
|
38 | RST_PAT = re.compile(r're?st',re.IGNORECASE) | |||
|
39 | PLAIN_PAT = re.compile(r'readme',re.IGNORECASE) | |||
|
40 | ||||
|
41 | def __detect_renderer(self, source, filename=None): | |||
|
42 | """ | |||
|
43 | runs detection of what renderer should be used for generating html | |||
|
44 | from a markup language | |||
|
45 | ||||
|
46 | filename can be also explicitly a renderer name | |||
|
47 | ||||
|
48 | :param source: | |||
|
49 | :param filename: | |||
|
50 | """ | |||
|
51 | ||||
|
52 | if MarkupRenderer.MARKDOWN_PAT.findall(filename): | |||
|
53 | detected_renderer = 'markdown' | |||
|
54 | elif MarkupRenderer.RST_PAT.findall(filename): | |||
|
55 | detected_renderer = 'rst' | |||
|
56 | elif MarkupRenderer.PLAIN_PAT.findall(filename): | |||
|
57 | detected_renderer = 'rst' | |||
|
58 | else: | |||
|
59 | detected_renderer = 'plain' | |||
|
60 | ||||
|
61 | return getattr(MarkupRenderer, detected_renderer) | |||
|
62 | ||||
|
63 | ||||
|
64 | def render(self, source, filename=None): | |||
|
65 | """ | |||
|
66 | Renders a given filename using detected renderer | |||
|
67 | it detects renderers based on file extension or mimetype. | |||
|
68 | At last it will just do a simple html replacing new lines with <br/> | |||
|
69 | ||||
|
70 | :param file_name: | |||
|
71 | :param source: | |||
|
72 | """ | |||
|
73 | ||||
|
74 | renderer = self.__detect_renderer(source, filename) | |||
|
75 | readme_data = renderer(source) | |||
|
76 | return readme_data | |||
|
77 | ||||
|
78 | @classmethod | |||
|
79 | def plain(cls, source): | |||
|
80 | source = safe_unicode(source) | |||
|
81 | def urlify_text(text): | |||
|
82 | url_pat = re.compile(r'(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]' | |||
|
83 | '|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)') | |||
|
84 | ||||
|
85 | def url_func(match_obj): | |||
|
86 | url_full = match_obj.groups()[0] | |||
|
87 | return '<a href="%(url)s">%(url)s</a>' % ({'url':url_full}) | |||
|
88 | ||||
|
89 | return url_pat.sub(url_func, text) | |||
|
90 | ||||
|
91 | source = urlify_text(source) | |||
|
92 | return '<br />' + source.replace("\n", '<br />') | |||
|
93 | ||||
|
94 | ||||
|
95 | @classmethod | |||
|
96 | def markdown(cls, source): | |||
|
97 | source = safe_unicode(source) | |||
|
98 | try: | |||
|
99 | import markdown as __markdown | |||
|
100 | return __markdown.markdown(source) | |||
|
101 | except ImportError: | |||
|
102 | log.warning('Install markdown to use this function') | |||
|
103 | return cls.plain(source) | |||
|
104 | ||||
|
105 | ||||
|
106 | @classmethod | |||
|
107 | def rst(cls, source): | |||
|
108 | source = safe_unicode(source) | |||
|
109 | try: | |||
|
110 | from docutils.core import publish_parts | |||
|
111 | from docutils.parsers.rst import directives | |||
|
112 | docutils_settings = dict([(alias, None) for alias in | |||
|
113 | cls.RESTRUCTUREDTEXT_DISALLOWED_DIRECTIVES]) | |||
|
114 | ||||
|
115 | docutils_settings.update({'input_encoding': 'unicode', | |||
|
116 | 'report_level':4}) | |||
|
117 | ||||
|
118 | for k, v in docutils_settings.iteritems(): | |||
|
119 | directives.register_directive(k, v) | |||
|
120 | ||||
|
121 | parts = publish_parts(source=source, | |||
|
122 | writer_name="html4css1", | |||
|
123 | settings_overrides=docutils_settings) | |||
|
124 | ||||
|
125 | return parts['html_title'] + parts["fragment"] | |||
|
126 | except ImportError: | |||
|
127 | log.warning('Install docutils to use this function') | |||
|
128 | return cls.plain(source) | |||
|
129 |
General Comments 0
You need to be logged in to leave comments.
Login now