Show More
@@ -38,6 +38,7 b' import string' | |||||
38 | import hashlib |
|
38 | import hashlib | |
39 | import pygments |
|
39 | import pygments | |
40 | import itertools |
|
40 | import itertools | |
|
41 | import fnmatch | |||
41 |
|
42 | |||
42 | from datetime import datetime |
|
43 | from datetime import datetime | |
43 | from functools import partial |
|
44 | from functools import partial | |
@@ -1811,27 +1812,15 b' def urlify_commit_message(commit_text, r' | |||||
1811 | return literal(newtext) |
|
1812 | return literal(newtext) | |
1812 |
|
1813 | |||
1813 |
|
1814 | |||
1814 | def rst(source, mentions=False): |
|
|||
1815 | return literal('<div class="rst-block">%s</div>' % |
|
|||
1816 | MarkupRenderer.rst(source, mentions=mentions)) |
|
|||
1817 |
|
||||
1818 |
|
||||
1819 | def markdown(source, mentions=False): |
|
|||
1820 | return literal('<div class="markdown-block">%s</div>' % |
|
|||
1821 | MarkupRenderer.markdown(source, flavored=True, |
|
|||
1822 | mentions=mentions)) |
|
|||
1823 |
|
||||
1824 |
|
||||
1825 | def renderer_from_filename(filename, exclude=None): |
|
1815 | def renderer_from_filename(filename, exclude=None): | |
1826 | """ |
|
1816 | """ | |
1827 | choose a renderer based on filename |
|
1817 | choose a renderer based on filename | |
1828 | """ |
|
1818 | """ | |
1829 |
|
1819 | |||
1830 | # images |
|
|||
1831 |
|
||||
1832 | # ipython |
|
1820 | # ipython | |
1833 | if filename.endswith('.ipynb'): |
|
1821 | for ext in ['*.ipynb']: | |
1834 | return 'ipython' |
|
1822 | if fnmatch.fnmatch(filename, pat=ext): | |
|
1823 | return 'jupyter' | |||
1835 |
|
1824 | |||
1836 | is_markup = MarkupRenderer.renderer_from_filename(filename, exclude=exclude) |
|
1825 | is_markup = MarkupRenderer.renderer_from_filename(filename, exclude=exclude) | |
1837 | if is_markup: |
|
1826 | if is_markup: | |
@@ -1841,26 +1830,18 b' def renderer_from_filename(filename, exc' | |||||
1841 |
|
1830 | |||
1842 | def render(source, renderer='rst', mentions=False): |
|
1831 | def render(source, renderer='rst', mentions=False): | |
1843 | if renderer == 'rst': |
|
1832 | if renderer == 'rst': | |
1844 | return rst(source, mentions=mentions) |
|
1833 | return literal( | |
|
1834 | '<div class="rst-block">%s</div>' % | |||
|
1835 | MarkupRenderer.rst(source, mentions=mentions)) | |||
1845 | elif renderer == 'markdown': |
|
1836 | elif renderer == 'markdown': | |
1846 | return markdown(source, mentions=mentions) |
|
1837 | return literal( | |
1847 | elif renderer == 'ipython': |
|
1838 | '<div class="markdown-block">%s</div>' % | |
1848 | def ipython_renderer(source): |
|
1839 | MarkupRenderer.markdown(source, flavored=True, mentions=mentions)) | |
1849 | import nbformat |
|
1840 | elif renderer == 'jupyter': | |
1850 | from nbconvert import HTMLExporter |
|
1841 | return literal( | |
1851 | notebook = nbformat.reads(source, as_version=4) |
|
1842 | '<div class="ipynb">%s</div>' % | |
|
1843 | MarkupRenderer.jupyter(source)) | |||
1852 |
|
1844 | |||
1853 | # 2. Instantiate the exporter. We use the `basic` template for now; we'll get into more details |
|
|||
1854 | # later about how to customize the exporter further. |
|
|||
1855 | html_exporter = HTMLExporter() |
|
|||
1856 | html_exporter.template_file = 'basic' |
|
|||
1857 |
|
||||
1858 | # 3. Process the notebook we loaded earlier |
|
|||
1859 | (body, resources) = html_exporter.from_notebook_node(notebook) |
|
|||
1860 |
|
||||
1861 | return body |
|
|||
1862 |
|
||||
1863 | return ipython_renderer(source) |
|
|||
1864 | # None means just show the file-source |
|
1845 | # None means just show the file-source | |
1865 | return None |
|
1846 | return None | |
1866 |
|
1847 |
@@ -29,6 +29,7 b' import logging' | |||||
29 | import itertools |
|
29 | import itertools | |
30 |
|
30 | |||
31 | from mako.lookup import TemplateLookup |
|
31 | from mako.lookup import TemplateLookup | |
|
32 | from mako.template import Template as MakoTemplate | |||
32 |
|
33 | |||
33 | from docutils.core import publish_parts |
|
34 | from docutils.core import publish_parts | |
34 | from docutils.parsers.rst import directives |
|
35 | from docutils.parsers.rst import directives | |
@@ -49,6 +50,7 b' class MarkupRenderer(object):' | |||||
49 |
|
50 | |||
50 | MARKDOWN_PAT = re.compile(r'\.(md|mkdn?|mdown|markdown)$', re.IGNORECASE) |
|
51 | MARKDOWN_PAT = re.compile(r'\.(md|mkdn?|mdown|markdown)$', re.IGNORECASE) | |
51 | RST_PAT = re.compile(r'\.re?st$', re.IGNORECASE) |
|
52 | RST_PAT = re.compile(r'\.re?st$', re.IGNORECASE) | |
|
53 | JUPYTER_PAT = re.compile(r'\.(ipynb)$', re.IGNORECASE) | |||
52 | PLAIN_PAT = re.compile(r'^readme$', re.IGNORECASE) |
|
54 | PLAIN_PAT = re.compile(r'^readme$', re.IGNORECASE) | |
53 |
|
55 | |||
54 | extensions = ['codehilite', 'extra', 'def_list', 'sane_lists'] |
|
56 | extensions = ['codehilite', 'extra', 'def_list', 'sane_lists'] | |
@@ -95,6 +97,8 b' class MarkupRenderer(object):' | |||||
95 | detected_renderer = 'markdown' |
|
97 | detected_renderer = 'markdown' | |
96 | elif MarkupRenderer.RST_PAT.findall(filename): |
|
98 | elif MarkupRenderer.RST_PAT.findall(filename): | |
97 | detected_renderer = 'rst' |
|
99 | detected_renderer = 'rst' | |
|
100 | elif MarkupRenderer.JUPYTER_PAT.findall(filename): | |||
|
101 | detected_renderer = 'jupyter' | |||
98 | elif MarkupRenderer.PLAIN_PAT.findall(filename): |
|
102 | elif MarkupRenderer.PLAIN_PAT.findall(filename): | |
99 | detected_renderer = 'plain' |
|
103 | detected_renderer = 'plain' | |
100 | else: |
|
104 | else: | |
@@ -263,6 +267,78 b' class MarkupRenderer(object):' | |||||
263 | else: |
|
267 | else: | |
264 | raise |
|
268 | raise | |
265 |
|
269 | |||
|
270 | @classmethod | |||
|
271 | def jupyter(cls, source): | |||
|
272 | from rhodecode.lib import helpers | |||
|
273 | import nbformat | |||
|
274 | from nbconvert import HTMLExporter | |||
|
275 | from traitlets.config import Config | |||
|
276 | ||||
|
277 | class CustomHTMLExporter(HTMLExporter): | |||
|
278 | def _template_file_default(self): | |||
|
279 | return 'basic' | |||
|
280 | ||||
|
281 | def _sanitize_resources(resources): | |||
|
282 | """ | |||
|
283 | Skip/sanitize some of the CSS generated and included in jupyter | |||
|
284 | so it doesn't messes up UI so much | |||
|
285 | """ | |||
|
286 | ||||
|
287 | # TODO(marcink): probably we should replace this with whole custom | |||
|
288 | # CSS set that doesn't screw up, but jupyter generated html has some | |||
|
289 | # special markers, so it requires Custom HTML exporter template with | |||
|
290 | # _default_template_path_default, to achieve that | |||
|
291 | ||||
|
292 | # strip the reset CSS | |||
|
293 | resources[0] = resources[0][resources[0].find('/*! Source'):] | |||
|
294 | return resources | |||
|
295 | ||||
|
296 | def as_html(notebook): | |||
|
297 | conf = Config() | |||
|
298 | html_exporter = CustomHTMLExporter(config=conf) | |||
|
299 | ||||
|
300 | (body, resources) = html_exporter.from_notebook_node(notebook) | |||
|
301 | header = '<!-- ## IPYTHON NOTEBOOK RENDERING ## -->' | |||
|
302 | js = MakoTemplate(r''' | |||
|
303 | <!-- Load mathjax --> | |||
|
304 | <!-- MathJax configuration --> | |||
|
305 | <script type="text/x-mathjax-config"> | |||
|
306 | MathJax.Hub.Config({ | |||
|
307 | jax: ["input/TeX","output/HTML-CSS", "output/PreviewHTML"], | |||
|
308 | extensions: ["tex2jax.js","MathMenu.js","MathZoom.js", "fast-preview.js", "AssistiveMML.js", "[Contrib]/a11y/accessibility-menu.js"], | |||
|
309 | TeX: { | |||
|
310 | extensions: ["AMSmath.js","AMSsymbols.js","noErrors.js","noUndefined.js"] | |||
|
311 | }, | |||
|
312 | tex2jax: { | |||
|
313 | inlineMath: [ ['$','$'], ["\\(","\\)"] ], | |||
|
314 | displayMath: [ ['$$','$$'], ["\\[","\\]"] ], | |||
|
315 | processEscapes: true, | |||
|
316 | processEnvironments: true | |||
|
317 | }, | |||
|
318 | // Center justify equations in code and markdown cells. Elsewhere | |||
|
319 | // we use CSS to left justify single line equations in code cells. | |||
|
320 | displayAlign: 'center', | |||
|
321 | "HTML-CSS": { | |||
|
322 | styles: {'.MathJax_Display': {"margin": 0}}, | |||
|
323 | linebreaks: { automatic: true } | |||
|
324 | }, | |||
|
325 | showMathMenu: false | |||
|
326 | }); | |||
|
327 | </script> | |||
|
328 | <!-- End of mathjax configuration --> | |||
|
329 | <script src="${h.asset('js/src/math_jax/MathJax.js')}"></script> | |||
|
330 | ''').render(h=helpers) | |||
|
331 | ||||
|
332 | css = '<style>{}</style>'.format( | |||
|
333 | ''.join(_sanitize_resources(resources['inlining']['css']))) | |||
|
334 | ||||
|
335 | body = '\n'.join([header, css, js, body]) | |||
|
336 | return body, resources | |||
|
337 | ||||
|
338 | notebook = nbformat.reads(source, as_version=4) | |||
|
339 | (body, resources) = as_html(notebook) | |||
|
340 | return body | |||
|
341 | ||||
266 |
|
342 | |||
267 | class RstTemplateRenderer(object): |
|
343 | class RstTemplateRenderer(object): | |
268 |
|
344 |
General Comments 0
You need to be logged in to leave comments.
Login now