2 Sphinx plugins for Django documentation.
7 from docutils import nodes, transforms
12 import simplejson as json
15 from django.utils import simplejson as json
19 from sphinx import addnodes, roles
20 from sphinx.builders.html import StandaloneHTMLBuilder
21 from sphinx.writers.html import SmartyPantsHTMLTranslator
22 from sphinx.util.console import bold
23 from sphinx.util.compat import Directive
25 # RE for option descriptions without a '--' prefix
26 simple_option_desc_re = re.compile(
27 r'([-_a-zA-Z0-9]+)(\s*.*?)(?=,\s+(?:/|-|--)|$)')
30 app.add_crossref_type(
31 directivename = "setting",
33 indextemplate = "pair: %s; setting",
35 app.add_crossref_type(
36 directivename = "templatetag",
38 indextemplate = "pair: %s; template tag"
40 app.add_crossref_type(
41 directivename = "templatefilter",
43 indextemplate = "pair: %s; template filter"
45 app.add_crossref_type(
46 directivename = "fieldlookup",
48 indextemplate = "pair: %s; field lookup type",
50 app.add_description_unit(
51 directivename = "django-admin",
53 indextemplate = "pair: %s; django-admin command",
54 parse_node = parse_django_admin_node,
56 app.add_description_unit(
57 directivename = "django-admin-option",
58 rolename = "djadminopt",
59 indextemplate = "pair: %s; django-admin command-line option",
60 parse_node = parse_django_adminopt_node,
62 app.add_config_value('django_next_version', '0.0', True)
63 app.add_directive('versionadded', VersionDirective)
64 app.add_directive('versionchanged', VersionDirective)
65 app.add_transform(SuppressBlockquotes)
66 app.add_builder(DjangoStandaloneHTMLBuilder)
69 class VersionDirective(Directive):
71 required_arguments = 1
72 optional_arguments = 1
73 final_argument_whitespace = True
77 env = self.state.document.settings.env
78 arg0 = self.arguments[0]
79 is_nextversion = env.config.django_next_version == arg0
81 node = addnodes.versionmodified()
83 if not is_nextversion:
84 if len(self.arguments) == 1:
85 linktext = 'Please, see the release notes </releases/%s>' % (arg0)
86 xrefs = roles.XRefRole()('doc', linktext, linktext, self.lineno, self.state)
88 node['version'] = arg0
90 node['version'] = "Development version"
91 node['type'] = self.name
92 if len(self.arguments) == 2:
93 inodes, messages = self.state.inline_text(self.arguments[1], self.lineno+1)
96 self.state.nested_parse(self.content, self.content_offset, node)
98 env.note_versionchange(node['type'], node['version'], node, self.lineno)
102 class SuppressBlockquotes(transforms.Transform):
104 Remove the default blockquotes that encase indented list, tables, etc.
106 default_priority = 300
108 suppress_blockquote_child_nodes = (
110 nodes.enumerated_list,
111 nodes.definition_list,
119 for node in self.document.traverse(nodes.block_quote):
120 if len(node.children) == 1 and isinstance(node.children[0], self.suppress_blockquote_child_nodes):
121 node.replace_self(node.children[0])
123 class DjangoHTMLTranslator(SmartyPantsHTMLTranslator):
125 Django-specific reST to HTML tweaks.
128 # Don't use border=1, which docutils does by default.
129 def visit_table(self, node):
130 self.body.append(self.starttag(node, 'table', CLASS='docutils'))
133 def visit_desc_parameterlist(self, node):
134 self.body.append('(')
137 def depart_desc_parameterlist(self, node):
138 self.body.append(')')
141 # Don't apply smartypants to literal blocks
143 def visit_literal_block(self, node):
145 SmartyPantsHTMLTranslator.visit_literal_block(self, node)
147 def depart_literal_block(self, node):
148 SmartyPantsHTMLTranslator.depart_literal_block(self, node)
152 # Turn the "new in version" stuff (versionadded/versionchanged) into a
153 # better callout -- the Sphinx default is just a little span,
154 # which is a bit less obvious that I'd like.
156 # FIXME: these messages are all hardcoded in English. We need to change
157 # that to accomodate other language docs, but I can't work out how to make
161 'deprecated': 'Deprecated in Django %s',
162 'versionchanged': 'Changed in Django %s',
163 'versionadded': 'New in Django %s',
166 def visit_versionmodified(self, node):
168 self.starttag(node, 'div', CLASS=node['type'])
171 self.version_text[node['type']] % node['version'],
172 len(node) and ":" or "."
174 self.body.append('<span class="title">%s</span> ' % title)
176 def depart_versionmodified(self, node):
177 self.body.append("</div>\n")
179 # Give each section a unique ID -- nice for custom CSS hooks
180 def visit_section(self, node):
181 old_ids = node.get('ids', [])
182 node['ids'] = ['s-' + i for i in old_ids]
183 node['ids'].extend(old_ids)
184 SmartyPantsHTMLTranslator.visit_section(self, node)
185 node['ids'] = old_ids
187 def parse_django_admin_node(env, sig, signode):
188 command = sig.split(' ')[0]
189 env._django_curr_admin_command = command
190 title = "django-admin.py %s" % sig
191 signode += addnodes.desc_name(title, title)
194 def parse_django_adminopt_node(env, sig, signode):
195 """A copy of sphinx.directives.CmdoptionDesc.parse_signature()"""
196 from sphinx.domains.std import option_desc_re
199 for m in option_desc_re.finditer(sig):
200 optname, args = m.groups()
202 signode += addnodes.desc_addname(', ', ', ')
203 signode += addnodes.desc_name(optname, optname)
204 signode += addnodes.desc_addname(args, args)
209 for m in simple_option_desc_re.finditer(sig):
210 optname, args = m.groups()
212 signode += addnodes.desc_addname(', ', ', ')
213 signode += addnodes.desc_name(optname, optname)
214 signode += addnodes.desc_addname(args, args)
223 class DjangoStandaloneHTMLBuilder(StandaloneHTMLBuilder):
225 Subclass to add some extra things we need.
231 super(DjangoStandaloneHTMLBuilder, self).finish()
233 self.warn("cannot create templatebuiltins.js due to missing simplejson dependency")
235 self.info(bold("writing templatebuiltins.js..."))
236 xrefs = self.env.domaindata["std"]["objects"]
238 "ttags": [n for ((t, n), (l, a)) in xrefs.items()
239 if t == "templatetag" and l == "ref/templates/builtins"],
240 "tfilters": [n for ((t, n), (l, a)) in xrefs.items()
241 if t == "templatefilter" and l == "ref/templates/builtins"],
243 outfilename = os.path.join(self.outdir, "templatebuiltins.js")
244 f = open(outfilename, 'wb')
245 f.write('var django_template_builtins = ')
246 json.dump(templatebuiltins, f)