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# -*- coding: utf-8 -*- 

2""" 

3@file 

4@brief Defines a :epkg:`sphinx` extension for a quote. 

5""" 

6from docutils import nodes 

7from docutils.parsers.rst import directives 

8 

9import sphinx 

10from sphinx.locale import _ 

11from docutils.parsers.rst.directives.admonitions import BaseAdmonition 

12from docutils.statemachine import StringList 

13from sphinx.util.nodes import nested_parse_with_titles 

14 

15 

16class quote_node(nodes.admonition): 

17 """ 

18 Defines ``quote`` node. 

19 """ 

20 pass 

21 

22 

23class QuoteNode(BaseAdmonition): 

24 """ 

25 A ``quotedef`` entry, displayed in the form of an admonition. 

26 It takes the following options: 

27 

28 * *author* 

29 * *book* 

30 * *year* 

31 * *pages* 

32 * *tag* 

33 * *source* 

34 * *lid* or *label* 

35 * *index*, additional index words beside the title and the author 

36 * *date*, if the text was written or declared at specific date 

37 

38 Example:: 

39 

40 .. quote:: 

41 :author: author 

42 :book: book 

43 :year: year 

44 :pages: pages (optional) 

45 :tag: something 

46 :lid: id (used for further reference) 

47 :source: optional 

48 :index: word 

49 

50 A monkey could... 

51 """ 

52 

53 node_class = quote_node 

54 has_content = True 

55 required_arguments = 0 

56 optional_arguments = 0 

57 final_argument_whitespace = False 

58 option_spec = { 

59 'author': directives.unchanged, 

60 'book': directives.unchanged, 

61 'year': directives.unchanged, 

62 'pages': directives.unchanged, 

63 'tag': directives.unchanged, 

64 'lid': directives.unchanged, 

65 'label': directives.unchanged, 

66 'source': directives.unchanged, 

67 'class': directives.class_option, 

68 'index': directives.unchanged, 

69 'date': directives.unchanged, 

70 } 

71 

72 def run(self): 

73 """ 

74 Builds the mathdef text. 

75 """ 

76 env = self.state.document.settings.env if hasattr( 

77 self.state.document.settings, "env") else None 

78 docname = None if env is None else env.docname 

79 if docname is not None: 

80 docname = docname.replace("\\", "/").split("/")[-1] 

81 

82 if not self.options.get('class'): 

83 self.options['class'] = ['admonition-quote'] 

84 

85 # body 

86 (quote,) = super(QuoteNode, self).run() 

87 if isinstance(quote, nodes.system_message): 

88 return [quote] # pragma: no cover 

89 

90 # mid 

91 tag = self.options.get('tag', 'quotetag').strip() 

92 if len(tag) == 0: 

93 raise ValueError("tag is empty") # pragma: no cover 

94 

95 def __(text): 

96 if text: 

97 return _(text) 

98 return "" 

99 

100 # book 

101 author = __(self.options.get('author', "").strip()) 

102 book = __(self.options.get('book', "").strip()) 

103 pages = __(self.options.get('pages', "").strip()) 

104 year = __(self.options.get('year', "").strip()) 

105 source = __(self.options.get('source', "").strip()) 

106 index = __(self.options.get('index', "").strip()) 

107 date = __(self.options.get('date', "").strip()) 

108 

109 indexes = [] 

110 if index: 

111 indexes.append(index) # pragma: no cover 

112 

113 # add a label 

114 lid = self.options.get('lid', self.options.get('label', None)) 

115 if lid: 

116 tnl = ['', ".. _{0}:".format(lid), ""] 

117 else: 

118 tnl = [] # pragma: no cover 

119 

120 if author: 

121 tnl.append("**{0}**, ".format(author)) 

122 indexes.append(author) 

123 if book: 

124 tnl.append("*{0}*".format(book)) 

125 indexes.append(book) 

126 if pages: 

127 tnl.append(", {0}".format(pages)) 

128 if date: 

129 tnl.append(" ({0})".format(date)) 

130 if source: 

131 if source.startswith("http"): 

132 tnl.append(", `source <{0}>`_".format(source)) 

133 else: 

134 tnl.append(", {0}".format(source)) 

135 tnl.append('') 

136 tnl.append(".. index:: " + ", ".join(indexes)) 

137 tnl.append('') 

138 

139 content = StringList(tnl) 

140 content = content + self.content 

141 node = quote_node() 

142 

143 try: 

144 nested_parse_with_titles(self.state, content, node) 

145 except Exception as e: # pragma: no cover 

146 from sphinx.util import logging 

147 logger = logging.getLogger("blogpost") 

148 logger.warning( 

149 "[blogpost] unable to parse '{0}' - '{1}' - {2}".format(author, book, e)) 

150 raise e 

151 

152 node['tag'] = tag 

153 node['author'] = author 

154 node['pages'] = pages 

155 node['year'] = year 

156 node['label'] = lid 

157 node['source'] = source 

158 node['book'] = book 

159 node['index'] = index 

160 node['content'] = '\n'.join(self.content) 

161 node['classes'] += ["quote"] 

162 

163 return [node] 

164 

165 

166def visit_quote_node(self, node): 

167 """ 

168 visit_quote_node 

169 """ 

170 self.visit_admonition(node) 

171 

172 

173def depart_quote_node(self, node): 

174 """ 

175 depart_quote_node, 

176 see https://github.com/sphinx-doc/sphinx/blob/master/sphinx/writers/html.py 

177 """ 

178 self.depart_admonition(node) 

179 

180 

181def visit_quote_node_rst(self, node): 

182 """ 

183 visit_quote_node 

184 """ 

185 self.new_state(0) 

186 self.add_text(".. quote::") 

187 for k, v in sorted(node.attributes.items()): 

188 if k in ("content", 'classes'): 

189 continue 

190 if v: 

191 self.new_state(4) 

192 self.add_text(":{0}: {1}".format(k, v)) 

193 self.end_state(wrap=False, end=None) 

194 self.add_text(self.nl) 

195 self.new_state(4) 

196 self.add_text(node['content']) 

197 self.end_state() 

198 self.end_state() 

199 raise nodes.SkipNode 

200 

201 

202def depart_quote_node_rst(self, node): 

203 """ 

204 depart_quote_node, 

205 see https://github.com/sphinx-doc/sphinx/blob/master/sphinx/writers/html.py 

206 """ 

207 pass 

208 

209 

210def setup(app): 

211 """ 

212 setup for ``mathdef`` (sphinx) 

213 """ 

214 if hasattr(app, "add_mapping"): 

215 app.add_mapping('quote', quote_node) 

216 

217 app.add_node(quote_node, 

218 html=(visit_quote_node, depart_quote_node), 

219 epub=(visit_quote_node, depart_quote_node), 

220 elatex=(visit_quote_node, depart_quote_node), 

221 latex=(visit_quote_node, depart_quote_node), 

222 text=(visit_quote_node, depart_quote_node), 

223 md=(visit_quote_node, depart_quote_node), 

224 rst=(visit_quote_node_rst, depart_quote_node_rst)) 

225 

226 app.add_directive('quote', QuoteNode) 

227 return {'version': sphinx.__display_version__, 'parallel_read_safe': True}