Browse Source

fix #661: [code] bbcode

Rafał Pitoń 8 years ago
parent
commit
bd4dc05d33
3 changed files with 132 additions and 2 deletions
  1. 16 0
      misago/markup/bbcode/blocks.py
  2. 7 0
      misago/markup/parser.py
  3. 109 2
      misago/markup/tests/test_parser.py

+ 16 - 0
misago/markup/bbcode/blocks.py

@@ -4,6 +4,7 @@ import re
 
 
 import markdown
 import markdown
 from markdown.blockprocessors import BlockProcessor, HRProcessor
 from markdown.blockprocessors import BlockProcessor, HRProcessor
+from markdown.extensions.fenced_code import FencedBlockPreprocessor
 from markdown.preprocessors import Preprocessor
 from markdown.preprocessors import Preprocessor
 from markdown.util import etree
 from markdown.util import etree
 
 
@@ -99,3 +100,18 @@ class QuoteBlockProcessor(BlockProcessor):
                 heading.text = title
                 heading.text = title
 
 
             self.parser.parseBlocks(blockquote, children)
             self.parser.parseBlocks(blockquote, children)
+
+
+class CodeBlockExtension(markdown.Extension):
+    def extendMarkdown(self, md):
+        md.registerExtension(self)
+
+        md.preprocessors.add('misago_code_bbcode',
+                             CodeBlockPreprocessor(md),
+                             ">normalize_whitespace")
+
+
+class CodeBlockPreprocessor(FencedBlockPreprocessor):
+        FENCED_BLOCK_RE = re.compile(r'''
+\[code(=("?)(?P<lang>.*?)("?))?](([ ]*\n)+)?(?P<code>.*?)((\s|\n)+)?\[/code\]
+''', re.IGNORECASE | re.MULTILINE | re.DOTALL | re.VERBOSE)

+ 7 - 0
misago/markup/parser.py

@@ -8,6 +8,7 @@ from htmlmin.minify import html_minify
 from django.http import Http404
 from django.http import Http404
 from django.urls import resolve
 from django.urls import resolve
 from django.utils import six
 from django.utils import six
+from markdown.extensions.fenced_code import FencedCodeExtension
 
 
 from .bbcode import blocks, inline
 from .bbcode import blocks, inline
 from .md.shortimgs import ShortImagesExtension
 from .md.shortimgs import ShortImagesExtension
@@ -111,6 +112,12 @@ def md_factory(allow_links=True, allow_images=True, allow_blocks=True):
         # Add [hr] and [quote] blocks
         # Add [hr] and [quote] blocks
         md.parser.blockprocessors.add('bb_hr', blocks.BBCodeHRProcessor(md.parser), '>hr')
         md.parser.blockprocessors.add('bb_hr', blocks.BBCodeHRProcessor(md.parser), '>hr')
 
 
+        fenced_code = FencedCodeExtension()
+        fenced_code.extendMarkdown(md, None)
+
+        code_bbcode = blocks.CodeBlockExtension()
+        code_bbcode.extendMarkdown(md)
+
         quote_bbcode = blocks.QuoteExtension()
         quote_bbcode = blocks.QuoteExtension()
         quote_bbcode.extendMarkdown(md)
         quote_bbcode.extendMarkdown(md)
     else:
     else:

+ 109 - 2
misago/markup/tests/test_parser.py

@@ -57,8 +57,8 @@ Lorem [b]ipsum[/B].
         result = parse(test_text, MockRequest(), MockPoster(), minify=False)
         result = parse(test_text, MockRequest(), MockPoster(), minify=False)
         self.assertEqual(expected_result, result['parsed_text'])
         self.assertEqual(expected_result, result['parsed_text'])
 
 
-    def test_blocks(self):
-        """block elements are correctly parsed"""
+    def test_hr(self):
+        """hr bbcode is correctly parsed"""
         test_text = """
         test_text = """
 Lorem ipsum.
 Lorem ipsum.
 [hr]
 [hr]
@@ -397,3 +397,110 @@ Amet elit
 
 
         result = parse(test_text, MockRequest(), MockPoster(), minify=False)
         result = parse(test_text, MockRequest(), MockPoster(), minify=False)
         self.assertEqual(expected_result, result['parsed_text'])
         self.assertEqual(expected_result, result['parsed_text'])
+
+
+class CodeTests(TestCase):
+    def test_code(self):
+        """code bbcode is correctly parsed"""
+        test_text = """
+Lorem ipsum.
+[code]
+Dolor [b]met.[/b]
+[/code]
+""".strip()
+
+        expected_result = """
+<p>Lorem ipsum.</p>
+<pre><code>Dolor [b]met.[/b]</code></pre>
+""".strip()
+
+        result = parse(test_text, MockRequest(), MockPoster(), minify=False)
+        self.assertEqual(expected_result, result['parsed_text'])
+
+    def test_inline_code(self):
+        """inline code bbcode is correctly parsed"""
+        test_text = """
+Lorem ipsum.
+
+[code]Dolor [b]met.[/b][/code]
+""".strip()
+
+        expected_result = """
+<p>Lorem ipsum.</p>
+<pre><code>Dolor [b]met.[/b]</code></pre>
+""".strip()
+
+        result = parse(test_text, MockRequest(), MockPoster(), minify=False)
+        self.assertEqual(expected_result, result['parsed_text'])
+
+    def test_code_strip(self):
+        """code bbcode trims its content"""
+        test_text = """
+Lorem ipsum.
+
+[code]
+
+   Dolor [b]met.[/b]
+
+
+[/code]
+""".strip()
+
+        expected_result = """
+<p>Lorem ipsum.</p>
+<pre><code>   Dolor [b]met.[/b]</code></pre>
+""".strip()
+        result = parse(test_text, MockRequest(), MockPoster(), minify=False)
+        self.assertEqual(expected_result, result['parsed_text'])
+
+    def test_code_language(self):
+        """code bbcode with language is correctly parsed"""
+        test_text = """
+Lorem ipsum.
+
+[code="python"]
+Dolor [b]met.[/b]
+[/code]
+""".strip()
+
+        expected_result = """
+<p>Lorem ipsum.</p>
+<pre><code class="python">Dolor [b]met.[/b]</code></pre>
+""".strip()
+
+        result = parse(test_text, MockRequest(), MockPoster(), minify=False)
+        self.assertEqual(expected_result, result['parsed_text'])
+
+    def test_code_language_optional_quotes(self):
+        """code quotes around language name are optional"""
+        test_text = """
+Lorem ipsum.
+
+[code=python"]
+Dolor [b]met.[/b]
+[/code]
+""".strip()
+
+        expected_result = """
+<p>Lorem ipsum.</p>
+<pre><code class="python">Dolor [b]met.[/b]</code></pre>
+""".strip()
+
+        result = parse(test_text, MockRequest(), MockPoster(), minify=False)
+        self.assertEqual(expected_result, result['parsed_text'])
+
+        test_text = """
+Lorem ipsum.
+
+[code="python]
+Dolor [b]met.[/b]
+[/code]
+""".strip()
+
+        expected_result = """
+<p>Lorem ipsum.</p>
+<pre><code class="python">Dolor [b]met.[/b]</code></pre>
+""".strip()
+
+        result = parse(test_text, MockRequest(), MockPoster(), minify=False)
+        self.assertEqual(expected_result, result['parsed_text'])