PageRenderTime 148ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 1ms

/documentor/libraries/Sphinx-1.1.3-py3.2/sphinx/builders/qthelp.py

https://github.com/tictactatic/Superdesk
Python | 296 lines | 253 code | 16 blank | 27 comment | 15 complexity | fb86754164afeb6f1078af46f114ea31 MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-3.0, GPL-2.0
  1. # -*- coding: utf-8 -*-
  2. """
  3. sphinx.builders.qthelp
  4. ~~~~~~~~~~~~~~~~~~~~~~
  5. Build input files for the Qt collection generator.
  6. :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
  7. :license: BSD, see LICENSE for details.
  8. """
  9. import os
  10. import re
  11. import codecs
  12. import posixpath
  13. from os import path
  14. from docutils import nodes
  15. from sphinx import addnodes
  16. from sphinx.builders.html import StandaloneHTMLBuilder
  17. from sphinx.util import force_decode
  18. from sphinx.util.pycompat import htmlescape
  19. _idpattern = re.compile(
  20. r'(?P<title>.+) (\((class in )?(?P<id>[\w\.]+)( (?P<descr>\w+))?\))$')
  21. # Qt Help Collection Project (.qhcp).
  22. # Is the input file for the help collection generator.
  23. # It contains references to compressed help files which should be
  24. # included in the collection.
  25. # It may contain various other information for customizing Qt Assistant.
  26. collection_template = '''\
  27. <?xml version="1.0" encoding="utf-8" ?>
  28. <QHelpCollectionProject version="1.0">
  29. <assistant>
  30. <title>%(title)s</title>
  31. <homePage>%(homepage)s</homePage>
  32. <startPage>%(startpage)s</startPage>
  33. </assistant>
  34. <docFiles>
  35. <generate>
  36. <file>
  37. <input>%(outname)s.qhp</input>
  38. <output>%(outname)s.qch</output>
  39. </file>
  40. </generate>
  41. <register>
  42. <file>%(outname)s.qch</file>
  43. </register>
  44. </docFiles>
  45. </QHelpCollectionProject>
  46. '''
  47. # Qt Help Project (.qhp)
  48. # This is the input file for the help generator.
  49. # It contains the table of contents, indices and references to the
  50. # actual documentation files (*.html).
  51. # In addition it defines a unique namespace for the documentation.
  52. project_template = '''\
  53. <?xml version="1.0" encoding="utf-8" ?>
  54. <QtHelpProject version="1.0">
  55. <namespace>%(namespace)s</namespace>
  56. <virtualFolder>doc</virtualFolder>
  57. <customFilter name="%(project)s %(version)s">
  58. <filterAttribute>%(outname)s</filterAttribute>
  59. <filterAttribute>%(version)s</filterAttribute>
  60. </customFilter>
  61. <filterSection>
  62. <filterAttribute>%(outname)s</filterAttribute>
  63. <filterAttribute>%(version)s</filterAttribute>
  64. <toc>
  65. <section title="%(title)s" ref="%(masterdoc)s.html">
  66. %(sections)s
  67. </section>
  68. </toc>
  69. <keywords>
  70. %(keywords)s
  71. </keywords>
  72. <files>
  73. %(files)s
  74. </files>
  75. </filterSection>
  76. </QtHelpProject>
  77. '''
  78. section_template = '<section title="%(title)s" ref="%(ref)s"/>'
  79. file_template = ' '*12 + '<file>%(filename)s</file>'
  80. class QtHelpBuilder(StandaloneHTMLBuilder):
  81. """
  82. Builder that also outputs Qt help project, contents and index files.
  83. """
  84. name = 'qthelp'
  85. # don't copy the reST source
  86. copysource = False
  87. supported_image_types = ['image/svg+xml', 'image/png', 'image/gif',
  88. 'image/jpeg']
  89. # don't add links
  90. add_permalinks = False
  91. # don't add sidebar etc.
  92. embedded = True
  93. def init(self):
  94. StandaloneHTMLBuilder.init(self)
  95. # the output files for HTML help must be .html only
  96. self.out_suffix = '.html'
  97. #self.config.html_style = 'traditional.css'
  98. def handle_finish(self):
  99. self.build_qhp(self.outdir, self.config.qthelp_basename)
  100. def build_qhp(self, outdir, outname):
  101. self.info('writing project file...')
  102. # sections
  103. tocdoc = self.env.get_and_resolve_doctree(self.config.master_doc, self,
  104. prune_toctrees=False)
  105. istoctree = lambda node: (
  106. isinstance(node, addnodes.compact_paragraph)
  107. and 'toctree' in node)
  108. sections = []
  109. for node in tocdoc.traverse(istoctree):
  110. sections.extend(self.write_toc(node))
  111. for indexname, indexcls, content, collapse in self.domain_indices:
  112. item = section_template % {'title': indexcls.localname,
  113. 'ref': '%s.html' % indexname}
  114. sections.append(' ' * 4 * 4 + item)
  115. # sections may be unicode strings or byte strings, we have to make sure
  116. # they are all unicode strings before joining them
  117. new_sections = []
  118. for section in sections:
  119. if not isinstance(section, str):
  120. new_sections.append(force_decode(section, None))
  121. else:
  122. new_sections.append(section)
  123. sections = '\n'.join(new_sections)
  124. # keywords
  125. keywords = []
  126. index = self.env.create_index(self, group_entries=False)
  127. for (key, group) in index:
  128. for title, (refs, subitems) in group:
  129. keywords.extend(self.build_keywords(title, refs, subitems))
  130. keywords = '\n'.join(keywords)
  131. # files
  132. if not outdir.endswith(os.sep):
  133. outdir += os.sep
  134. olen = len(outdir)
  135. projectfiles = []
  136. staticdir = path.join(outdir, '_static')
  137. imagesdir = path.join(outdir, '_images')
  138. for root, dirs, files in os.walk(outdir):
  139. resourcedir = root.startswith(staticdir) or \
  140. root.startswith(imagesdir)
  141. for fn in files:
  142. if (resourcedir and not fn.endswith('.js')) or \
  143. fn.endswith('.html'):
  144. filename = path.join(root, fn)[olen:]
  145. projectfiles.append(file_template %
  146. {'filename': htmlescape(filename)})
  147. projectfiles = '\n'.join(projectfiles)
  148. # it seems that the "namespace" may not contain non-alphanumeric
  149. # characters, and more than one successive dot, or leading/trailing
  150. # dots, are also forbidden
  151. nspace = 'org.sphinx.%s.%s' % (outname, self.config.version)
  152. nspace = re.sub('[^a-zA-Z0-9.]', '', nspace)
  153. nspace = re.sub(r'\.+', '.', nspace).strip('.')
  154. nspace = nspace.lower()
  155. # write the project file
  156. f = codecs.open(path.join(outdir, outname+'.qhp'), 'w', 'utf-8')
  157. try:
  158. f.write(project_template % {
  159. 'outname': htmlescape(outname),
  160. 'title': htmlescape(self.config.html_title),
  161. 'version': htmlescape(self.config.version),
  162. 'project': htmlescape(self.config.project),
  163. 'namespace': htmlescape(nspace),
  164. 'masterdoc': htmlescape(self.config.master_doc),
  165. 'sections': sections,
  166. 'keywords': keywords,
  167. 'files': projectfiles})
  168. finally:
  169. f.close()
  170. homepage = 'qthelp://' + posixpath.join(
  171. nspace, 'doc', self.get_target_uri(self.config.master_doc))
  172. startpage = 'qthelp://' + posixpath.join(nspace, 'doc', 'index.html')
  173. self.info('writing collection project file...')
  174. f = codecs.open(path.join(outdir, outname+'.qhcp'), 'w', 'utf-8')
  175. try:
  176. f.write(collection_template % {
  177. 'outname': htmlescape(outname),
  178. 'title': htmlescape(self.config.html_short_title),
  179. 'homepage': htmlescape(homepage),
  180. 'startpage': htmlescape(startpage)})
  181. finally:
  182. f.close()
  183. def isdocnode(self, node):
  184. if not isinstance(node, nodes.list_item):
  185. return False
  186. if len(node.children) != 2:
  187. return False
  188. if not isinstance(node.children[0], addnodes.compact_paragraph):
  189. return False
  190. if not isinstance(node.children[0][0], nodes.reference):
  191. return False
  192. if not isinstance(node.children[1], nodes.bullet_list):
  193. return False
  194. return True
  195. def write_toc(self, node, indentlevel=4):
  196. # XXX this should return a Unicode string, not a bytestring
  197. parts = []
  198. if self.isdocnode(node):
  199. refnode = node.children[0][0]
  200. link = refnode['refuri']
  201. title = htmlescape(refnode.astext()).replace('"', '&quot;')
  202. item = '<section title="%(title)s" ref="%(ref)s">' % \
  203. {'title': title, 'ref': link}
  204. parts.append(' '*4*indentlevel + item)
  205. for subnode in node.children[1]:
  206. parts.extend(self.write_toc(subnode, indentlevel+1))
  207. parts.append(' '*4*indentlevel + '</section>')
  208. elif isinstance(node, nodes.list_item):
  209. for subnode in node:
  210. parts.extend(self.write_toc(subnode, indentlevel))
  211. elif isinstance(node, nodes.reference):
  212. link = node['refuri']
  213. title = htmlescape(node.astext()).replace('"','&quot;')
  214. item = section_template % {'title': title, 'ref': link}
  215. item = ' ' * 4 * indentlevel + item
  216. parts.append(item.encode('ascii', 'xmlcharrefreplace'))
  217. elif isinstance(node, nodes.bullet_list):
  218. for subnode in node:
  219. parts.extend(self.write_toc(subnode, indentlevel))
  220. elif isinstance(node, addnodes.compact_paragraph):
  221. for subnode in node:
  222. parts.extend(self.write_toc(subnode, indentlevel))
  223. return parts
  224. def keyword_item(self, name, ref):
  225. matchobj = _idpattern.match(name)
  226. if matchobj:
  227. groupdict = matchobj.groupdict()
  228. shortname = groupdict['title']
  229. id = groupdict.get('id')
  230. #descr = groupdict.get('descr')
  231. if shortname.endswith('()'):
  232. shortname = shortname[:-2]
  233. id = '%s.%s' % (id, shortname)
  234. else:
  235. id = None
  236. if id:
  237. item = ' '*12 + '<keyword name="%s" id="%s" ref="%s"/>' % (
  238. name, id, ref[1])
  239. else:
  240. item = ' '*12 + '<keyword name="%s" ref="%s"/>' % (name, ref[1])
  241. item.encode('ascii', 'xmlcharrefreplace')
  242. return item
  243. def build_keywords(self, title, refs, subitems):
  244. keywords = []
  245. title = htmlescape(title)
  246. # if len(refs) == 0: # XXX
  247. # write_param('See Also', title)
  248. if len(refs) == 1:
  249. keywords.append(self.keyword_item(title, refs[0]))
  250. elif len(refs) > 1:
  251. for i, ref in enumerate(refs): # XXX
  252. # item = (' '*12 +
  253. # '<keyword name="%s [%d]" ref="%s"/>' % (
  254. # title, i, ref))
  255. # item.encode('ascii', 'xmlcharrefreplace')
  256. # keywords.append(item)
  257. keywords.append(self.keyword_item(title, ref))
  258. if subitems:
  259. for subitem in subitems:
  260. keywords.extend(self.build_keywords(subitem[0], subitem[1], []))
  261. return keywords