Changeset 42
- Timestamp:
- 01/06/08 14:41:54 (8 months ago)
- Files:
-
- bitstructures/trunk/README (modified) (1 diff)
- bitstructures/trunk/css/bitstructures.css (modified) (1 diff)
- bitstructures/trunk/substructure/codeblocks.py (modified) (4 diffs)
- bitstructures/trunk/substructure/templatetags/substructure_tags.py (modified) (2 diffs)
- bitstructures/trunk/substructure/tests.py (modified) (4 diffs)
- bitstructures/trunk/substructure/views.py (modified) (1 diff)
- bitstructures/trunk/templates/substructure/entry.html (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
bitstructures/trunk/README
r25 r42 13 13 Django 0.96 14 14 Python Markdown 1.6a http://www.freewisdom.org/projects/python-markdown/ 15 Pygments 0.9 http://pygments.org/ bitstructures/trunk/css/bitstructures.css
r24 r42 120 120 text-decoration: none; 121 121 } 122 123 pre { 124 background-color: #def; 125 } 126 127 /* rules for Pygments */ 128 129 .highlight .k, .highlight .nb, .highlight .nt { 130 color: #555; 131 font-weight: bold; 132 } bitstructures/trunk/substructure/codeblocks.py
r25 r42 18 18 return self.text 19 19 20 def is_codeblock_header_field(line): 21 if line.is_codeblock_line() and get_field_name(line): 22 return True 23 else: 24 return False 25 26 def get_field_name(header_line): 27 name_value = header_line.get_text_without_indentation() 28 index = name_value.find(':') 29 if index != -1: 30 return name_value[0:index].strip() 31 else: 32 return None 33 34 def get_field_value(header_line): 35 name_value = header_line.get_text_without_indentation() 36 index = name_value.find(':') 37 if index != -1: 38 return name_value[index+1:].strip() 39 else: 40 return None 41 20 42 class MarkdownLineTokeniser: 21 43 def __init__(self, text): 22 44 self._lines = iter(text.splitlines(True)) 23 self. _current_line = None45 self.current_line = None 24 46 self._at_end = False 25 26 def get_current_line(self):27 return self._current_line28 47 29 48 def is_at_end(self): … … 32 51 def read_next(self): 33 52 try: 34 self. _current_line = MarkdownLine(self._lines.next())53 self.current_line = MarkdownLine(self._lines.next()) 35 54 except StopIteration: 36 55 self._at_end = True 37 self._current_line = None 56 self.current_line = None 57 58 class Section: 59 def __init__(self): 60 self.lines = list() 61 62 def get_text(self): 63 return ''.join(line.text for line in self.lines) 64 65 def append(self, line): 66 self.lines.append(line) 67 68 class Codeblock(Section): 69 def __init__(self): 70 Section.__init__(self) 71 self.content_type = None 72 73 def is_codeblock(self): 74 return True 75 76 def get_code(self): 77 return ''.join(line.get_text_without_indentation() for line in self.lines) 78 79 class NonCodeblock(Section): 80 def is_codeblock(self): 81 return False 38 82 39 83 class MarkdownCodeblocksParser: … … 45 89 lines.read_next() 46 90 while not lines.is_at_end(): 47 if lines. get_current_line().is_indented():48 codeblock = self._get_codeblock _text(lines)91 if lines.current_line.is_indented(): 92 codeblock = self._get_codeblock(lines) 49 93 count += 1 50 94 if count == n: … … 53 97 return None 54 98 55 def _get_codeblock_text(self, lines): 56 text = str() 57 while (not lines.is_at_end()) and lines.get_current_line().is_codeblock_line(): 58 text = text + lines.get_current_line().get_text_without_indentation() 99 def parse(self, text): 100 sections = list() 101 lines = MarkdownLineTokeniser(text) 102 lines.read_next() 103 while not lines.is_at_end(): 104 if lines.current_line.is_indented(): 105 sections.append(self._get_codeblock(lines)) 106 else: 107 sections.append(self._get_non_codeblock(lines)) 108 return sections 109 110 def _get_codeblock(self, lines): 111 codeblock = Codeblock() 112 if is_codeblock_header_field(lines.current_line): 113 if get_field_name(lines.current_line) == 'Content-Type': 114 codeblock.content_type = get_field_value(lines.current_line) 59 115 lines.read_next() 60 return text 116 while (not lines.is_at_end()) and lines.current_line.is_codeblock_line(): 117 codeblock.append(lines.current_line) 118 lines.read_next() 119 return codeblock 120 121 def _get_non_codeblock(self, lines): 122 section = NonCodeblock() 123 while (not lines.is_at_end()) and (not lines.current_line.is_indented()): 124 section.append(lines.current_line) 125 lines.read_next() 126 return section bitstructures/trunk/substructure/templatetags/substructure_tags.py
r15 r42 1 1 from django import template 2 2 from django.utils.tzinfo import LocalTimezone 3 from markdown import markdown 4 from pygments import highlight 5 from pygments.lexers import get_lexer_for_mimetype 6 from pygments.formatters import HtmlFormatter 7 from bitstructures.substructure.codeblocks import MarkdownCodeblocksParser 3 8 4 9 def rfc3339(dt): … … 9 14 return dt_out.isoformat() 10 15 16 def syntax_highlighted_markdown(markdown_text): 17 parser = MarkdownCodeblocksParser() 18 formatter = HtmlFormatter() 19 sections = parser.parse(markdown_text) 20 for_markdown = list() 21 html = list() 22 for section in sections: 23 if section.is_codeblock() and section.content_type: 24 # run Markdown on any text that isn't to be syntax highlighted 25 if for_markdown: 26 html.append(markdown(''.join(for_markdown))) 27 for_markdown = list() 28 # run Pygments on code to be syntax highlighted 29 html.append(highlight(section.get_code(), 30 get_lexer_for_mimetype(section.content_type), formatter)) 31 else: 32 for_markdown.append(section.get_text()) 33 # run Markdown on any remaining text that isn't to be syntax highlighted 34 if for_markdown: 35 html.append(markdown(''.join(for_markdown))) 36 return ''.join(html) 37 11 38 register = template.Library() 12 register.filter("rfc3339", rfc3339) 39 register.filter('rfc3339', rfc3339) 40 register.filter('syntax_highlighted_markdown', syntax_highlighted_markdown) bitstructures/trunk/substructure/tests.py
r25 r42 1 from bitstructures.substructure.codeblocks import MarkdownLine, MarkdownCodeblocksParser 1 from bitstructures.substructure.codeblocks import MarkdownLine, MarkdownCodeblocksParser, is_codeblock_header_field, get_field_name, get_field_value 2 2 import unittest 3 3 4 4 class MarkdownLineTest(unittest.TestCase): 5 def setUp(self): 6 self.empty = MarkdownLine('') 7 self.foo_bar = MarkdownLine(' foo:bar') 8 self.foo_bar_spaces = MarkdownLine(' foo : bar') 9 self.foo_bar_newline = MarkdownLine(' foo:bar\n') 10 5 11 def test_is_blank(self): 6 self.assert_( MarkdownLine('').is_blank())12 self.assert_(self.empty.is_blank()) 7 13 self.assert_(MarkdownLine(' ').is_blank()) 8 14 self.assert_(MarkdownLine('\t').is_blank()) … … 14 20 self.assert_(MarkdownLine(' code').is_indented()) 15 21 self.assert_(MarkdownLine(' code').is_indented()) 22 23 def test_codeblock_header_field(self): 24 self.assert_(not is_codeblock_header_field(self.empty)) 25 self.assert_(not is_codeblock_header_field(MarkdownLine('foo'))) 26 self.assert_(not is_codeblock_header_field(MarkdownLine('foo:bar'))) 27 self.assert_(not is_codeblock_header_field(MarkdownLine(' foo'))) 28 self.assert_(not is_codeblock_header_field(MarkdownLine(' :'))) 29 self.assert_(not is_codeblock_header_field(MarkdownLine(' :foo'))) 30 self.assert_(is_codeblock_header_field(self.foo_bar)) 31 self.assertEqual('foo', get_field_name(self.foo_bar)) 32 self.assertEqual('bar', get_field_value(self.foo_bar)) 33 self.assert_(is_codeblock_header_field(self.foo_bar_spaces)) 34 self.assertEqual('foo', get_field_name(self.foo_bar_spaces)) 35 self.assertEqual('bar', get_field_value(self.foo_bar_spaces)) 36 self.assert_(is_codeblock_header_field(self.foo_bar_newline)) 37 self.assertEqual('foo', get_field_name(self.foo_bar_newline)) 38 self.assertEqual('bar', get_field_value(self.foo_bar_newline)) 16 39 17 40 class MarkdownCodeblocksParserTest(unittest.TestCase): … … 33 56 text 34 57 code2''' 58 self.with_content_type = ''' Content-Type: text/x-python 59 line2''' 35 60 36 61 def test_get_codeblock_on_empty(self): … … 52 77 53 78 def test_get_codeblock(self): 54 self.assertEqual('foo', self.parser.get_codeblock(' foo', 1)) 79 self.assertEqual(' foo', self.parser.get_codeblock(' foo', 1).get_text()) 80 self.assertEqual('foo', self.parser.get_codeblock(' foo', 1).get_code()) 81 self.assertEqual(self.two_line, 82 self.parser.get_codeblock(self.two_line, 1).get_text()) 55 83 expect_twoline = '''line1 56 84 line2''' 57 85 self.assertEqual(expect_twoline, 58 self.parser.get_codeblock(self.two_line, 1)) 86 self.parser.get_codeblock(self.two_line, 1).get_code()) 87 self.assertEqual(' code\n\n', 88 self.parser.get_codeblock(self.text_code_text, 1).get_text()) 59 89 self.assertEqual('code\n\n', 60 self.parser.get_codeblock(self.text_code_text, 1)) 90 self.parser.get_codeblock(self.text_code_text, 1).get_code()) 91 self.assertEqual(' code1\n\n', 92 self.parser.get_codeblock(self.code_text_code, 1).get_text()) 61 93 self.assertEqual('code1\n\n', 62 self.parser.get_codeblock(self.code_text_code, 1)) 94 self.parser.get_codeblock(self.code_text_code, 1).get_code()) 95 self.assertEqual(' code2\n', 96 self.parser.get_codeblock(self.code_text_code, 2).get_text()) 63 97 self.assertEqual('code2\n', 64 self.parser.get_codeblock(self.code_text_code, 2)) 98 self.parser.get_codeblock(self.code_text_code, 2).get_code()) 99 self.assertEqual(' code1\n', 100 self.parser.get_codeblock(self.code_text_code_no_blank_lines, 1).get_text()) 65 101 self.assertEqual('code1\n', 66 self.parser.get_codeblock(self.code_text_code_no_blank_lines, 1)) 102 self.parser.get_codeblock(self.code_text_code_no_blank_lines, 1).get_code()) 103 self.assertEqual(' code2', 104 self.parser.get_codeblock(self.code_text_code_no_blank_lines, 2).get_text()) 67 105 self.assertEqual('code2', 68 self.parser.get_codeblock(self.code_text_code_no_blank_lines, 2)) 106 self.parser.get_codeblock(self.code_text_code_no_blank_lines, 2).get_code()) 107 108 def test_get_codeblock_with_content_type(self): 109 self.assertEqual('text/x-python', 110 self.parser.get_codeblock(self.with_content_type, 1).content_type) 111 self.assertEqual(' line2', 112 self.parser.get_codeblock(self.with_content_type, 1).get_text()) 113 self.assertEqual('line2', 114 self.parser.get_codeblock(self.with_content_type, 1).get_code()) 115 116 def test_parse_text_code_text(self): 117 sections = self.parser.parse(self.text_code_text) 118 self.assertEqual(3, len(sections)) 119 self.assert_(not sections[0].is_codeblock()) 120 self.assertEqual('text\n\n', sections[0].get_text()) 121 self.assert_(sections[1].is_codeblock()) 122 self.assertEqual(' code\n\n', sections[1].get_text()) 123 self.assertEqual('code\n\n', sections[1].get_code()) 124 self.assert_(not sections[2].is_codeblock()) 125 self.assertEqual('text', sections[2].get_text()) 126 127 def test_parse_code_text_code(self): 128 sections = self.parser.parse(self.code_text_code) 129 self.assertEqual(3, len(sections)) 130 self.assert_(sections[0].is_codeblock()) 131 self.assertEqual(' code1\n\n', sections[0].get_text()) 132 self.assertEqual('code1\n\n', sections[0].get_code()) 133 self.assert_(not sections[1].is_codeblock()) 134 self.assertEqual('text\n\n', sections[1].get_text()) 135 self.assert_(sections[2].is_codeblock()) 136 self.assertEqual(' code2\n', sections[2].get_text()) 137 self.assertEqual('code2\n', sections[2].get_code()) bitstructures/trunk/substructure/views.py
r25 r42 53 53 if codeblock: 54 54 if filename.lower().endswith('html'): 55 return HttpResponse(codeblock , mimetype='text/html')55 return HttpResponse(codeblock.get_code(), mimetype='text/html') 56 56 else: 57 return HttpResponse(codeblock , mimetype='text/plain')57 return HttpResponse(codeblock.get_code(), mimetype='text/plain') 58 58 else: 59 59 raise Http404 bitstructures/trunk/templates/substructure/entry.html
r14 r42 1 {% load django.contrib.markup%}1 {% load substructure_tags %} 2 2 3 3 <div class="entry"> … … 13 13 {% endif %} 14 14 15 {{ entry.text| markdown }}15 {{ entry.text|syntax_highlighted_markdown }} 16 16 17 17 </div>
