1
# -*- coding: iso-8859-1 -*-
3
MoinMoin - highlighting parser using the Pygments highlighting library
5
@copyright: 2008 Radomir Dopieralski <moindev@sheep.art.pl>
6
@license: GNU GPL, see COPYING for details.
13
import pygments.lexers
14
import pygments.formatter
15
from pygments.token import Token
17
from MoinMoin import config, wikiutil
18
from MoinMoin.parser import parse_start_step
19
from MoinMoin.support.python_compatibility import hash_new
20
from MoinMoin.Page import Page
22
Dependencies = ['user'] # the "Toggle line numbers link" depends on user's language
25
def extensions_from_lexer_filenames(filenames):
26
# pygment's lexer.filenames is like ['*.py', 'Python'], but we only want
27
# the filename extensions list (like ['.py', ]):
28
return [filename[1:] for filename in filenames if filename.startswith('*.')]
30
def extensions_for_all_lexers():
32
get supported filename extensions for all pygments lexers
35
for name, short, patterns, mime in pygments.lexers.get_all_lexers():
36
extensions.extend(extensions_from_lexer_filenames(patterns))
40
class PygmentsFormatter(pygments.formatter.Formatter):
41
""" a formatter for Pygments that uses the moin formatter for creating output """
42
line_re = re.compile(r'(\n)')
44
def __init__(self, formatter, **kw):
45
pygments.formatter.Formatter.__init__(self)
47
self.formatter = formatter
48
self.start_line = kw.get('start_line', 0)
50
def get_class(self, ttype):
51
if ttype in Token.Text:
53
# Reuse existing MoinMoin css class names
54
elif ttype in Token.Operator.Word:
56
elif ttype in Token.Comment.Preproc:
58
elif ttype in Token.Keyword.Constant:
60
elif ttype in Token.Keyword:
62
elif ttype in Token.Name.Builtin:
64
elif ttype in Token.Name.Constant:
66
elif ttype in Token.String.Char:
68
elif ttype in Token.String.Escape:
70
elif ttype in Token.String:
72
elif ttype in Token.Number:
74
elif ttype in Token.Name:
76
elif ttype in Token.Comment:
78
elif ttype in Token.Generic.Heading:
80
elif ttype in Token.Generic.Subheading:
81
return 'DiffSeparator'
82
elif ttype in Token.Generic.Inserted:
84
elif ttype in Token.Generic.Deleted:
86
elif ttype in Token.Generic.Strong:
88
elif ttype in Token.Generic.Output:
90
elif ttype in Token.Generic.Prompt:
93
# skip tags that have no class defined
95
# ... or use the token's name when nothing apropriate
96
# return str(ttype).replace(".", " ")
98
def add_next_line(self, line_parts):
101
self.result.append(fmt.code_line(1))
102
self.result.append(fmt.line_anchordef(self.lineno))
103
self.result += line_parts
104
self.result.append(fmt.code_line(0))
106
def format(self, tokensource, outfile):
108
self.lineno = self.start_line
110
for ttype, value in tokensource:
111
class_ = self.get_class(ttype)
113
for line in self.line_re.split(value):
115
self.add_next_line(line_parts)
119
line_parts.append(fmt.code_token(1, class_))
120
line_parts.append(fmt.text(line))
122
line_parts.append(fmt.code_token(0, class_))
123
if line_parts and line_parts != [u'']: # Don't output an empty line at the end.
124
self.add_next_line(line_parts)
128
parsername = "highlight" # compatibility wrappers override this with the pygments lexer name
129
Dependencies = Dependencies
130
extensions = extensions_for_all_lexers()
132
def __init__(self, raw, request, filename=None, format_args='', **kw):
133
self.request = request
135
self.filename = filename
136
self.start_line = kw.get('start_line', 0)
138
if self.parsername == 'highlight':
139
# user is directly using the highlight parser
140
parts = format_args.split(None)
142
self.syntax = parts[0]
146
params = ' '.join(parts[1:])
150
# a compatibility wrapper inherited from this class
151
self.syntax = self.parsername
153
self.show_nums, self.num_start, self.num_step, attrs = parse_start_step(request, params)
155
def format(self, formatter):
156
_ = self.request.getText
157
fmt = PygmentsFormatter(formatter, start_line=self.start_line)
159
# adding line number anchors for process instruction lines
160
for lineno in range(1, self.num_start + 1):
161
fmt.result.append(formatter.line_anchordef(lineno))
163
fmt.result.append(formatter.div(1, css_class="highlight %s" % self.syntax))
164
self._code_id = hash_new('sha1', self.raw.encode(config.charset)).hexdigest()
166
if self.filename is not None:
168
lexer = pygments.lexers.get_lexer_for_filename(self.filename)
169
except pygments.util.ClassNotFound:
170
fmt.result.append(formatter.text(self.filename))
171
lexer = pygments.lexers.TextLexer()
174
lexer = pygments.lexers.get_lexer_by_name(self.syntax)
175
except pygments.util.ClassNotFound:
176
f = self.request.formatter
178
f.url(1, href=Page(self.request, _("HelpOnParsers")).url(self.request, escape=0)),
181
msg = _("Syntax highlighting not supported for '%(syntax)s', see %(highlight_help_page)s.") % {"syntax": wikiutil.escape(self.syntax),
182
"highlight_help_page": url
184
lexer = pygments.lexers.TextLexer()
186
fmt.result.append(formatter.code_area(1, self._code_id, self.parsername, self.show_nums, self.num_start, self.num_step, msg))
187
pygments.highlight(self.raw, lexer, fmt)
188
fmt.result.append(formatter.code_area(0, self._code_id))
189
fmt.result.append(formatter.div(0))
190
self.request.write("".join(fmt.result))