Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1""" 

2@file 

3@brief Copy of `singlehtml.py <https://github.com/sphinx-doc/sphinx/blob/3.x/sphinx/builders/singlehtml.py>`_ 

4 

5Single HTML builders. 

6 

7:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. 

8:license: BSD, see LICENSE for details. 

9""" 

10 

11from os import path 

12from typing import Any, Dict, Tuple 

13from docutils import nodes 

14from docutils.nodes import Node 

15from sphinx.builders.html import StandaloneHTMLBuilder 

16from sphinx.environment.adapters.toctree import TocTree 

17from sphinx.locale import __ 

18from sphinx.util import logging 

19from sphinx.util import progress_message 

20from sphinx.util.console import darkgreen # type: ignore 

21from sphinx.util.nodes import inline_all_toctrees 

22 

23 

24class CustomSingleFileHTMLBuilder(StandaloneHTMLBuilder): 

25 """ 

26 A StandaloneHTMLBuilder subclass that puts the whole document tree on one 

27 HTML page. 

28 """ 

29 name = 'singlehtml' 

30 epilog = __('The HTML page is in %(outdir)s.') 

31 

32 copysource = False 

33 

34 def get_outdated_docs(self): 

35 return 'all documents' 

36 

37 def get_target_uri(self, docname: str, typ: str = None) -> str: 

38 if docname in self.env.all_docs: 

39 # all references are on the same page... 

40 return self.config.master_doc + self.out_suffix + \ 

41 '#document-' + docname 

42 else: 

43 # chances are this is a html_additional_page 

44 return docname + self.out_suffix 

45 

46 def get_relative_uri(self, from_: str, to: str, typ: str = None) -> str: 

47 # ignore source 

48 return self.get_target_uri(to, typ) 

49 

50 def fix_refuris(self, tree: Node) -> None: 

51 # fix refuris with double anchor 

52 fname = self.config.master_doc + self.out_suffix 

53 for refnode in tree.traverse(nodes.reference): 

54 if 'refuri' not in refnode: 

55 continue 

56 refuri = refnode['refuri'] 

57 hashindex = refuri.find('#') 

58 if hashindex < 0: 

59 continue 

60 hashindex = refuri.find('#', hashindex + 1) 

61 if hashindex >= 0: 

62 refnode['refuri'] = fname + refuri[hashindex:] 

63 

64 def _get_local_toctree(self, docname: str, collapse: bool = True, **kwargs: Any) -> str: 

65 if 'includehidden' not in kwargs: 

66 kwargs['includehidden'] = False 

67 toctree = TocTree(self.env).get_toctree_for( 

68 docname, self, collapse, **kwargs) 

69 if toctree is not None: 

70 self.fix_refuris(toctree) 

71 return self.render_partial(toctree)['fragment'] 

72 

73 def assemble_doctree(self) -> nodes.document: 

74 master = self.config.master_doc 

75 tree = self.env.get_doctree(master) 

76 tree = inline_all_toctrees( 

77 self, set(), master, tree, darkgreen, [master]) 

78 tree['docname'] = master 

79 self.env.resolve_references(tree, master, self) 

80 self.fix_refuris(tree) 

81 return tree 

82 

83 def assemble_toc_secnumbers(self) -> Dict[str, Dict[str, Tuple[int, ...]]]: 

84 # Assemble toc_secnumbers to resolve section numbers on SingleHTML. 

85 # Merge all secnumbers to single secnumber. 

86 # 

87 # Note: current Sphinx has refid confliction in singlehtml mode. 

88 # To avoid the problem, it replaces key of secnumbers to 

89 # tuple of docname and refid. 

90 # 

91 # There are related codes in inline_all_toctres() and 

92 # HTMLTranslter#add_secnumber(). 

93 new_secnumbers = {} # type: Dict[str, Tuple[int, ...]] 

94 for docname, secnums in self.env.toc_secnumbers.items(): 

95 for id, secnum in secnums.items(): 

96 alias = "%s/%s" % (docname, id) 

97 new_secnumbers[alias] = secnum 

98 

99 return {self.config.master_doc: new_secnumbers} 

100 

101 def assemble_toc_fignumbers(self) -> Dict[str, Dict[str, Dict[str, Tuple[int, ...]]]]: 

102 # Assemble toc_fignumbers to resolve figure numbers on SingleHTML. 

103 # Merge all fignumbers to single fignumber. 

104 # 

105 # Note: current Sphinx has refid confliction in singlehtml mode. 

106 # To avoid the problem, it replaces key of secnumbers to 

107 # tuple of docname and refid. 

108 # 

109 # There are related codes in inline_all_toctres() and 

110 # HTMLTranslter#add_fignumber(). 

111 new_fignumbers = {} # type: Dict[str, Dict[str, Tuple[int, ...]]] 

112 # {'foo': {'figure': {'id2': (2,), 'id1': (1,)}}, 'bar': {'figure': {'id1': (3,)}}} 

113 for docname, fignumlist in self.env.toc_fignumbers.items(): 

114 for figtype, fignums in fignumlist.items(): 

115 alias = "%s/%s" % (docname, figtype) 

116 new_fignumbers.setdefault(alias, {}) 

117 for id, fignum in fignums.items(): 

118 new_fignumbers[alias][id] = fignum 

119 

120 return {self.config.master_doc: new_fignumbers} 

121 

122 def get_doc_context(self, docname: str, body: str, metatags: str) -> Dict: 

123 # no relation links... 

124 toctree = TocTree(self.env).get_toctree_for( 

125 self.config.master_doc, self, False) 

126 # if there is no toctree, toc is None 

127 if toctree: 

128 self.fix_refuris(toctree) 

129 toc = self.render_partial(toctree)['fragment'] 

130 display_toc = True 

131 else: 

132 toc = '' 

133 display_toc = False 

134 return { 

135 'parents': [], 

136 'prev': None, 

137 'next': None, 

138 'docstitle': None, 

139 'title': self.config.html_title, 

140 'meta': None, 

141 'body': body, 

142 'metatags': metatags, 

143 'rellinks': [], 

144 'sourcename': '', 

145 'toc': toc, 

146 'display_toc': display_toc, 

147 } 

148 

149 def write(self, *ignored: Any) -> None: # pylint: disable=W0221,W0222 

150 docnames = self.env.all_docs 

151 

152 with progress_message(__('preparing documents')): 

153 self.prepare_writing(docnames) # type: ignore 

154 

155 with progress_message(__('assembling single document')): 

156 doctree = self.assemble_doctree() 

157 self.env.toc_secnumbers = self.assemble_toc_secnumbers() 

158 self.env.toc_fignumbers = self.assemble_toc_fignumbers() 

159 

160 with progress_message(__('writing')): 

161 self.write_doc_serialized(self.config.master_doc, doctree) 

162 self.write_doc(self.config.master_doc, doctree) 

163 

164 def finish(self) -> None: 

165 self.write_additional_files() 

166 self.copy_image_files() 

167 self.copy_download_files() 

168 self.copy_static_files() 

169 self.copy_extra_files() 

170 self.write_buildinfo() 

171 self.dump_inventory() 

172 

173 @progress_message(__('writing additional files')) 

174 def write_additional_files(self) -> None: 

175 # no indices or search pages are supported 

176 logger = logging.getLogger(__name__) 

177 

178 # additional pages from conf.py 

179 for pagename, template in self.config.html_additional_pages.items(): 

180 logger.info(' ' + pagename, nonl=True) 

181 self.handle_page(pagename, {}, template) 

182 

183 if self.config.html_use_opensearch: 

184 logger.info(' opensearch', nonl=True) 

185 fn = path.join(self.outdir, '_static', 'opensearch.xml') 

186 self.handle_page('opensearch', {}, 

187 'opensearch.xml', outfilename=fn)