def translate(self): visitor = PDFTranslator(self.document, self.builder) self.document.walkabout(visitor) lang = self.config.language or 'en' langmod = get_language_available(lang)[2] self.docutils_languages = {lang: langmod} # Generate Contents topic manually if self.use_toc: contents=nodes.topic(classes=['contents']) contents+=nodes.title('') contents[0]+=nodes.Text(langmod.labels['contents']) contents['ids']=['Contents'] pending=nodes.topic() contents.append(pending) pending.details={} self.document.insert(0,nodes.raw(text='SetPageCounter 1 arabic', format='pdf')) self.document.insert(0,nodes.raw(text='OddPageBreak %s'%self.page_template, format='pdf')) self.document.insert(0,contents) self.document.insert(0,nodes.raw(text='SetPageCounter 1 lowerroman', format='pdf')) contTrans=PDFContents(self.document) contTrans.toc_depth = self.toc_depth contTrans.startnode=pending contTrans.apply() if self.use_coverpage: # Generate cover page # FIXME: duplicate from createpdf, refactor! # Add the Sphinx template paths def add_template_path(path): return os.path.join(self.srcdir, path) jinja_env = jinja2.Environment( loader=jinja2.FileSystemLoader([ self.srcdir, os.path.expanduser('~/.rst2pdf'), os.path.join(self.PATH,'templates')] + list(map(add_template_path, self.config.templates_path))), autoescape=jinja2.select_autoescape(['html', 'xml']) ) try: template = jinja_env.get_template(self.config.pdf_cover_template) except jinja2.TemplateNotFound: log.error("Can't find cover template %s, using default"%self.config.pdf_cover_template) template = jinja_env.get_template('sphinxcover.tmpl') # This is what's used in the python docs because # Latex does a manual linebreak. This sucks. authors=self.document.settings.author.split('\\') # Honour the "today" config setting if self.config.today : date = self.config.today else: date=time.strftime(self.config.today_fmt or _('%B %d, %Y')) # Feed data to the template, get restructured text. cover_text = template.render( title=self.document.settings.title or visitor.elements['title'], subtitle='%s %s'%(_('version'),self.config.version), authors=authors, date=date ) cover_tree = docutils.core.publish_doctree(cover_text) self.document.insert(0, cover_tree) sio=BytesIO() if self.invariant: createpdf.patch_PDFDate() createpdf.patch_digester() createpdf.RstToPdf(sphinx=True, stylesheets=self.stylesheets, language=self.__language, breaklevel=self.breaklevel, breakside=self.breakside, fit_mode=self.fitmode, font_path=self.fontpath, inline_footnotes=self.inline_footnotes, highlightlang=self.highlightlang, splittables=self.splittables, style_path=self.style_path, repeat_table_rows=self.repeat_table_rows, basedir=self.srcdir, def_dpi=self.default_dpi, real_footnotes=self.real_footnotes, numbered_links=self.use_numbered_links, background_fit_mode=self.fit_background_mode, baseurl=self.baseurl, section_header_depth=self.section_header_depth ).createPdf(doctree=self.document, output=sio, compressed=self.compressed) self.output=sio.getvalue()
def assemble_doctree(self, docname, title, author, appendices): # FIXME: use the new inline_all_trees from Sphinx. # check how the LaTeX builder does it. self.docnames = set([docname]) self.spinx_logger.info(darkgreen(docname) + " ") def process_tree(docname, tree): tree = tree.deepcopy() for toctreenode in tree.traverse(addnodes.toctree): newnodes = [] includefiles = map(str, toctreenode['includefiles']) for includefile in includefiles: try: self.spinx_logger.info(darkgreen(includefile) + " ") subtree = process_tree(includefile, self.env.get_doctree(includefile)) self.docnames.add(includefile) except Exception: self.warn('%s: toctree contains ref to nonexisting file %r'\ % (docname, includefile)) else: sof = addnodes.start_of_file(docname=includefile) sof.children = subtree.children newnodes.append(sof) toctreenode.parent.replace(toctreenode, newnodes) return tree tree = self.env.get_doctree(docname) tree = process_tree(docname, tree) self.docutils_languages = {} if self.config.language: self.docutils_languages[self.config.language] = \ get_language_available(self.config.language)[2] if self.opts.get('pdf_use_index',self.config.pdf_use_index): # Add index at the end of the document # This is a hack. create_index creates an index from # ALL the documents data, not just this one. # So, we preserve a copy, use just what we need, then # restore it. t=copy(self.env.indexentries) try: self.env.indexentries={docname:self.env.indexentries[docname+'-gen']} except KeyError: self.env.indexentries={} for dname in self.docnames: self.env.indexentries[dname]=t.get(dname,[]) genindex = IndexEntries(self.env).create_index(self) self.env.indexentries=t # EOH (End Of Hack) if genindex: # No point in creating empty indexes index_nodes=genindex_nodes(genindex) tree.append(nodes.raw(text='OddPageBreak twoColumn', format='pdf')) tree.append(index_nodes) # This is stolen from the HTML builder's prepare_writing function self.domain_indices = [] # html_domain_indices can be False/True or a list of index names indices_config = self.config.pdf_domain_indices if indices_config and hasattr(self.env, 'domains'): for domain in self.env.domains.values(): for indexcls in domain.indices: indexname = '%s-%s' % (domain.name, indexcls.name) if isinstance(indices_config, list): if indexname not in indices_config: continue # deprecated config value if indexname == 'py-modindex' and \ not self.config.pdf_use_modindex: continue content, collapse = indexcls(domain).generate() if content: self.domain_indices.append( (indexname, indexcls, content, collapse)) # self.domain_indices contains a list of indices to generate, like # this: # [('py-modindex', # <class 'sphinx.domains.python.PythonModuleIndex'>, # [(u'p', [[u'parrot', 0, 'test', u'module-parrot', 'Unix, Windows', # '', 'Analyze and reanimate dead parrots.']])], True)] # Now this in the HTML builder is passed onto write_domain_indices. # We handle it right here for indexname, indexcls, content, collapse in self.domain_indices: indexcontext = dict( indextitle = indexcls.localname, content = content, collapse_index = collapse, ) # In HTML this is handled with a Jinja template, domainindex.html # We have to generate docutils stuff right here in the same way. self.spinx_logger.info(' ' + indexname) print output=['DUMMY','=====','', '.. _modindex:\n\n'] t=indexcls.localname t+='\n'+'='*len(t)+'\n' output.append(t) for letter, entries in content: output.append('.. cssclass:: heading4\n\n%s\n\n'%letter) for (name, grouptype, page, anchor, extra, qualifier, description) in entries: if qualifier: q = '[%s]'%qualifier else: q = '' if extra: e = '(%s)'%extra else: e = '' output.append ('`%s <#%s>`_ %s %s'%(name, anchor, e, q)) output.append(' %s'%description) output.append('') dt = docutils.core.publish_doctree('\n'.join(output))[1:] dt.insert(0,nodes.raw(text='OddPageBreak twoColumn', format='pdf')) tree.extend(dt) if appendices: tree.append(nodes.raw(text='OddPageBreak %s'%self.page_template, format='pdf')) self.spinx_logger.info() self.spinx_logger.info('adding appendixes...') for docname in appendices: self.spinx_logger.info(darkgreen(docname) + " ") appendix = self.env.get_doctree(docname) appendix['docname'] = docname tree.append(appendix) self.spinx_logger.info('done') # Replace Sphinx's HighlightLanguageTransform with our own for Spinx version between 1.8.0 & less than 2.0.0 as # Sphinx's HighlightLanguageTransform breaks linenothreshold setting in the highlight directive (See issue #721) # This code can be removed when we drop support for Python 2 if sphinx.__version__ > '1.7.9' and sphinx.__version__ < '2.0.0': for i in range(len(self.env.app.registry.post_transforms)): if self.env.app.registry.post_transforms[i].__name__ == 'HighlightLanguageTransform': self.env.app.registry.post_transforms[i] = HighlightLanguageTransform break self.spinx_logger.info("resolving references...") self.env.resolve_references(tree, docname, self) for pendingnode in tree.traverse(addnodes.pending_xref): # This needs work, need to keep track of all targets # so I don't replace and create hanging refs, which # crash if pendingnode.get('reftarget',None) == 'genindex'\ and self.config.pdf_use_index: pendingnode.replace_self(nodes.reference(text=pendingnode.astext(), refuri=pendingnode['reftarget'])) # FIXME: probably need to handle dangling links to domain-specific indexes else: # FIXME: This is from the LaTeX builder and I still don't understand it # well, and doesn't seem to work # resolve :ref:s to distant tex files -- we can't add a cross-reference, # but append the document name docname = pendingnode['refdocname'] sectname = pendingnode['refsectname'] newnodes = [nodes.emphasis(sectname, sectname)] for subdir, title in self.titles: if docname.startswith(subdir): newnodes.append(nodes.Text(_(' (in '), _(' (in '))) newnodes.append(nodes.emphasis(title, title)) newnodes.append(nodes.Text(')', ')')) break else: pass pendingnode.replace_self(newnodes) #else: #pass return tree
def translate(self): visitor = PDFTranslator(self.document, self.builder) self.document.walkabout(visitor) lang = self.config.language or 'en' langmod = get_language_available(lang)[2] self.docutils_languages = {lang: langmod} # Generate Contents topic manually if self.use_toc: contents=nodes.topic(classes=['contents']) contents+=nodes.title('') contents[0]+=nodes.Text(langmod.labels['contents']) contents['ids']=['Contents'] pending=nodes.topic() contents.append(pending) pending.details={} self.document.insert(0,nodes.raw(text='SetPageCounter 1 arabic', format='pdf')) self.document.insert(0,nodes.raw(text='OddPageBreak %s'%self.page_template, format='pdf')) self.document.insert(0,contents) self.document.insert(0,nodes.raw(text='SetPageCounter 1 lowerroman', format='pdf')) contTrans=PDFContents(self.document) contTrans.toc_depth = self.toc_depth contTrans.startnode=pending contTrans.apply() if self.use_coverpage: # Generate cover page # FIXME: duplicate from createpdf, refactor! # Find cover template, save it in cover_file def find_cover(name): cover_path=[self.srcdir, os.path.expanduser('~/.rst2pdf'), os.path.join(self.PATH,'templates')] # Add the Sphinx template paths def add_template_path(path): return os.path.join(self.srcdir, path) cover_path.extend(map(add_template_path, self.config.templates_path)) cover_file=None for d in cover_path: if os.path.exists(os.path.join(d,name)): cover_file=os.path.join(d,name) break return cover_file cover_file=find_cover(self.config.pdf_cover_template) if cover_file is None: log.error("Can't find cover template %s, using default"%self.custom_cover) cover_file=find_cover('sphinxcover.tmpl') # This is what's used in the python docs because # Latex does a manual linebreak. This sucks. authors=self.document.settings.author.split('\\') # Feed data to the template, get restructured text. cover_text = createpdf.renderTemplate(tname=cover_file, title=self.document.settings.title or visitor.elements['title'], subtitle='%s %s'%(_('version'),self.config.version), authors=authors, date=ustrftime(self.config.today_fmt or _('%B %d, %Y')) ) cover_tree = docutils.core.publish_doctree(cover_text) self.document.insert(0, cover_tree) sio=StringIO() if self.invariant: createpdf.patch_PDFDate() createpdf.patch_digester() createpdf.RstToPdf(sphinx=True, stylesheets=self.stylesheets, language=self.__language, breaklevel=self.breaklevel, breakside=self.breakside, fit_mode=self.fitmode, font_path=self.fontpath, inline_footnotes=self.inline_footnotes, highlightlang=self.highlightlang, splittables=self.splittables, style_path=self.style_path, basedir=self.srcdir, def_dpi=self.default_dpi, real_footnotes=self.real_footnotes, numbered_links=self.use_numbered_links, background_fit_mode=self.fit_background_mode, baseurl=self.baseurl, section_header_depth=self.section_header_depth ).createPdf(doctree=self.document, output=sio, compressed=self.compressed) self.output=sio.getvalue()
def translate(self): visitor = PDFTranslator(self.document, self.builder) self.document.walkabout(visitor) lang = self.config.language or 'en' langmod = get_language_available(lang)[2] self.docutils_languages = {lang: langmod} # Generate Contents topic manually if self.use_toc: contents = nodes.topic(classes=['contents']) contents += nodes.title('') contents[0] += nodes.Text(langmod.labels['contents']) contents['ids'] = ['Contents'] pending = nodes.topic() contents.append(pending) pending.details = {} self.document.insert( 0, nodes.raw(text='SetPageCounter 1 arabic', format='pdf')) self.document.insert( 0, nodes.raw(text='OddPageBreak %s' % self.page_template, format='pdf')) self.document.insert(0, contents) self.document.insert( 0, nodes.raw(text='SetPageCounter 1 lowerroman', format='pdf')) contTrans = PDFContents(self.document) contTrans.toc_depth = self.toc_depth contTrans.startnode = pending contTrans.apply() if self.use_coverpage: # Generate cover page # FIXME: duplicate from createpdf, refactor! # Find cover template, save it in cover_file def find_cover(name): cover_path = [ self.srcdir, os.path.expanduser('~/.rst2pdf'), os.path.join(self.PATH, 'templates') ] # Add the Sphinx template paths def add_template_path(path): return os.path.join(self.srcdir, path) cover_path.extend( map(add_template_path, self.config.templates_path)) cover_file = None for d in cover_path: if os.path.exists(os.path.join(d, name)): cover_file = os.path.join(d, name) break return cover_file cover_file = find_cover(self.config.pdf_cover_template) if cover_file is None: log.error("Can't find cover template %s, using default" % self.custom_cover) cover_file = find_cover('sphinxcover.tmpl') # This is what's used in the python docs because # Latex does a manual linebreak. This sucks. authors = self.document.settings.author.split('\\') # Feed data to the template, get restructured text. cover_text = createpdf.renderTemplate( tname=cover_file, title=self.document.settings.title or visitor.elements['title'], subtitle='%s %s' % (_('version'), self.config.version), authors=authors, date=ustrftime(self.config.today_fmt or _('%B %d, %Y'))) cover_tree = docutils.core.publish_doctree(cover_text) self.document.insert(0, cover_tree) sio = StringIO() if self.invariant: createpdf.patch_PDFDate() createpdf.patch_digester() createpdf.RstToPdf(sphinx=True, stylesheets=self.stylesheets, language=self.__language, breaklevel=self.breaklevel, breakside=self.breakside, fit_mode=self.fitmode, font_path=self.fontpath, inline_footnotes=self.inline_footnotes, highlightlang=self.highlightlang, splittables=self.splittables, style_path=self.style_path, basedir=self.srcdir, def_dpi=self.default_dpi, real_footnotes=self.real_footnotes, numbered_links=self.use_numbered_links, background_fit_mode=self.fit_background_mode, baseurl=self.baseurl, section_header_depth=self.section_header_depth, floating_images=self.floating_images).createPdf( doctree=self.document, output=sio, compressed=self.compressed) self.output = sio.getvalue()
def assemble_doctree(self, docname, title, author, appendices): # FIXME: use the new inline_all_trees from Sphinx. # check how the LaTeX builder does it. self.docnames = set([docname]) self.info(darkgreen(docname) + " ", nonl=1) def process_tree(docname, tree): tree = tree.deepcopy() for toctreenode in tree.traverse(addnodes.toctree): newnodes = [] includefiles = map(str, toctreenode['includefiles']) for includefile in includefiles: try: self.info(darkgreen(includefile) + " ", nonl=1) subtree = process_tree(includefile, self.env.get_doctree(includefile)) self.docnames.add(includefile) except Exception: self.warn('%s: toctree contains ref to nonexisting file %r'\ % (docname, includefile)) else: sof = addnodes.start_of_file(docname=includefile) sof.children = subtree.children newnodes.append(sof) toctreenode.parent.replace(toctreenode, newnodes) return tree tree = self.env.get_doctree(docname) tree = process_tree(docname, tree) self.docutils_languages = {} if self.config.language: self.docutils_languages[self.config.language] = \ get_language_available(self.config.language)[2] if self.opts.get('pdf_use_index',self.config.pdf_use_index): # Add index at the end of the document # This is a hack. create_index creates an index from # ALL the documents data, not just this one. # So, we preserve a copy, use just what we need, then # restore it. #from pudb import set_trace; set_trace() t=copy(self.env.indexentries) try: self.env.indexentries={docname:self.env.indexentries[docname+'-gen']} except KeyError: self.env.indexentries={} for dname in self.docnames: self.env.indexentries[dname]=t.get(dname,[]) genindex = self.env.create_index(self) self.env.indexentries=t # EOH (End Of Hack) if genindex: # No point in creating empty indexes index_nodes=genindex_nodes(genindex) tree.append(nodes.raw(text='OddPageBreak twoColumn', format='pdf')) tree.append(index_nodes) # This is stolen from the HTML builder's prepare_writing function self.domain_indices = [] # html_domain_indices can be False/True or a list of index names indices_config = self.config.pdf_domain_indices if indices_config and hasattr(self.env, 'domains'): for domain in self.env.domains.itervalues(): for indexcls in domain.indices: indexname = '%s-%s' % (domain.name, indexcls.name) if isinstance(indices_config, list): if indexname not in indices_config: continue # deprecated config value if indexname == 'py-modindex' and \ not self.config.pdf_use_modindex: continue content, collapse = indexcls(domain).generate() if content: self.domain_indices.append( (indexname, indexcls, content, collapse)) # self.domain_indices contains a list of indices to generate, like # this: # [('py-modindex', # <class 'sphinx.domains.python.PythonModuleIndex'>, # [(u'p', [[u'parrot', 0, 'test', u'module-parrot', 'Unix, Windows', # '', 'Analyze and reanimate dead parrots.']])], True)] # Now this in the HTML builder is passed onto write_domain_indices. # We handle it right here for indexname, indexcls, content, collapse in self.domain_indices: indexcontext = dict( indextitle = indexcls.localname, content = content, collapse_index = collapse, ) # In HTML this is handled with a Jinja template, domainindex.html # We have to generate docutils stuff right here in the same way. self.info(' ' + indexname, nonl=1) print output=['DUMMY','=====','', '.. _modindex:\n\n'] t=indexcls.localname t+='\n'+'='*len(t)+'\n' output.append(t) for letter, entries in content: output.append('.. cssclass:: heading4\n\n%s\n\n'%letter) for (name, grouptype, page, anchor, extra, qualifier, description) in entries: if qualifier: q = '[%s]'%qualifier else: q = '' if extra: e = '(%s)'%extra else: e = '' output.append ('`%s <#%s>`_ %s %s'%(name, anchor, e, q)) output.append(' %s'%description) output.append('') dt = docutils.core.publish_doctree('\n'.join(output))[1:] dt.insert(0,nodes.raw(text='OddPageBreak twoColumn', format='pdf')) tree.extend(dt) if appendices: tree.append(nodes.raw(text='OddPageBreak %s'%self.page_template, format='pdf')) self.info() self.info('adding appendixes...', nonl=1) for docname in appendices: self.info(darkgreen(docname) + " ", nonl=1) appendix = self.env.get_doctree(docname) appendix['docname'] = docname tree.append(appendix) self.info('done') self.info() self.info("resolving references...") #print tree #print '--------------' self.env.resolve_references(tree, docname, self) #print tree for pendingnode in tree.traverse(addnodes.pending_xref): # This needs work, need to keep track of all targets # so I don't replace and create hanging refs, which # crash if pendingnode.get('reftarget',None) == 'genindex'\ and self.config.pdf_use_index: pendingnode.replace_self(nodes.reference(text=pendingnode.astext(), refuri=pendingnode['reftarget'])) # FIXME: probably need to handle dangling links to domain-specific indexes else: # FIXME: This is from the LaTeX builder and I still don't understand it # well, and doesn't seem to work # resolve :ref:s to distant tex files -- we can't add a cross-reference, # but append the document name docname = pendingnode['refdocname'] sectname = pendingnode['refsectname'] newnodes = [nodes.emphasis(sectname, sectname)] for subdir, title in self.titles: if docname.startswith(subdir): newnodes.append(nodes.Text(_(' (in '), _(' (in '))) newnodes.append(nodes.emphasis(title, title)) newnodes.append(nodes.Text(')', ')')) break else: pass pendingnode.replace_self(newnodes) #else: #pass return tree