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] 

89 

90 # mid 

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

92 if len(tag) == 0: 

93 raise ValueError("tag is empty") 

94 

95 def __(text): 

96 if text: 

97 return _(text) 

98 else: 

99 return "" 

100 

101 # book 

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

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

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

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

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

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

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

109 

110 indexes = [] 

111 if index: 

112 indexes.append(index) 

113 

114 # add a label 

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

116 if lid: 

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

118 else: 

119 tnl = [] 

120 

121 if author: 

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

123 indexes.append(author) 

124 if book: 

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

126 indexes.append(book) 

127 if pages: 

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

129 if date: 

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

131 if source: 

132 if source.startswith("http"): 

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

134 else: 

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

136 tnl.append('') 

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

138 tnl.append('') 

139 

140 content = StringList(tnl) 

141 content = content + self.content 

142 node = quote_node() 

143 

144 try: 

145 nested_parse_with_titles(self.state, content, node) 

146 except Exception as e: 

147 from sphinx.util import logging 

148 logger = logging.getLogger("blogpost") 

149 logger.warning( 

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

151 raise e 

152 

153 node['tag'] = tag 

154 node['author'] = author 

155 node['pages'] = pages 

156 node['year'] = year 

157 node['label'] = lid 

158 node['source'] = source 

159 node['book'] = book 

160 node['index'] = index 

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

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

163 

164 return [node] 

165 

166 

167def visit_quote_node(self, node): 

168 """ 

169 visit_quote_node 

170 """ 

171 self.visit_admonition(node) 

172 

173 

174def depart_quote_node(self, node): 

175 """ 

176 depart_quote_node, 

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

178 """ 

179 self.depart_admonition(node) 

180 

181 

182def visit_quote_node_rst(self, node): 

183 """ 

184 visit_quote_node 

185 """ 

186 self.new_state(0) 

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

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

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

190 continue 

191 if v: 

192 self.new_state(4) 

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

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

195 self.add_text(self.nl) 

196 self.new_state(4) 

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

198 self.end_state() 

199 self.end_state() 

200 raise nodes.SkipNode 

201 

202 

203def depart_quote_node_rst(self, node): 

204 """ 

205 depart_quote_node, 

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

207 """ 

208 pass 

209 

210 

211def setup(app): 

212 """ 

213 setup for ``mathdef`` (sphinx) 

214 """ 

215 if hasattr(app, "add_mapping"): 

216 app.add_mapping('quote', quote_node) 

217 

218 app.add_node(quote_node, 

219 html=(visit_quote_node, depart_quote_node), 

220 epub=(visit_quote_node, depart_quote_node), 

221 elatex=(visit_quote_node, depart_quote_node), 

222 latex=(visit_quote_node, depart_quote_node), 

223 text=(visit_quote_node, depart_quote_node), 

224 md=(visit_quote_node, depart_quote_node), 

225 rst=(visit_quote_node_rst, depart_quote_node_rst)) 

226 

227 app.add_directive('quote', QuoteNode) 

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