Georg Brandl avatar Georg Brandl committed 0f61d8e

Added options for rendering LaTeX in source code comments in the LaTeX formatter (#461).

Comments (0)

Files changed (4)

 * Benjamin Peterson -- Test suite refactoring
 * Justin Reidy -- MXML lexer
 * Andre Roberge -- Tango style
+* Konrad Rudolph -- LaTeX formatter enhancements
 * Mario Ruggier -- Evoque lexers
 * Stou Sandalski -- NumPy, FORTRAN, tcsh and XSLT lexers
 * Matteo Sasso -- Common Lisp lexer
   * CMake
   * OOC
 
+- Added options for rendering LaTeX in source code comments in the
+  LaTeX formatter (#461).
+
 - Updated the Logtalk lexer.
 
 - Added `line_number_start` option to image formatter (#456).

pygments/filters/__init__.py

                 yield ttype, value
 
 
+class GobbleFilter(Filter):
+    """
+    Gobbles source code lines (eats initial characters).
+
+    This filter drops the first ``n`` characters off every line of code.  This
+    may be useful when the source code fed to the lexer is indented by a fixed
+    amount of space that isn't desired in the output.
+
+    Options accepted:
+
+    `n` : int
+       The number of characters to gobble.
+
+    *New in Pygments 1.2.*
+    """
+    def __init__(self, **options):
+        Filter.__init__(self, **options)
+        self.n = get_int_opt(options, 'n', 0)
+
+    def gobble(self, value, left):
+        if left < len(value):
+            return value[left:], 0
+        else:
+            return '', left - len(value)
+
+    def filter(self, lexer, stream):
+        n = self.n
+        left = n # How many characters left to gobble.
+        for ttype, value in stream:
+            # Remove ``left`` tokens from first line, ``n`` from all others.
+            parts = value.split('\n')
+            (parts[0], left) = self.gobble(parts[0], left)
+            for i in range(1, len(parts)):
+                (parts[i], left) = self.gobble(parts[i], n)
+            value = '\n'.join(parts)
+
+            if value != '':
+                yield ttype, value
+
+
+class TokenMergeFilter(Filter):
+    """
+    Merges consecutive tokens with the same token type in the output stream of a
+    lexer.
+
+    *New in Pygments 1.2.*
+    """
+    def __init__(self, **options):
+        Filter.__init__(self, **options)
+
+    def filter(self, lexer, stream):
+        output = []
+        current_type = None
+        current_value = None
+        for ttype, value in stream:
+            if ttype is current_type:
+                current_value += value
+            else:
+                if not current_type is None:
+                    yield current_type, current_value
+                current_type = ttype
+                current_value = value
+        if not current_type is None:
+            yield current_type, current_value
+
+
 FILTERS = {
     'codetagify':     CodeTagFilter,
     'keywordcase':    KeywordCaseFilter,
     'highlight':      NameHighlightFilter,
     'raiseonerror':   RaiseOnErrorTokenFilter,
     'whitespace':     VisibleWhitespaceFilter,
+    'gobble':         GobbleFilter,
+    'tokenmerge':     TokenMergeFilter,
 }

pygments/formatters/latex.py

 
 
 def escape_tex(text, commandprefix):
-    return text.replace('@', '\x00').    \
-                replace('[', '\x01').    \
-                replace(']', '\x02').    \
-                replace('\x00', '@%sZat[]' % commandprefix).\
-                replace('\x01', '@%sZlb[]' % commandprefix).\
-                replace('\x02', '@%sZrb[]' % commandprefix)
+    return text.replace('\\', '\x00'). \
+                replace('{', '\x01'). \
+                replace('}', '\x02'). \
+                replace('^', '\x03'). \
+                replace('_', '\x04'). \
+                replace('\x00', r'\%sZbs{}' % commandprefix). \
+                replace('\x01', r'\%sZob{}' % commandprefix). \
+                replace('\x02', r'\%sZcb{}' % commandprefix). \
+                replace('\x03', r'\%sZca{}' % commandprefix). \
+                replace('\x04', r'\%sZus{}' % commandprefix)
 
 
 DOC_TEMPLATE = r'''
 
 %(styles)s
 
-\def\%(cp)sZat{@}
-\def\%(cp)sZlb{[}
-\def\%(cp)sZrb{]}
+\def\%(cp)sZbs{\char`\\}
+\def\%(cp)sZus{\char`\_}
+\def\%(cp)sZob{\char`\{}
+\def\%(cp)sZcb{\char`\}}
+\def\%(cp)sZca{\char`\^}
 \makeatother
 '''
 
         *New in Pygments 0.7.*
 
         *New in Pygments 0.10:* the default is now ``'PY'`` instead of ``'C'``.
+
+    `texcomments`
+        If set to ``True``, enables LaTeX comment lines.  That is, LaTex markup
+        in comment tokens is not escaped so that LaTeX can render it (default:
+        ``False``).  *New in Pygments 1.2.*
+
+    `mathescape`
+        If set to ``True``, enables LaTeX math mode escape in comments. That
+        is, ``'$...$'`` inside a comment will trigger math mode (default:
+        ``False``).  *New in Pygments 1.2.*
     """
     name = 'LaTeX'
     aliases = ['latex', 'tex']
         self.verboptions = options.get('verboptions', '')
         self.nobackground = get_bool_opt(options, 'nobackground', False)
         self.commandprefix = options.get('commandprefix', 'PY')
+        self.texcomments = get_bool_opt(options, 'texcomments', False)
+        self.mathescape = get_bool_opt(options, 'mathescape', False)
 
         self._create_stylesheet()
 
             realoutfile = outfile
             outfile = StringIO()
 
-        outfile.write(r'\begin{Verbatim}[commandchars=@\[\]')
+        outfile.write(r'\begin{Verbatim}[commandchars=\\\{\}')
         if self.linenos:
             start, step = self.linenostart, self.linenostep
             outfile.write(',numbers=left' +
                           (start and ',firstnumber=%d' % start or '') +
                           (step and ',stepnumber=%d' % step or ''))
+        if self.mathescape or self.texcomments:
+            outfile.write(r',codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8}')
         if self.verboptions:
             outfile.write(',' + self.verboptions)
         outfile.write(']\n')
 
         for ttype, value in tokensource:
-            value = escape_tex(value, self.commandprefix)
+            if ttype in Token.Comment:
+                if self.texcomments:
+                    # Try to guess comment starting lexeme and escape it ...
+                    start = value[0:1]
+                    for i in xrange(1, len(value)):
+                        if start[0] != value[i]:
+                            break
+                        start += value[i]
+
+                    value = value[len(start):]
+                    start = escape_tex(start, self.commandprefix)
+
+                    # ... but do not escape inside comment.
+                    value = start + value
+                elif self.mathescape:
+                    # Only escape parts not inside a math environment.
+                    parts = value.split('$')
+                    in_math = False
+                    for i, part in enumerate(parts):
+                        if not in_math:
+                            parts[i] = escape_tex(part, self.commandprefix)
+                        in_math = not in_math
+                    value = '$'.join(parts)
+                else:
+                    value = escape_tex(value, self.commandprefix)
+            else:
+                value = escape_tex(value, self.commandprefix)
             styles = []
             while ttype is not Token:
                 try:
                 spl = value.split('\n')
                 for line in spl[:-1]:
                     if line:
-                        outfile.write("@%s[%s][%s]" % (cp, styleval, line))
+                        outfile.write("\\%s{%s}{%s}" % (cp, styleval, line))
                     outfile.write('\n')
                 if spl[-1]:
-                    outfile.write("@%s[%s][%s]" % (cp, styleval, spl[-1]))
+                    outfile.write("\\%s{%s}{%s}" % (cp, styleval, spl[-1]))
             else:
                 outfile.write(value)
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.