rst/options_node.py (164 lines of code) (raw):
from docutils import nodes
from sphinx.errors import SphinxError
from docutils.nodes import fully_normalize_name as normalize_name
from docutils.parsers.rst import Directive
from itertools import groupby
#import sphinx.ext.doctest
#from sphinx.directives import CodeBlock
#from sphinx.util import parselinenos
#from sphinx.util.nodes import set_source_info
#from docutils.transforms import Transform
#from docutils.transforms.parts import ContentsFilter
class OptionsNodesError(SphinxError):
category = "OptionsNode error"
class OptionInfo(nodes.section, nodes.Element):
pass
class OptionsList(nodes.General, nodes.Element):
pass
def visit_optioninfo_node(self, node):
self.visit_section(node)
def depart_optioninfo_node(self, node):
self.depart_section(node)
class OptionsDirective(Directive):
has_content = True
required_arguments = 0
optional_arguments = 4
option_spec = dict(
name = str,
type = str,
default = str,
short = str
)
def make_field(self, name, content):
fieldname = nodes.field_name('', name)
fieldbody = nodes.field_body('', nodes.paragraph('', '', content))
return nodes.field('', fieldname, fieldbody)
def run(self):
name = self.options.get('name')
env = self.state.document.settings.env
targetid = "indigo-option-%d" % env.new_serialno('indigo-option')
targetnode = nodes.target('', '', ids=[targetid])
section_node = OptionInfo()
section_node['names'].append(normalize_name(name))
section_node['ids'].append(normalize_name(name))
#titlenode = nodes.title('', name + ' = ' + self.options.get('default'))
titlenode = nodes.title('', name)
section_node += titlenode
new_list = nodes.field_list()
new_list += self.make_field('type', nodes.Text(self.options.get('type')))
new_list += self.make_field('default', nodes.Text(self.options.get('default')))
new_list += self.make_field('description', nodes.Text(self.options.get('short')))
section_node += new_list
text = '\n'.join(self.content)
if text:
self.state.nested_parse(self.content, self.content_offset, section_node)
if not hasattr(env, 'indigo_options'):
env.indigo_options = []
env.indigo_options.append({
'docname': env.docname,
'lineno': self.lineno,
'name': name,
'type': self.options.get('type'),
'default': self.options.get('default'),
'short':self.options.get('short'),
'target': targetnode
})
return [ targetnode, section_node ]
def purge_indigo_options(app, env, docname):
if not hasattr(env, 'indigo_options'):
return
env.indigo_options = [opt for opt in env.indigo_options
if opt['docname'] != docname]
def create_row_entry (node):
entry = nodes.entry()
paragraph = nodes.paragraph()
paragraph += node
entry += paragraph
return entry
def create_row_entry_text (text):
return create_row_entry(nodes.Text(text))
def create_options_table(content):
tbl = nodes.table()
tgroup = nodes.tgroup(cols=4)
tbl += tgroup
tgroup += nodes.colspec(colwidth=35)
tgroup += nodes.colspec(colwidth=9)
tgroup += nodes.colspec(colwidth=73)
tgroup += nodes.colspec(colwidth=9)
thead = nodes.thead()
tgroup += thead
row = nodes.row()
thead += row
row += create_row_entry_text('Name')
row += create_row_entry_text('Type')
row += create_row_entry_text('Short description')
row += create_row_entry_text('Default')
tbody = nodes.tbody()
tgroup += tbody
content.append(tbl)
return tbody
def get_title(title_str):
t = str(title_str).strip()
if t.startswith('<title>'):
end_s = t.find('</title>')
t=t[len('<title>'):end_s]
return t
def process_indigo_option_nodes(app, doctree, fromdocname):
env = app.builder.env
for node in doctree.traverse(OptionsList):
content = []
#sorted_options = sorted(env.indigo_options, key=lambda o:o['name'])
for op_group,s_options in groupby(env.indigo_options, key=lambda o:get_title(env.titles[o['docname']])):
#group = nodes.title('', op_group)
#print(op_group)
#for opt_info in s_options:
# print(opt_info)
#sorted_options = list(s_options)
#print(str(sorted_options))
#group.source = op_group
#group.setText(op_group)
#group=nodes.rubric('', op_group)
#group.append(nodes.Text(op_group))
#content.append(group)
section_node = OptionInfo()
options_name = op_group
section_node['names'].append(options_name)
section_node['ids'].append(options_name)
titlenode = nodes.title('', options_name)
section_node += titlenode
tbody = create_options_table(section_node)
content.append(section_node)
for opt_info in s_options:
row = nodes.row()
tbody.append(row)
# Create a reference
newnode = nodes.reference('', '')
innernode = nodes.Text(opt_info['name'], opt_info['name'])
newnode['refdocname'] = opt_info['docname']
newnode['refuri'] = app.builder.get_relative_uri(
fromdocname, opt_info['docname'])
newnode['refuri'] += '#' + normalize_name(opt_info['name'])
newnode['classes'].append('option')
newnode.append(innernode)
row += create_row_entry(newnode)
row += create_row_entry_text(opt_info['type'])
row += create_row_entry_text(opt_info['short'])
row += create_row_entry_text(opt_info['default'])
node.replace_self(content)
class OptionsTableDirective(Directive):
has_content = False
required_arguments = 0
optional_arguments = 0
option_spec = dict()
def run(self):
optlist = OptionsList('')
env = self.state.document.settings.env
optlist['docname'] = env.docname
return [ optlist ]
def indigo_option_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
"""Link to an Indigo option
Returns 2 part tuple containing list of nodes to insert into the
document and a list of system messages. Both are allowed to be
empty.
:param name: The role name used in the document.
:param rawtext: The entire markup snippet, with role.
:param text: The text marked with the role.
:param lineno: The line number where rawtext appears in the input.
:param inliner: The inliner instance that called us.
:param options: Directive options for customization.
:param content: The directive content for customization.
"""
env = inliner.document.settings.env
app = env.app
opts = [opt for opt in env.indigo_options if opt['name'] == text]
if len(opts) == 0:
raise ValueError("Cannot find option " + slug)
opt_info = opts[0]
newnode = nodes.reference('', '')
innernode = nodes.Text(opt_info['name'], opt_info['name'])
newnode['refdocname'] = opt_info['docname']
newnode['refuri'] = app.builder.get_relative_uri(
env.docname, opt_info['docname'])
newnode['refuri'] += '#' + normalize_name(opt_info['name'])
newnode['classes'].append('option')
newnode.append(innernode)
return [newnode], []
def setup(app):
app.add_directive('indigo_option', OptionsDirective)
app.add_directive('indigo_options_table', OptionsTableDirective)
app.add_node(OptionsList)
app.add_node(OptionInfo,
html=(visit_optioninfo_node, depart_optioninfo_node),
latex=(visit_optioninfo_node, depart_optioninfo_node),
text=(visit_optioninfo_node, depart_optioninfo_node))
app.connect('doctree-resolved', process_indigo_option_nodes)
app.connect('env-purge-doc', purge_indigo_options)
app.add_role('optref', indigo_option_role)