Anonymous avatar Anonymous committed 0ac5ae8

Fix syntax highlighting so it works like other writers

Comments (0)

Files changed (1)

sphinx/writers/pdf.py

     :license: BSD, see LICENSE for details.
 """
 
+import parser
+import re
+import sys
+
 from StringIO import StringIO
 from docutils import writers
 from docutils import nodes
 from rst2pdf import createpdf
+from rst2pdf import pygments_code_block_directive
 from sphinx import addnodes
+from pygments.lexers import get_lexer_by_name, guess_lexer
 
 class PDFWriter(writers.Writer):
     def __init__(self,
         self.elements = {
             'title': document.settings.title,
         }
+        self.highlightlang = builder.config.highlight_language
         
     def visit_document(self,node):
         self.footnotestack.append('')
     def depart_start_of_file(self,node):
         self.footnotestack.pop()
         
+    def visit_highlightlang(self, node):
+        self.highlightlang = node['lang']
+        self.highlightlinenothreshold = node['linenothreshold']
+        raise nodes.SkipNode
+    
+    def visit_literal_block(self, node):
+        lang=lang_for_block(node.astext(),node.get('lang',self.highlightlang))
+        replacement = nodes.literal_block()
+        replacement.children = \
+            pygments_code_block_directive.code_block_directive(
+                                name = None,
+                                arguments = [lang],
+                                options = {},
+                                content = node.astext().splitlines(),
+                                lineno = False,
+                                content_offset = None,
+                                block_text = None,
+                                state = None,
+                                state_machine = None,
+                                )
+        node.parent.replace(node,replacement)
+        
     def visit_footnote(self, node):
         node['backrefs']=[ '%s_%s'%(self.footnotestack[-1],x) for x in node['backrefs']]
         node['ids']=[ '%s_%s'%(self.footnotestack[-1],x) for x in node['ids']]
         node['ids']=[ '%s_%s'%(self.footnotestack[-1],x) for x in node['ids']]
         node['refid']='%s_%s'%(self.footnotestack[-1],node['refid'])
         self.footnotedict[node['ids'][0]]=node
+
+
+# This is copied from sphinx.highlighting
+def lang_for_block(source,lang):
+    if lang in ('py', 'python'):
+        if source.startswith('>>>'):
+            # interactive session
+            return 'pycon'
+        else:
+            # maybe Python -- try parsing it
+            if try_parse(source):
+                return 'python'
+            else:
+                return 'text'
+    elif lang in ('python3', 'py3') and source.startswith('>>>'):
+        # for py3, recognize interactive sessions, but do not try parsing...
+        return 'pycon3'
+    elif lang == 'guess':
+        try:
+            #return 'python'
+            return guess_lexer(source).name
+        except Exception:
+            return None
+    else:
+        return lang
+    
+def try_parse(src):
+    # Make sure it ends in a newline
+    src += '\n'
+
+    # Replace "..." by a mark which is also a valid python expression
+    # (Note, the highlighter gets the original source, this is only done
+    #  to allow "..." in code and still highlight it as Python code.)
+    mark = "__highlighting__ellipsis__"
+    src = src.replace("...", mark)
+
+    # lines beginning with "..." are probably placeholders for suite
+    src = re.sub(r"(?m)^(\s*)" + mark + "(.)", r"\1"+ mark + r"# \2", src)
+
+    # if we're using 2.5, use the with statement
+    if sys.version_info >= (2, 5):
+        src = 'from __future__ import with_statement\n' + src
+
+    if isinstance(src, unicode):
+        # Non-ASCII chars will only occur in string literals
+        # and comments.  If we wanted to give them to the parser
+        # correctly, we'd have to find out the correct source
+        # encoding.  Since it may not even be given in a snippet,
+        # just replace all non-ASCII characters.
+        src = src.encode('ascii', 'replace')
+
+    try:
+        parser.suite(src)
+    except SyntaxError, UnicodeEncodeError:
+        return False
+    else:
+        return True
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.