Add glossary directive and :term: role for crossreferencing into the glossary.

This commit is contained in:
Georg Brandl 2007-08-17 06:27:35 +00:00
parent a826246980
commit 12cfdea91f
9 changed files with 83 additions and 6 deletions

1
TODO
View File

@ -9,4 +9,3 @@ Global TODO
- look at the old tools/ scripts, what functionality should be rewritten
- add search via Xapian?
- optionally have a contents tree view in the sidebar (AJAX based)?
- .. caveat?

View File

@ -53,9 +53,13 @@ class highlightlang(nodes.Element): pass
# like emphasis, but doesn't apply further text processors, e.g. smartypants
class literal_emphasis(nodes.emphasis): pass
# glossary
class glossary(nodes.Element): pass
# make them known to docutils. this is needed, because the HTMl writer
# will choke at some point if these are not added
nodes._add_node_class_names("""index desc desc_content desc_signature
desc_classname desc_name desc_parameterlist desc_parameter desc_optional
centered versionmodified seealso productionlist production toctree
pending_xref compact_paragraph highlightlang""".split())
pending_xref compact_paragraph highlightlang literal_emphasis
glossary""".split())

View File

@ -579,3 +579,35 @@ def literalinclude_directive(name, arguments, options, content, lineno,
literalinclude_directive.content = 0
literalinclude_directive.arguments = (1, 0, 0)
directives.register_directive('literalinclude', literalinclude_directive)
# ------ glossary directive ---------------------------------------------------------
def glossary_directive(name, arguments, options, content, lineno,
content_offset, block_text, state, state_machine):
"""Glossary with cross-reference targets for :dfn: roles."""
env = state.document.settings.env
node = addnodes.glossary()
state.nested_parse(content, content_offset, node)
# the content should be definition lists
dls = [child for child in node if isinstance(child, nodes.definition_list)]
# now, extract definition terms to enable cross-reference creation
for dl in dls:
dl['classes'].append('glossary')
for li in dl.children:
if not li.children or not isinstance(li[0], nodes.term):
continue
termtext = li.children[0].astext()
new_id = 'term-' + nodes.make_id(termtext)
if new_id in env.gloss_entries:
new_id = 'term-' + str(len(env.gloss_entries))
env.gloss_entries.add(new_id)
li[0]['names'].append(new_id)
li[0]['ids'].append(new_id)
state.document.settings.env.note_glossaryterm(termtext, new_id)
return [node]
glossary_directive.content = 1
glossary_directive.arguments = (0, 0, 0)
directives.register_directive('glossary', glossary_directive)

View File

@ -52,7 +52,7 @@ default_settings = {
# This is increased every time a new environment attribute is added
# to properly invalidate pickle files.
ENV_VERSION = 10
ENV_VERSION = 11
def walk_depth(node, depth, maxdepth):
@ -206,6 +206,7 @@ class BuildEnvironment:
self.modules = {} # modname -> filename, synopsis, platform, deprecated
self.tokens = {} # tokenname -> filename
self.labels = {} # labelname -> filename, labelid
self.glossary = {} # term -> filename, labelid
# Other inventories
self.indexentries = {} # filename -> list of
@ -219,6 +220,7 @@ class BuildEnvironment:
self.currclass = None # current class name
self.currdesc = None # current descref name
self.index_num = 0 # autonumber for index targets
self.gloss_entries = set() # existing definition labels
def set_warning_stream(self, stream):
self.warning_stream = stream
@ -247,6 +249,9 @@ class BuildEnvironment:
for labelname, (fn, _, _) in self.labels.items():
if fn == filename:
del self.labels[labelname]
for term, (fn, _) in self.glossary.items():
if fn == filename:
del self.glossary[term]
self.indexentries.pop(filename, None)
for version, changes in self.versionchanges.items():
new = [change for change in changes if change[1] != filename]
@ -351,6 +356,8 @@ class BuildEnvironment:
self.filename = None
self.currmodule = None
self.currclass = None
self.indexnum = 0
self.gloss_entries = set()
if save_parsed:
# save the parsed doctree
@ -497,7 +504,6 @@ class BuildEnvironment:
def note_token(self, tokenname):
self.tokens[tokenname] = self.filename
def note_index_entry(self, type, string, targetid, aliasname):
self.indexentries.setdefault(self.filename, []).append(
(type, string, targetid, aliasname))
@ -505,6 +511,9 @@ class BuildEnvironment:
def note_versionchange(self, type, version, node):
self.versionchanges.setdefault(version, []).append(
(type, self.filename, self.currmodule, self.currdesc, node.deepcopy()))
def note_glossaryterm(self, text, labelname):
self.glossary[text] = (self.filename, labelname)
# -------
# --------- RESOLVING REFERENCES AND TOCTREES ------------------------------
@ -592,6 +601,20 @@ class BuildEnvironment:
newnode['refuri'] = builder.get_relative_uri(
docfilename, filename) + '#' + labelid
newnode.append(nodes.emphasis(sectname, sectname))
elif typ == 'term':
filename, labelid = self.glossary.get(target, ('', ''))
if not filename:
print >>self.warning_stream, \
'%s: term not in glossary: %s' % (docfilename, target)
newnode = contnode
else:
newnode = nodes.reference('', '')
if filename == docfilename:
newnode['refid'] = labelid
else:
newnode['refuri'] = builder.get_relative_uri(
docfilename, filename) + '#' + labelid
newnode.append(contnode)
elif typ == 'token':
filename = self.tokens.get(target, '')
if not filename:

View File

@ -20,7 +20,7 @@ ws_re = re.compile(r'\s+')
generic_docroles = {
'command' : nodes.strong,
'dfn' : addnodes.literal_emphasis,
'dfn' : addnodes.emphasis,
'guilabel' : nodes.strong,
'kbd' : nodes.literal,
'keyword' : nodes.literal,
@ -89,6 +89,7 @@ roles.register_local_role('rfc', indexmarkup_role)
# default is `literal`
innernodetypes = {
'ref': nodes.emphasis,
'term': nodes.emphasis,
'token': nodes.strong,
}
@ -106,7 +107,7 @@ def xfileref_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
typ in ('data', 'exc', 'func', 'class', 'const', 'attr', 'meth'):
text = text[1:]
pnode['refspecific'] = True
pnode['reftarget'] = ws_re.sub('', text)
pnode['reftarget'] = ws_re.sub((' ' if typ == 'term' else ''), text)
pnode['modname'] = env.currmodule
pnode['classname'] = env.currclass
pnode += innernodetypes.get(typ, nodes.literal)(rawtext, text, classes=['xref'])
@ -153,6 +154,7 @@ specific_docroles = {
'ref': xfileref_role,
'token' : xfileref_role,
'term': xfileref_role,
'menuselection' : menusel_role,
'file' : emph_literal_role,

View File

@ -691,6 +691,11 @@ dt:target,
background-color: #fbe54e;
}
dl.glossary dt {
font-weight: bold;
font-size: 1.1em;
}
th {
text-align: left;
padding-right: 5px;

View File

@ -591,6 +591,11 @@ dd {
margin-left: 30px;
}
dl.glossary dt {
font-weight: bold;
font-size: 1.1em;
}
.refcount {
color: #060;
}

View File

@ -44,6 +44,8 @@
<span class="linkdescr">quick access to all modules</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("genindex.rst") }}">General Index</a><br>
<span class="linkdescr">all functions, classes, terms</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("glossary.rst") }}">Glossary</a><br>
<span class="linkdescr">the most important terms explained</span></p>
</td><td width="50%">
<p class="biglink"><a class="biglink" href="{{ pathto("search.rst") }}">Search page</a><br>
<span class="linkdescr">search this documentation</span></p>

View File

@ -211,6 +211,11 @@ class HTMLTranslator(BaseTranslator):
def visit_index(self, node):
raise nodes.SkipNode
def visit_glossary(self, node):
pass
def depart_glossary(self, node):
pass
# these are only handled specially in the SmartyPantsHTMLTranslator
def visit_literal_emphasis(self, node):
return self.visit_emphasis(node)