Trees Indices Help
Trac
Package trac :: Package mimeview :: Module pygments

Source Code for Module trac.mimeview.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 
44 - class PygmentsRenderer (Component):
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
85 - def __init__ (self):
86 self._types = None
87 88 # ISystemInfoProvider methods 89
90 - def get_system_info (self):
91 version = get_pkginfo (pygments ).get ('version') 92 # if installed from source, fallback to the hardcoded version info 93 if not version and hasattr(pygments , '__version__'): 94 version = pygments .__version__ 95 yield 'Pygments', version
96 97 # IHTMLPreviewRenderer methods 98
99 - def get_quality_ratio (self, mimetype):
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
125 - def get_preference_panels (self, req):
126 yield ('pygments', _ ('Syntax Highlighting'))
127
128 - def render_preference_panel (self, req, panel):
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
147 - def match_request (self, req):
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
153 - def process_request (self, req):
154 style = req.args ['style'] 155 try: 156 style_cls = get_style_by_name(style) 157 except ValueError, e : 158 raise HTTPNotFound (e ) 159 160 parts = style_cls.__module__.split('.') 161 filename = resource_filename('.'.join (parts[:-1]), parts[-1] + '.py') 162 mtime = datetime.fromtimestamp(os.path .getmtime(filename ), localtz ) 163 last_modified = http_date (mtime) 164 if last_modified == req.get_header ('If-Modified-Since'): 165 req.send_response (304) 166 req.end_headers () 167 return 168 169 formatter = HtmlFormatter(style=style_cls) 170 content = u'\n\n'.join ([ 171 formatter .get_style_defs('div.code pre'), 172 formatter .get_style_defs('table.code td') 173 ]).encode('utf-8') 174 175 req.send_response (200) 176 req.send_header ('Content-Type', 'text/css; charset=utf-8') 177 req.send_header ('Last-Modified', last_modified ) 178 req.send_header ('Content-Length', len(content)) 179 req.write (content)
180 181 # Internal methods 182
183 - def _init_types (self):
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
200 - def _generate (self, language, content):
201 lexer = get_lexer_by_name(language, stripnl=False) 202 return GenshiHtmlFormatter().generate(lexer.get_tokens(content))
203 204
205 - class GenshiHtmlFormatter (HtmlFormatter):
206 """A Pygments formatter subclass that generates a Python stream instead 207 of writing markup as strings to an output file. 208 """ 209
210 - def _chunk (self, tokens):
211 """Groups tokens with the same CSS class in the token stream 212 and yields them one by one, along with the CSS class, with the 213 values chunked together.""" 214 215 last_class = None 216 text = [] 217 for ttype, value in tokens: 218 c = self._get_css_class(ttype) 219 if c == 'n': 220 c = '' 221 if c == last_class: 222 text .append(value) 223 continue 224 225 # If no value, leave the old <span> open. 226 if value: 227 yield last_class, u''.join (text ) 228 text = [value] 229 last_class = c 230 231 if text : 232 yield last_class, u''.join (text )
233
234 - def generate (self, tokens):
235 pos = (None, -1, -1) 236 span = QName('span') 237 class_ = QName('class') 238 239 def _generate(): 240 for c , text in self._chunk(tokens): 241 if c : 242 attrs = Attrs([(class_, c )]) 243 yield START, (span, attrs), pos 244 yield TEXT, text , pos 245 yield END, span, pos 246 else: 247 yield TEXT, text , pos
248 return Stream(_generate())
249
Trees Indices Help
Trac
Generated by Epydoc 3.0.1 on Mon Feb 13 23:37:26 2023 http://epydoc.sourceforge.net

AltStyle によって変換されたページ (->オリジナル) /