buildframework/helium/external/python/lib/2.5/Sphinx-0.5.1-py2.5.egg/sphinx/highlighting.py
changeset 179 d8ac696cc51f
parent 1 be27ed110b50
child 180 e02a83d4c571
child 592 3215c239276a
equal deleted inserted replaced
1:be27ed110b50 179:d8ac696cc51f
     1 # -*- coding: utf-8 -*-
       
     2 """
       
     3     sphinx.highlighting
       
     4     ~~~~~~~~~~~~~~~~~~~
       
     5 
       
     6     Highlight code blocks using Pygments.
       
     7 
       
     8     :copyright: 2007-2008 by Georg Brandl.
       
     9     :license: BSD.
       
    10 """
       
    11 
       
    12 import sys
       
    13 import cgi
       
    14 import re
       
    15 import parser
       
    16 
       
    17 from sphinx.util.texescape import tex_hl_escape_map
       
    18 
       
    19 try:
       
    20     import pygments
       
    21     from pygments import highlight
       
    22     from pygments.lexers import PythonLexer, PythonConsoleLexer, CLexer, \
       
    23          TextLexer, RstLexer
       
    24     from pygments.lexers import get_lexer_by_name, guess_lexer
       
    25     from pygments.formatters import HtmlFormatter, LatexFormatter
       
    26     from pygments.filters import ErrorToken
       
    27     from pygments.style import Style
       
    28     from pygments.styles import get_style_by_name
       
    29     from pygments.styles.friendly import FriendlyStyle
       
    30     from pygments.token import Generic, Comment, Number
       
    31 except ImportError:
       
    32     pygments = None
       
    33 else:
       
    34     class SphinxStyle(Style):
       
    35         """
       
    36         Like friendly, but a bit darker to enhance contrast on the green
       
    37         background.
       
    38         """
       
    39 
       
    40         background_color = '#eeffcc'
       
    41         default_style = ''
       
    42 
       
    43         styles = FriendlyStyle.styles
       
    44         styles.update({
       
    45             Generic.Output: '#333',
       
    46             Comment: 'italic #408090',
       
    47             Number: '#208050',
       
    48         })
       
    49 
       
    50     lexers = dict(
       
    51         none = TextLexer(),
       
    52         python = PythonLexer(),
       
    53         pycon = PythonConsoleLexer(),
       
    54         # the python3 option exists as of Pygments 0.12, but it doesn't
       
    55         # do any harm in previous versions
       
    56         pycon3 = PythonConsoleLexer(python3=True),
       
    57         rest = RstLexer(),
       
    58         c = CLexer(),
       
    59     )
       
    60     for _lexer in lexers.values():
       
    61         _lexer.add_filter('raiseonerror')
       
    62 
       
    63 
       
    64 escape_hl_chars = {ord(u'@'): u'@PYGZat[]',
       
    65                    ord(u'['): u'@PYGZlb[]',
       
    66                    ord(u']'): u'@PYGZrb[]'}
       
    67 
       
    68 # used if Pygments is not available
       
    69 _LATEX_STYLES = r'''
       
    70 \newcommand\PYGZat{@}
       
    71 \newcommand\PYGZlb{[}
       
    72 \newcommand\PYGZrb{]}
       
    73 '''
       
    74 
       
    75 
       
    76 parsing_exceptions = (SyntaxError, UnicodeEncodeError)
       
    77 if sys.version_info < (2, 5):
       
    78     # Python <= 2.4 raises MemoryError when parsing an
       
    79     # invalid encoding cookie
       
    80     parsing_exceptions += MemoryError,
       
    81 
       
    82 
       
    83 class PygmentsBridge(object):
       
    84     def __init__(self, dest='html', stylename='sphinx'):
       
    85         self.dest = dest
       
    86         if not pygments:
       
    87             return
       
    88         if stylename == 'sphinx':
       
    89             style = SphinxStyle
       
    90         elif '.' in stylename:
       
    91             module, stylename = stylename.rsplit('.', 1)
       
    92             style = getattr(__import__(module, None, None, ['']), stylename)
       
    93         else:
       
    94             style = get_style_by_name(stylename)
       
    95         self.hfmter = {False: HtmlFormatter(style=style),
       
    96                        True: HtmlFormatter(style=style, linenos=True)}
       
    97         self.lfmter = {False: LatexFormatter(style=style, commandprefix='PYG'),
       
    98                        True: LatexFormatter(style=style, linenos=True,
       
    99                                             commandprefix='PYG')}
       
   100 
       
   101     def unhighlighted(self, source):
       
   102         if self.dest == 'html':
       
   103             return '<pre>' + cgi.escape(source) + '</pre>\n'
       
   104         else:
       
   105             # first, escape highlighting characters like Pygments does
       
   106             source = source.translate(escape_hl_chars)
       
   107             # then, escape all characters nonrepresentable in LaTeX
       
   108             source = source.translate(tex_hl_escape_map)
       
   109             return '\\begin{Verbatim}[commandchars=@\\[\\]]\n' + \
       
   110                    source + '\\end{Verbatim}\n'
       
   111 
       
   112     def try_parse(self, src):
       
   113         # Make sure it ends in a newline
       
   114         src += '\n'
       
   115 
       
   116         # Replace "..." by a mark which is also a valid python expression
       
   117         # (Note, the highlighter gets the original source, this is only done
       
   118         #  to allow "..." in code and still highlight it as Python code.)
       
   119         mark = "__highlighting__ellipsis__"
       
   120         src = src.replace("...", mark)
       
   121 
       
   122         # lines beginning with "..." are probably placeholders for suite
       
   123         src = re.sub(r"(?m)^(\s*)" + mark + "(.)", r"\1"+ mark + r"# \2", src)
       
   124 
       
   125         # if we're using 2.5, use the with statement
       
   126         if sys.version_info >= (2, 5):
       
   127             src = 'from __future__ import with_statement\n' + src
       
   128 
       
   129         if isinstance(src, unicode):
       
   130             # Non-ASCII chars will only occur in string literals
       
   131             # and comments.  If we wanted to give them to the parser
       
   132             # correctly, we'd have to find out the correct source
       
   133             # encoding.  Since it may not even be given in a snippet,
       
   134             # just replace all non-ASCII characters.
       
   135             src = src.encode('ascii', 'replace')
       
   136 
       
   137         try:
       
   138             parser.suite(src)
       
   139         except parsing_exceptions:
       
   140             return False
       
   141         else:
       
   142             return True
       
   143 
       
   144     def highlight_block(self, source, lang, linenos=False):
       
   145         if not pygments:
       
   146             return self.unhighlighted(source)
       
   147         if lang in ('py', 'python'):
       
   148             if source.startswith('>>>'):
       
   149                 # interactive session
       
   150                 lexer = lexers['pycon']
       
   151             else:
       
   152                 # maybe Python -- try parsing it
       
   153                 if self.try_parse(source):
       
   154                     lexer = lexers['python']
       
   155                 else:
       
   156                     return self.unhighlighted(source)
       
   157         elif lang in ('python3', 'py3') and source.startswith('>>>'):
       
   158             # for py3, recognize interactive sessions, but do not try parsing...
       
   159             lexer = lexers['pycon3']
       
   160         elif lang == 'guess':
       
   161             try:
       
   162                 lexer = guess_lexer(source)
       
   163             except Exception:
       
   164                 return self.unhighlighted(source)
       
   165         else:
       
   166             if lang in lexers:
       
   167                 lexer = lexers[lang]
       
   168             else:
       
   169                 lexer = lexers[lang] = get_lexer_by_name(lang)
       
   170                 lexer.add_filter('raiseonerror')
       
   171         try:
       
   172             if self.dest == 'html':
       
   173                 return highlight(source, lexer, self.hfmter[bool(linenos)])
       
   174             else:
       
   175                 hlsource = highlight(source, lexer, self.lfmter[bool(linenos)])
       
   176                 return hlsource.translate(tex_hl_escape_map)
       
   177         except ErrorToken:
       
   178             # this is most probably not the selected language,
       
   179             # so let it pass unhighlighted
       
   180             return self.unhighlighted(source)
       
   181 
       
   182     def get_stylesheet(self):
       
   183         if not pygments:
       
   184             if self.dest == 'latex':
       
   185                 return _LATEX_STYLES
       
   186             # no HTML styles needed
       
   187             return ''
       
   188         if self.dest == 'html':
       
   189             return self.hfmter[0].get_style_defs()
       
   190         else:
       
   191             styledefs = self.lfmter[0].get_style_defs()
       
   192             # workaround for Pygments < 0.12
       
   193             if styledefs.startswith('\\newcommand\\at{@}'):
       
   194                 styledefs += _LATEX_STYLES
       
   195             return styledefs