Back to index

moin  1.9.0~rc2
rtf.py
Go to the documentation of this file.
00001 # -*- coding: utf-8 -*-
00002 """
00003     pygments.formatters.rtf
00004     ~~~~~~~~~~~~~~~~~~~~~~~
00005 
00006     A formatter that generates RTF files.
00007 
00008     :copyright: Copyright 2006-2009 by the Pygments team, see AUTHORS.
00009     :license: BSD, see LICENSE for details.
00010 """
00011 
00012 from pygments.formatter import Formatter
00013 
00014 
00015 __all__ = ['RtfFormatter']
00016 
00017 
00018 class RtfFormatter(Formatter):
00019     """
00020     Format tokens as RTF markup. This formatter automatically outputs full RTF
00021     documents with color information and other useful stuff. Perfect for Copy and
00022     Paste into Microsoft® Word® documents.
00023 
00024     *New in Pygments 0.6.*
00025 
00026     Additional options accepted:
00027 
00028     `style`
00029         The style to use, can be a string or a Style subclass (default:
00030         ``'default'``).
00031 
00032     `fontface`
00033         The used font famliy, for example ``Bitstream Vera Sans``. Defaults to
00034         some generic font which is supposed to have fixed width.
00035     """
00036     name = 'RTF'
00037     aliases = ['rtf']
00038     filenames = ['*.rtf']
00039 
00040     unicodeoutput = False
00041 
00042     def __init__(self, **options):
00043         """
00044         Additional options accepted:
00045 
00046         ``fontface``
00047             Name of the font used. Could for example be ``'Courier New'``
00048             to further specify the default which is ``'\fmodern'``. The RTF
00049             specification claims that ``\fmodern`` are "Fixed-pitch serif
00050             and sans serif fonts". Hope every RTF implementation thinks
00051             the same about modern...
00052         """
00053         Formatter.__init__(self, **options)
00054         self.fontface = options.get('fontface') or ''
00055 
00056     def _escape(self, text):
00057         return text.replace('\\', '\\\\') \
00058                    .replace('{', '\\{') \
00059                    .replace('}', '\\}')
00060 
00061     def _escape_text(self, text):
00062         # empty strings, should give a small performance improvment
00063         if not text:
00064             return ''
00065 
00066         # escape text
00067         text = self._escape(text)
00068         if self.encoding in ('utf-8', 'utf-16', 'utf-32'):
00069             encoding = 'iso-8859-15'
00070         else:
00071             encoding = self.encoding or 'iso-8859-15'
00072 
00073         buf = []
00074         for c in text:
00075             if ord(c) > 128:
00076                 ansic = c.encode(encoding, 'ignore') or '?'
00077                 if ord(ansic) > 128:
00078                     ansic = '\\\'%x' % ord(ansic)
00079                 else:
00080                     ansic = c
00081                 buf.append(r'\ud{\u%d%s}' % (ord(c), ansic))
00082             else:
00083                 buf.append(str(c))
00084 
00085         return ''.join(buf).replace('\n', '\\par\n')
00086 
00087     def format_unencoded(self, tokensource, outfile):
00088         # rtf 1.8 header
00089         outfile.write(r'{\rtf1\ansi\deff0'
00090                       r'{\fonttbl{\f0\fmodern\fprq1\fcharset0%s;}}'
00091                       r'{\colortbl;' % (self.fontface and
00092                                         ' ' + self._escape(self.fontface) or
00093                                         ''))
00094 
00095         # convert colors and save them in a mapping to access them later.
00096         color_mapping = {}
00097         offset = 1
00098         for _, style in self.style:
00099             for color in style['color'], style['bgcolor'], style['border']:
00100                 if color and color not in color_mapping:
00101                     color_mapping[color] = offset
00102                     outfile.write(r'\red%d\green%d\blue%d;' % (
00103                         int(color[0:2], 16),
00104                         int(color[2:4], 16),
00105                         int(color[4:6], 16)
00106                     ))
00107                     offset += 1
00108         outfile.write(r'}\f0')
00109 
00110         # highlight stream
00111         for ttype, value in tokensource:
00112             while not self.style.styles_token(ttype) and ttype.parent:
00113                 ttype = ttype.parent
00114             style = self.style.style_for_token(ttype)
00115             buf = []
00116             if style['bgcolor']:
00117                 buf.append(r'\cb%d' % color_mapping[style['bgcolor']])
00118             if style['color']:
00119                 buf.append(r'\cf%d' % color_mapping[style['color']])
00120             if style['bold']:
00121                 buf.append(r'\b')
00122             if style['italic']:
00123                 buf.append(r'\i')
00124             if style['underline']:
00125                 buf.append(r'\ul')
00126             if style['border']:
00127                 buf.append(r'\chbrdr\chcfpat%d' %
00128                            color_mapping[style['border']])
00129             start = ''.join(buf)
00130             if start:
00131                 outfile.write('{%s ' % start)
00132             outfile.write(self._escape_text(value))
00133             if start:
00134                 outfile.write('}')
00135 
00136         outfile.write('}')