Package trac ::
Package mimeview ::
Module pygments
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) 2006-2009 Edgewall Software
4 # Copyright (C) 2006 Matthew Good <matt@matt-good.net>
5 # All rights reserved.
6 #
7 # This software is licensed as described in the file COPYING, which
8 # you should have received as part of this distribution. The terms
9 # are also available at http://trac.edgewall.org/wiki/TracLicense.
10 #
11 # Author: Matthew Good <matt@matt-good.net>
12
13 from datetime import datetime
14 import os
15 from pkg_resources import resource_filename
16 import re
17
18 from trac .core import *
19 from trac .config import ListOption , Option
20 from trac .env import ISystemInfoProvider
21 from trac .mimeview .api import IHTMLPreviewRenderer, Mimeview
22 from trac .prefs import IPreferencePanelProvider
23 from trac .util import get_pkginfo
24 from trac .util .datefmt import http_date , localtz
25 from trac .util .translation import _
26 from trac .web .api import IRequestHandler , HTTPNotFound
27 from trac .web .chrome import add_notice , add_stylesheet
28
29 from genshi import QName, Stream
30 from genshi.core import Attrs, START, END, TEXT
31
32 # Kludge to workaround the lack of absolute imports in Python version prior to
33 # 2.5
34 pygments = __import__('pygments', {}, {}, ['lexers', 'styles', 'formatters'])
35 get_all_lexers = pygments .lexers.get_all_lexers
36 get_lexer_by_name = pygments .lexers.get_lexer_by_name
37 HtmlFormatter = pygments .formatters.html .HtmlFormatter
38 get_all_styles = pygments .styles.get_all_styles
39 get_style_by_name = pygments .styles.get_style_by_name
40
41 __all__ = ['PygmentsRenderer']
42
43
45 """HTML renderer for syntax highlighting based on Pygments."""
46
47 implements (ISystemInfoProvider, IHTMLPreviewRenderer,
48 IPreferencePanelProvider , IRequestHandler )
49
50 default_style = Option ('mimeviewer', 'pygments_default_style', 'trac',
51 """The default style to use for Pygments syntax highlighting.""")
52
53 pygments_modes = ListOption ('mimeviewer', 'pygments_modes',
54 '', doc=
55 """List of additional MIME types known by Pygments.
56
57 For each, a tuple `mimetype:mode:quality` has to be
58 specified, where `mimetype` is the MIME type,
59 `mode` is the corresponding Pygments mode to be used
60 for the conversion and `quality` is the quality ratio
61 associated to this conversion. That can also be used
62 to override the default quality ratio used by the
63 Pygments render.""")
64
65 expand_tabs = True
66 returns_source = True
67
68 QUALITY_RATIO = 7
69
70 EXAMPLE = """<!DOCTYPE html>
71 <html lang="en">
72 <head>
73 <title>Hello, world!</title>
74 <script>
75 jQuery(document).ready(function($) {
76 $("h1").fadeIn("slow");
77 });
78 </script>
79 </head>
80 <body>
81 <h1>Hello, world!</h1>
82 </body>
83 </html>"""
84
86 self._types = None
87
88 # ISystemInfoProvider methods
89
96
97 # IHTMLPreviewRenderer methods
98
100 # Extend default MIME type to mode mappings with configured ones
101 if self._types is None:
102 self._init_types()
103 try:
104 return self._types[mimetype][1]
105 except KeyError:
106 return 0
107
108 - def render (self, context, mimetype, content, filename=None, rev=None):
109 req = context.req
110 if self._types is None:
111 self._init_types()
112 add_stylesheet (req, '/pygments/%s.css' %
113 req.session .get ('pygments_style', self.default_style ))
114 try:
115 if len(content) > 0:
116 mimetype = mimetype.split(';', 1)[0]
117 language = self._types[mimetype][0]
118 return self._generate(language, content)
119 except (KeyError, ValueError):
120 raise Exception("No Pygments lexer found for mime-type '%s'."
121 % mimetype)
122
123 # IPreferencePanelProvider methods
124
126 yield ('pygments', _ ('Syntax Highlighting'))
127
129 styles = list(get_all_styles())
130
131 if req.method == 'POST':
132 style = req.args .get ('style')
133 if style and style in styles:
134 req.session ['pygments_style'] = style
135 add_notice (req, _ ('Your preferences have been saved.'))
136 req.redirect (req.href .prefs (panel or None))
137
138 output = self._generate('html', self.EXAMPLE )
139 return 'prefs_pygments.html', {
140 'output': output,
141 'selection': req.session .get ('pygments_style', self.default_style ),
142 'styles': styles
143 }
144
145 # IRequestHandler methods
146
148 match = re.match(r'/pygments/(\w+)\.css', req.path_info )
149 if match:
150 req.args ['style'] = match.group (1)
151 return True
152
180
181 # Internal methods
182
184 self._types = {}
185 for lexname, aliases, _ , mimetypes in get_all_lexers():
186 name = aliases and aliases[0] or lexname
187 for mimetype in mimetypes:
188 self._types[mimetype] = (name , self.QUALITY_RATIO )
189
190 # Pygments currently doesn't know application/javascript
191 if 'application/javascript' not in self._types:
192 js_entry = self._types.get ('text/javascript')
193 if js_entry:
194 self._types['application/javascript'] = js_entry
195
196 self._types.update (
197 Mimeview (self.env ).configured_modes_mapping ('pygments')
198 )
199
201 lexer = get_lexer_by_name(language, stripnl=False)
202 return GenshiHtmlFormatter().generate(lexer.get_tokens(content))
203
204