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
, __version__
as sphinx_ver
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_builder(DjangoStandaloneHTMLBuilder
)
68 class VersionDirective(Directive
):
70 required_arguments
= 1
71 optional_arguments
= 1
72 final_argument_whitespace
= True
76 env
= self
.state
.document
.settings
.env
77 arg0
= self
.arguments
[0]
78 is_nextversion
= env
.config
.django_next_version
== arg0
80 node
= addnodes
.versionmodified()
82 if not is_nextversion
:
83 if len(self
.arguments
) == 1:
84 linktext
= 'Please see the release notes </releases/%s>' % (arg0
)
85 xrefs
= roles
.XRefRole()('doc', linktext
, linktext
, self
.lineno
, self
.state
)
87 node
['version'] = arg0
89 node
['version'] = "Development version"
90 node
['type'] = self
.name
91 if len(self
.arguments
) == 2:
92 inodes
, messages
= self
.state
.inline_text(self
.arguments
[1], self
.lineno
+1)
95 self
.state
.nested_parse(self
.content
, self
.content_offset
, node
)
97 env
.note_versionchange(node
['type'], node
['version'], node
, self
.lineno
)
101 class DjangoHTMLTranslator(SmartyPantsHTMLTranslator
):
103 Django-specific reST to HTML tweaks.
106 # Don't use border=1, which docutils does by default.
107 def visit_table(self
, node
):
108 self
._table
_row
_index
= 0 # Needed by Sphinx
109 self
.body
.append(self
.starttag(node
, 'table', CLASS
='docutils'))
112 def visit_desc_parameterlist(self
, node
):
113 self
.body
.append('(')
115 self
.param_separator
= node
.child_text_separator
117 def depart_desc_parameterlist(self
, node
):
118 self
.body
.append(')')
120 if sphinx_ver
< '1.0.8':
122 # Don't apply smartypants to literal blocks
124 def visit_literal_block(self
, node
):
126 SmartyPantsHTMLTranslator
.visit_literal_block(self
, node
)
128 def depart_literal_block(self
, node
):
129 SmartyPantsHTMLTranslator
.depart_literal_block(self
, node
)
133 # Turn the "new in version" stuff (versionadded/versionchanged) into a
134 # better callout -- the Sphinx default is just a little span,
135 # which is a bit less obvious that I'd like.
137 # FIXME: these messages are all hardcoded in English. We need to change
138 # that to accomodate other language docs, but I can't work out how to make
142 'deprecated': 'Deprecated in Django %s',
143 'versionchanged': 'Changed in Django %s',
144 'versionadded': 'New in Django %s',
147 def visit_versionmodified(self
, node
):
149 self
.starttag(node
, 'div', CLASS
=node
['type'])
152 self
.version_text
[node
['type']] % node
['version'],
153 len(node
) and ":" or "."
155 self
.body
.append('<span class="title">%s</span> ' % title
)
157 def depart_versionmodified(self
, node
):
158 self
.body
.append("</div>\n")
160 # Give each section a unique ID -- nice for custom CSS hooks
161 def visit_section(self
, node
):
162 old_ids
= node
.get('ids', [])
163 node
['ids'] = ['s-' + i
for i
in old_ids
]
164 node
['ids'].extend(old_ids
)
165 SmartyPantsHTMLTranslator
.visit_section(self
, node
)
166 node
['ids'] = old_ids
168 def parse_django_admin_node(env
, sig
, signode
):
169 command
= sig
.split(' ')[0]
170 env
._django
_curr
_admin
_command
= command
171 title
= "django-admin.py %s" % sig
172 signode
+= addnodes
.desc_name(title
, title
)
175 def parse_django_adminopt_node(env
, sig
, signode
):
176 """A copy of sphinx.directives.CmdoptionDesc.parse_signature()"""
177 from sphinx
.domains
.std
import option_desc_re
180 for m
in option_desc_re
.finditer(sig
):
181 optname
, args
= m
.groups()
183 signode
+= addnodes
.desc_addname(', ', ', ')
184 signode
+= addnodes
.desc_name(optname
, optname
)
185 signode
+= addnodes
.desc_addname(args
, args
)
190 for m
in simple_option_desc_re
.finditer(sig
):
191 optname
, args
= m
.groups()
193 signode
+= addnodes
.desc_addname(', ', ', ')
194 signode
+= addnodes
.desc_name(optname
, optname
)
195 signode
+= addnodes
.desc_addname(args
, args
)
204 class DjangoStandaloneHTMLBuilder(StandaloneHTMLBuilder
):
206 Subclass to add some extra things we need.
212 super(DjangoStandaloneHTMLBuilder
, self
).finish()
214 self
.warn("cannot create templatebuiltins.js due to missing simplejson dependency")
216 self
.info(bold("writing templatebuiltins.js..."))
217 xrefs
= self
.env
.domaindata
["std"]["objects"]
219 "ttags": [n
for ((t
, n
), (l
, a
)) in xrefs
.items()
220 if t
== "templatetag" and l
== "ref/templates/builtins"],
221 "tfilters": [n
for ((t
, n
), (l
, a
)) in xrefs
.items()
222 if t
== "templatefilter" and l
== "ref/templates/builtins"],
224 outfilename
= os
.path
.join(self
.outdir
, "templatebuiltins.js")
225 f
= open(outfilename
, 'wb')
226 f
.write('var django_template_builtins = ')
227 json
.dump(templatebuiltins
, f
)