Commit 8fa2086580b678958dd292ddda57b799b9842cbd

  • avatar
  • gnomnain
  • Thu Sep 02 16:48:44 CEST 2010
Détection automatique du langage désactivée
  
1#!/usr/bin/python
2
3"""
4CodeHilite Extension for Python-Markdown
5========================================
6
7Adds code/syntax highlighting to standard Python-Markdown code blocks.
8
9Copyright 2006-2008 [Waylan Limberg](http://achinghead.com/).
10
11Project website: <http://www.freewisdom.org/project/python-markdown/CodeHilite>
12Contact: markdown@freewisdom.org
13
14License: BSD (see ../docs/LICENSE for details)
15
16Dependencies:
17* [Python 2.3+](http://python.org/)
18* [Markdown 2.0+](http://www.freewisdom.org/projects/python-markdown/)
19* [Pygments](http://pygments.org/)
20
21Modified to disable automatic language detection
22
23"""
24
25import markdown
26
27# --------------- CONSTANTS YOU MIGHT WANT TO MODIFY -----------------
28
29try:
30 TAB_LENGTH = markdown.TAB_LENGTH
31except AttributeError:
32 TAB_LENGTH = 4
33
34
35# ------------------ The Main CodeHilite Class ----------------------
36class CodeHilite:
37 """
38 Determine language of source code, and pass it into the pygments hilighter.
39
40 Basic Usage:
41 >>> code = CodeHilite(src = 'some text')
42 >>> html = code.hilite()
43
44 * src: Source string or any object with a .readline attribute.
45
46 * linenos: (Boolen) Turn line numbering 'on' or 'off' (off by default).
47
48 * css_class: Set class name of wrapper div ('codehilite' by default).
49
50 Low Level Usage:
51 >>> code = CodeHilite()
52 >>> code.src = 'some text' # String or anything with a .readline attr.
53 >>> code.linenos = True # True or False; Turns line numbering on or of.
54 >>> html = code.hilite()
55
56 """
57
58 def __init__(self, src=None, linenos=False, css_class="codehilite"):
59 self.src = src
60 self.lang = None
61 self.linenos = linenos
62 self.css_class = css_class
63
64 def hilite(self):
65 """
66 Pass code to the [Pygments](http://pygments.pocoo.org/) highliter with
67 optional line numbers. The output should then be styled with css to
68 your liking. No styles are applied by default - only styling hooks
69 (i.e.: <span class="k">).
70
71 returns : A string of html.
72
73 """
74
75 self.src = self.src.strip('\n')
76
77 self._getLang()
78
79 try:
80 from pygments import highlight
81 from pygments.lexers import get_lexer_by_name, guess_lexer, \
82 TextLexer
83 from pygments.formatters import HtmlFormatter
84 except ImportError:
85 # just escape and pass through
86 txt = self._escape(self.src)
87 if self.linenos:
88 txt = self._number(txt)
89 else :
90 txt = '<div class="%s"><pre>%s</pre></div>\n'% \
91 (self.css_class, txt)
92 return txt
93 else:
94 try:
95 lexer = get_lexer_by_name(self.lang)
96 except ValueError:
97 # try:
98 # lexer = guess_lexer(self.src)
99 # except ValueError:
100 lexer = TextLexer()
101 formatter = HtmlFormatter(linenos=self.linenos,
102 cssclass=self.css_class)
103 return highlight(self.src, lexer, formatter)
104
105 def _escape(self, txt):
106 """ basic html escaping """
107 txt = txt.replace('&', '&amp;')
108 txt = txt.replace('<', '&lt;')
109 txt = txt.replace('>', '&gt;')
110 txt = txt.replace('"', '&quot;')
111 return txt
112
113 def _number(self, txt):
114 """ Use <ol> for line numbering """
115 # Fix Whitespace
116 txt = txt.replace('\t', ' '*TAB_LENGTH)
117 txt = txt.replace(" "*4, "&nbsp; &nbsp; ")
118 txt = txt.replace(" "*3, "&nbsp; &nbsp;")
119 txt = txt.replace(" "*2, "&nbsp; ")
120
121 # Add line numbers
122 lines = txt.splitlines()
123 txt = '<div class="codehilite"><pre><ol>\n'
124 for line in lines:
125 txt += '\t<li>%s</li>\n'% line
126 txt += '</ol></pre></div>\n'
127 return txt
128
129
130 def _getLang(self):
131 """
132 Determines language of a code block from shebang lines and whether said
133 line should be removed or left in place. If the sheband line contains a
134 path (even a single /) then it is assumed to be a real shebang lines and
135 left alone. However, if no path is given (e.i.: #!python or :::python)
136 then it is assumed to be a mock shebang for language identifitation of a
137 code fragment and removed from the code block prior to processing for
138 code highlighting. When a mock shebang (e.i: #!python) is found, line
139 numbering is turned on. When colons are found in place of a shebang
140 (e.i.: :::python), line numbering is left in the current state - off
141 by default.
142
143 """
144
145 import re
146
147 #split text into lines
148 lines = self.src.split("\n")
149 #pull first line to examine
150 fl = lines.pop(0)
151
152 c = re.compile(r'''
153 (?:(?:::+)|(?P<shebang>[#]!)) # Shebang or 2 or more colons.
154 (?P<path>(?:/\w+)*[/ ])? # Zero or 1 path
155 (?P<lang>[\w+-]*) # The language
156 ''', re.VERBOSE)
157 # search first line for shebang
158 m = c.search(fl)
159 if m:
160 # we have a match
161 try:
162 self.lang = m.group('lang').lower()
163 except IndexError:
164 self.lang = None
165 if m.group('path'):
166 # path exists - restore first line
167 lines.insert(0, fl)
168 if m.group('shebang'):
169 # shebang exists - use line numbers
170 self.linenos = True
171 else:
172 # No match
173 lines.insert(0, fl)
174
175 self.src = "\n".join(lines).strip("\n")
176
177
178
179# ------------------ The Markdown Extension -------------------------------
180class HiliteTreeprocessor(markdown.treeprocessors.Treeprocessor):
181 """ Hilight source code in code blocks. """
182
183 def run(self, root):
184 """ Find code blocks and store in htmlStash. """
185 blocks = root.getiterator('pre')
186 for block in blocks:
187 children = block.getchildren()
188 if len(children) == 1 and children[0].tag == 'code':
189 code = CodeHilite(children[0].text,
190 linenos=self.config['force_linenos'][0],
191 css_class=self.config['css_class'][0])
192 placeholder = self.markdown.htmlStash.store(code.hilite(),
193 safe=True)
194 # Clear codeblock in etree instance
195 block.clear()
196 # Change to p element which will later
197 # be removed when inserting raw html
198 block.tag = 'p'
199 block.text = placeholder
200
201
202class CodeHiliteExtension(markdown.Extension):
203 """ Add source code hilighting to markdown codeblocks. """
204
205 def __init__(self, configs):
206 # define default configs
207 self.config = {
208 'force_linenos' : [False, "Force line numbers - Default: False"],
209 'css_class' : ["codehilite",
210 "Set class name for wrapper <div> - Default: codehilite"],
211 }
212
213 # Override defaults with user settings
214 for key, value in configs:
215 self.setConfig(key, value)
216
217 def extendMarkdown(self, md, md_globals):
218 """ Add HilitePostprocessor to Markdown instance. """
219 hiliter = HiliteTreeprocessor(md)
220 hiliter.config = self.config
221 md.treeprocessors.add("hilite", hiliter, "_begin")
222
223
224def makeExtension(configs={}):
225 return CodeHiliteExtension(configs=configs)
  
33
44register = template.Library()
55
6markdown_opts = "safe,codehilite,extra"
6markdown_opts = "safe,myhilite,extra"
77
88def markext(value, arg=''):
99 return markdown(value, markdown_opts)