root/bitstructures/trunk/substructure/codeblocks.py

Revision 42, 3.6 kB (checked in by simon, 9 months ago)

implemented syntax highlighting for codeblocks

Line 
1class MarkdownLine:
2    def __init__(self, line_of_text):
3        self.text = line_of_text
4
5    def is_blank(self):
6        return (len(self.text) == 0) or self.text.isspace()
7
8    def is_indented(self):
9        return self.text.startswith('    ')
10
11    def is_codeblock_line(self):
12        return self.is_indented() or self.is_blank()
13
14    def get_text_without_indentation(self):
15        if self.is_indented():
16            return self.text[4:]
17        else:
18            return self.text
19
20def 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
26def 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
34def 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
42class MarkdownLineTokeniser:
43    def __init__(self, text):
44        self._lines = iter(text.splitlines(True))
45        self.current_line = None
46        self._at_end = False
47
48    def is_at_end(self):
49        return self._at_end
50
51    def read_next(self):
52        try:
53            self.current_line = MarkdownLine(self._lines.next())
54        except StopIteration:
55            self._at_end = True
56            self.current_line = None
57
58class 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
68class 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
79class NonCodeblock(Section):
80    def is_codeblock(self):
81        return False
82
83class MarkdownCodeblocksParser:
84    def get_codeblock(self, text, n):
85        if n < 1:
86            return None
87        count = 0
88        lines = MarkdownLineTokeniser(text)
89        lines.read_next()
90        while not lines.is_at_end():
91            if lines.current_line.is_indented():
92                codeblock = self._get_codeblock(lines)
93                count += 1
94                if count == n:
95                    return codeblock
96            lines.read_next()
97        return None
98
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)
115            lines.read_next()
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
Note: See TracBrowser for help on using the browser.