Переглянути джерело

Merge pull request #283 from isms/liquid-notebook-language

[liquid_tags:notebook] Add language highlighting option
Justin Mayer 10 роки тому
батько
коміт
50f426bdbf
3 змінених файлів з 128 додано та 6 видалено
  1. 28 3
      liquid_tags/Readme.md
  2. 8 3
      liquid_tags/notebook.py
  3. 92 0
      liquid_tags/test_notebook.py

+ 28 - 3
liquid_tags/Readme.md

@@ -74,7 +74,7 @@ filename.
 The script must be in the ``code`` subdirectory of your content folder:
 this default location can be changed by specifying
 
-   CODE_DIR = 'code'
+    CODE_DIR = 'code'
 
 within your configuration file. Additionally, in order for the resulting
 hyperlink to work, this directory must be listed under the STATIC_PATHS
@@ -97,7 +97,7 @@ config file:
 Because the conversion and rendering of notebooks is rather involved, there
 are a few extra steps required for this plugin:
 
-- First, you will need to install IPython >= 1.0 [1]_
+- First, you will need to install IPython >= 1.0 [[1](#1)]
 
 - After typing "make html" when using the notebook tag, a file called
   ``_nb_header.html`` will be produced in the main directory.  The content
@@ -115,6 +115,31 @@ are a few extra steps required for this plugin:
 
   this will insert the proper css formatting into your document.
 
+### Optional Arguments for Notebook Tags
+
+The notebook tag also has two optional arguments: ``cells`` and ``language``.
+
+- You can specify a slice of cells to include:
+
+  ``{% notebook filename.ipynb cells[2:8] %}``
+
+- You can also specify the name of a language which Pygments should use for
+  highlighting code cells. A list of the short names for languages that Pygments
+  will highlight can be found [here](http://www.pygments.org/docs/lexers/).
+
+  ``{% notebook filename.ipynb language[julia] %}``
+
+  This may be helpful for those using [IJulia](https://github.com/JuliaLang/IJulia.jl)
+  or notebooks in any other language, especially as the IPython project [broadens its
+  scope](https://github.com/ipython/ipython/wiki/Roadmap:-IPython) of [language
+  compatibility](http://jupyter.org/). By default, the language for highlighting
+  will be ``ipython``.
+
+- These options can be used separately, together, or not at all. However,
+  if both tags are used then ``cells`` must come before ``language``:
+
+  ``{% notebook filename.ipynb cells[2:8] language[julia] %}``
+
 ### Collapsible Code in IPython Notebooks
 
 The plugin also enables collapsible code input boxes. For this to work
@@ -127,4 +152,4 @@ comment line ``# <!-- collapse=False -->`` will be open on load but
 can be collapsed by clicking on their header. Cells without collapse
 comments are rendered as standard code input cells.
 
-[1] http://ipython.org/
+[<a name="1">1</a>] http://ipython.org/

+ 8 - 3
liquid_tags/notebook.py

@@ -46,6 +46,8 @@ still be some conflicts.
 """
 import re
 import os
+from functools import partial
+
 from .mdx_liquid_tags import LiquidTags
 
 from distutils.version import LooseVersion
@@ -230,8 +232,8 @@ def custom_highlighter(source, language='ipython', metadata=None):
 #----------------------------------------------------------------------
 # Below is the pelican plugin code.
 #
-SYNTAX = "{% notebook /path/to/notebook.ipynb [ cells[start:end] ] %}"
-FORMAT = re.compile(r"""^(\s+)?(?P<src>\S+)(\s+)?((cells\[)(?P<start>-?[0-9]*):(?P<end>-?[0-9]*)(\]))?(\s+)?$""")
+SYNTAX = "{% notebook /path/to/notebook.ipynb [ cells[start:end] ] [ language[language] ] %}"
+FORMAT = re.compile(r"""^(\s+)?(?P<src>\S+)(\s+)?((cells\[)(?P<start>-?[0-9]*):(?P<end>-?[0-9]*)(\]))?(\s+)?((language\[)(?P<language>-?[a-z0-9\+\-]*)(\]))?(\s+)?$""")
 
 
 @LiquidTags.register('notebook')
@@ -242,6 +244,7 @@ def notebook(preprocessor, tag, markup):
         src = argdict['src']
         start = argdict['start']
         end = argdict['end']
+        language = argdict['language']
     else:
         raise ValueError("Error processing input, "
                          "expected syntax: {0}".format(SYNTAX))
@@ -256,6 +259,8 @@ def notebook(preprocessor, tag, markup):
     else:
         end = None
 
+    language_applied_highlighter = partial(custom_highlighter, language=language)
+
     settings = preprocessor.configs.config['settings']
     nb_dir =  settings.get('NOTEBOOK_DIR', 'notebooks')
     nb_path = os.path.join('content', nb_dir, src)
@@ -284,7 +289,7 @@ def notebook(preprocessor, tag, markup):
     
     exporter = HTMLExporter(config=c,
                             template_file=template_file,
-                            filters={'highlight2html': custom_highlighter},
+                            filters={'highlight2html': language_applied_highlighter},
                             **subcell_kwarg)
 
     # read and parse the notebook

+ 92 - 0
liquid_tags/test_notebook.py

@@ -0,0 +1,92 @@
+import re
+
+from pelican.tests.support import unittest
+
+import notebook
+
+
+class TestNotebookTagRegex(unittest.TestCase):
+
+    def get_argdict(self, markup):
+
+        match = notebook.FORMAT.search(markup)
+
+        if match:
+            argdict = match.groupdict()
+
+            src = argdict['src']
+            start = argdict['start']
+            end = argdict['end']
+            language = argdict['language']
+
+            return src, start, end, language
+
+        return None
+
+    def test_basic_notebook_tag(self):
+        markup = u'path/to/thing.ipynb'
+        src, start, end, language = self.get_argdict(markup)
+
+        self.assertEqual(src, u'path/to/thing.ipynb')
+        self.assertIsNone(start)
+        self.assertIsNone(end)
+        self.assertIsNone(language)
+
+    def test_basic_notebook_tag_insensitive_to_whitespace(self):
+        markup = u'   path/to/thing.ipynb '
+        src, start, end, language = self.get_argdict(markup)
+
+        self.assertEqual(src, u'path/to/thing.ipynb')
+        self.assertIsNone(start)
+        self.assertIsNone(end)
+        self.assertIsNone(language)
+
+    def test_notebook_tag_with_cells(self):
+        markup = u'path/to/thing.ipynb cells[1:5]'
+        src, start, end, language = self.get_argdict(markup)
+
+        self.assertEqual(src, u'path/to/thing.ipynb')
+        self.assertEqual(start, u'1')
+        self.assertEqual(end, u'5')
+        self.assertIsNone(language)
+
+    def test_notebook_tag_with_alphanumeric_language(self):
+        markup = u'path/to/thing.ipynb language[python3]'
+        src, start, end, language = self.get_argdict(markup)
+
+        self.assertEqual(src, u'path/to/thing.ipynb')
+        self.assertIsNone(start)
+        self.assertIsNone(end)
+        self.assertEqual(language, u'python3')
+
+    def test_notebook_tag_with_symbol_in_name_language(self):
+        for short_name in [u'c++', u'cpp-objdump', u'c++-objdumb', u'cxx-objdump']:
+            markup = u'path/to/thing.ipynb language[{}]'.format(short_name)
+            src, start, end, language = self.get_argdict(markup)
+
+            self.assertEqual(src, u'path/to/thing.ipynb')
+            self.assertIsNone(start)
+            self.assertIsNone(end)
+            self.assertEqual(language, short_name)
+
+    def test_notebook_tag_with_language_and_cells(self):
+        markup = u'path/to/thing.ipynb cells[1:5] language[julia]'
+        src, start, end, language = self.get_argdict(markup)
+
+        self.assertEqual(src, u'path/to/thing.ipynb')
+        self.assertEqual(start, u'1')
+        self.assertEqual(end, u'5')
+        self.assertEqual(language, u'julia')
+
+    def test_notebook_tag_with_language_and_cells_and_weird_spaces(self):
+        markup = u'   path/to/thing.ipynb   cells[1:5]  language[julia]       '
+        src, start, end, language = self.get_argdict(markup)
+
+        self.assertEqual(src, u'path/to/thing.ipynb')
+        self.assertEqual(start, u'1')
+        self.assertEqual(end, u'5')
+        self.assertEqual(language, u'julia')
+
+
+if __name__ == '__main__':
+    unittest.main()