mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Add glossary directive and :term: role for crossreferencing into the glossary.
This commit is contained in:
parent
a826246980
commit
12cfdea91f
1
TODO
1
TODO
@ -9,4 +9,3 @@ Global TODO
|
|||||||
- look at the old tools/ scripts, what functionality should be rewritten
|
- look at the old tools/ scripts, what functionality should be rewritten
|
||||||
- add search via Xapian?
|
- add search via Xapian?
|
||||||
- optionally have a contents tree view in the sidebar (AJAX based)?
|
- optionally have a contents tree view in the sidebar (AJAX based)?
|
||||||
- .. caveat?
|
|
@ -53,9 +53,13 @@ class highlightlang(nodes.Element): pass
|
|||||||
# like emphasis, but doesn't apply further text processors, e.g. smartypants
|
# like emphasis, but doesn't apply further text processors, e.g. smartypants
|
||||||
class literal_emphasis(nodes.emphasis): pass
|
class literal_emphasis(nodes.emphasis): pass
|
||||||
|
|
||||||
|
# glossary
|
||||||
|
class glossary(nodes.Element): pass
|
||||||
|
|
||||||
# make them known to docutils. this is needed, because the HTMl writer
|
# make them known to docutils. this is needed, because the HTMl writer
|
||||||
# will choke at some point if these are not added
|
# will choke at some point if these are not added
|
||||||
nodes._add_node_class_names("""index desc desc_content desc_signature
|
nodes._add_node_class_names("""index desc desc_content desc_signature
|
||||||
desc_classname desc_name desc_parameterlist desc_parameter desc_optional
|
desc_classname desc_name desc_parameterlist desc_parameter desc_optional
|
||||||
centered versionmodified seealso productionlist production toctree
|
centered versionmodified seealso productionlist production toctree
|
||||||
pending_xref compact_paragraph highlightlang""".split())
|
pending_xref compact_paragraph highlightlang literal_emphasis
|
||||||
|
glossary""".split())
|
||||||
|
@ -579,3 +579,35 @@ def literalinclude_directive(name, arguments, options, content, lineno,
|
|||||||
literalinclude_directive.content = 0
|
literalinclude_directive.content = 0
|
||||||
literalinclude_directive.arguments = (1, 0, 0)
|
literalinclude_directive.arguments = (1, 0, 0)
|
||||||
directives.register_directive('literalinclude', literalinclude_directive)
|
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)
|
||||||
|
@ -52,7 +52,7 @@ default_settings = {
|
|||||||
|
|
||||||
# This is increased every time a new environment attribute is added
|
# This is increased every time a new environment attribute is added
|
||||||
# to properly invalidate pickle files.
|
# to properly invalidate pickle files.
|
||||||
ENV_VERSION = 10
|
ENV_VERSION = 11
|
||||||
|
|
||||||
|
|
||||||
def walk_depth(node, depth, maxdepth):
|
def walk_depth(node, depth, maxdepth):
|
||||||
@ -206,6 +206,7 @@ class BuildEnvironment:
|
|||||||
self.modules = {} # modname -> filename, synopsis, platform, deprecated
|
self.modules = {} # modname -> filename, synopsis, platform, deprecated
|
||||||
self.tokens = {} # tokenname -> filename
|
self.tokens = {} # tokenname -> filename
|
||||||
self.labels = {} # labelname -> filename, labelid
|
self.labels = {} # labelname -> filename, labelid
|
||||||
|
self.glossary = {} # term -> filename, labelid
|
||||||
|
|
||||||
# Other inventories
|
# Other inventories
|
||||||
self.indexentries = {} # filename -> list of
|
self.indexentries = {} # filename -> list of
|
||||||
@ -219,6 +220,7 @@ class BuildEnvironment:
|
|||||||
self.currclass = None # current class name
|
self.currclass = None # current class name
|
||||||
self.currdesc = None # current descref name
|
self.currdesc = None # current descref name
|
||||||
self.index_num = 0 # autonumber for index targets
|
self.index_num = 0 # autonumber for index targets
|
||||||
|
self.gloss_entries = set() # existing definition labels
|
||||||
|
|
||||||
def set_warning_stream(self, stream):
|
def set_warning_stream(self, stream):
|
||||||
self.warning_stream = stream
|
self.warning_stream = stream
|
||||||
@ -247,6 +249,9 @@ class BuildEnvironment:
|
|||||||
for labelname, (fn, _, _) in self.labels.items():
|
for labelname, (fn, _, _) in self.labels.items():
|
||||||
if fn == filename:
|
if fn == filename:
|
||||||
del self.labels[labelname]
|
del self.labels[labelname]
|
||||||
|
for term, (fn, _) in self.glossary.items():
|
||||||
|
if fn == filename:
|
||||||
|
del self.glossary[term]
|
||||||
self.indexentries.pop(filename, None)
|
self.indexentries.pop(filename, None)
|
||||||
for version, changes in self.versionchanges.items():
|
for version, changes in self.versionchanges.items():
|
||||||
new = [change for change in changes if change[1] != filename]
|
new = [change for change in changes if change[1] != filename]
|
||||||
@ -351,6 +356,8 @@ class BuildEnvironment:
|
|||||||
self.filename = None
|
self.filename = None
|
||||||
self.currmodule = None
|
self.currmodule = None
|
||||||
self.currclass = None
|
self.currclass = None
|
||||||
|
self.indexnum = 0
|
||||||
|
self.gloss_entries = set()
|
||||||
|
|
||||||
if save_parsed:
|
if save_parsed:
|
||||||
# save the parsed doctree
|
# save the parsed doctree
|
||||||
@ -497,7 +504,6 @@ class BuildEnvironment:
|
|||||||
def note_token(self, tokenname):
|
def note_token(self, tokenname):
|
||||||
self.tokens[tokenname] = self.filename
|
self.tokens[tokenname] = self.filename
|
||||||
|
|
||||||
|
|
||||||
def note_index_entry(self, type, string, targetid, aliasname):
|
def note_index_entry(self, type, string, targetid, aliasname):
|
||||||
self.indexentries.setdefault(self.filename, []).append(
|
self.indexentries.setdefault(self.filename, []).append(
|
||||||
(type, string, targetid, aliasname))
|
(type, string, targetid, aliasname))
|
||||||
@ -505,6 +511,9 @@ class BuildEnvironment:
|
|||||||
def note_versionchange(self, type, version, node):
|
def note_versionchange(self, type, version, node):
|
||||||
self.versionchanges.setdefault(version, []).append(
|
self.versionchanges.setdefault(version, []).append(
|
||||||
(type, self.filename, self.currmodule, self.currdesc, node.deepcopy()))
|
(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 ------------------------------
|
# --------- RESOLVING REFERENCES AND TOCTREES ------------------------------
|
||||||
@ -592,6 +601,20 @@ class BuildEnvironment:
|
|||||||
newnode['refuri'] = builder.get_relative_uri(
|
newnode['refuri'] = builder.get_relative_uri(
|
||||||
docfilename, filename) + '#' + labelid
|
docfilename, filename) + '#' + labelid
|
||||||
newnode.append(nodes.emphasis(sectname, sectname))
|
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':
|
elif typ == 'token':
|
||||||
filename = self.tokens.get(target, '')
|
filename = self.tokens.get(target, '')
|
||||||
if not filename:
|
if not filename:
|
||||||
|
@ -20,7 +20,7 @@ ws_re = re.compile(r'\s+')
|
|||||||
|
|
||||||
generic_docroles = {
|
generic_docroles = {
|
||||||
'command' : nodes.strong,
|
'command' : nodes.strong,
|
||||||
'dfn' : addnodes.literal_emphasis,
|
'dfn' : addnodes.emphasis,
|
||||||
'guilabel' : nodes.strong,
|
'guilabel' : nodes.strong,
|
||||||
'kbd' : nodes.literal,
|
'kbd' : nodes.literal,
|
||||||
'keyword' : nodes.literal,
|
'keyword' : nodes.literal,
|
||||||
@ -89,6 +89,7 @@ roles.register_local_role('rfc', indexmarkup_role)
|
|||||||
# default is `literal`
|
# default is `literal`
|
||||||
innernodetypes = {
|
innernodetypes = {
|
||||||
'ref': nodes.emphasis,
|
'ref': nodes.emphasis,
|
||||||
|
'term': nodes.emphasis,
|
||||||
'token': nodes.strong,
|
'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'):
|
typ in ('data', 'exc', 'func', 'class', 'const', 'attr', 'meth'):
|
||||||
text = text[1:]
|
text = text[1:]
|
||||||
pnode['refspecific'] = True
|
pnode['refspecific'] = True
|
||||||
pnode['reftarget'] = ws_re.sub('', text)
|
pnode['reftarget'] = ws_re.sub((' ' if typ == 'term' else ''), text)
|
||||||
pnode['modname'] = env.currmodule
|
pnode['modname'] = env.currmodule
|
||||||
pnode['classname'] = env.currclass
|
pnode['classname'] = env.currclass
|
||||||
pnode += innernodetypes.get(typ, nodes.literal)(rawtext, text, classes=['xref'])
|
pnode += innernodetypes.get(typ, nodes.literal)(rawtext, text, classes=['xref'])
|
||||||
@ -153,6 +154,7 @@ specific_docroles = {
|
|||||||
|
|
||||||
'ref': xfileref_role,
|
'ref': xfileref_role,
|
||||||
'token' : xfileref_role,
|
'token' : xfileref_role,
|
||||||
|
'term': xfileref_role,
|
||||||
|
|
||||||
'menuselection' : menusel_role,
|
'menuselection' : menusel_role,
|
||||||
'file' : emph_literal_role,
|
'file' : emph_literal_role,
|
||||||
|
@ -691,6 +691,11 @@ dt:target,
|
|||||||
background-color: #fbe54e;
|
background-color: #fbe54e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dl.glossary dt {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
th {
|
th {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
|
@ -591,6 +591,11 @@ dd {
|
|||||||
margin-left: 30px;
|
margin-left: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dl.glossary dt {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
.refcount {
|
.refcount {
|
||||||
color: #060;
|
color: #060;
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,8 @@
|
|||||||
<span class="linkdescr">quick access to all modules</span></p>
|
<span class="linkdescr">quick access to all modules</span></p>
|
||||||
<p class="biglink"><a class="biglink" href="{{ pathto("genindex.rst") }}">General Index</a><br>
|
<p class="biglink"><a class="biglink" href="{{ pathto("genindex.rst") }}">General Index</a><br>
|
||||||
<span class="linkdescr">all functions, classes, terms</span></p>
|
<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%">
|
</td><td width="50%">
|
||||||
<p class="biglink"><a class="biglink" href="{{ pathto("search.rst") }}">Search page</a><br>
|
<p class="biglink"><a class="biglink" href="{{ pathto("search.rst") }}">Search page</a><br>
|
||||||
<span class="linkdescr">search this documentation</span></p>
|
<span class="linkdescr">search this documentation</span></p>
|
||||||
|
@ -211,6 +211,11 @@ class HTMLTranslator(BaseTranslator):
|
|||||||
def visit_index(self, node):
|
def visit_index(self, node):
|
||||||
raise nodes.SkipNode
|
raise nodes.SkipNode
|
||||||
|
|
||||||
|
def visit_glossary(self, node):
|
||||||
|
pass
|
||||||
|
def depart_glossary(self, node):
|
||||||
|
pass
|
||||||
|
|
||||||
# these are only handled specially in the SmartyPantsHTMLTranslator
|
# these are only handled specially in the SmartyPantsHTMLTranslator
|
||||||
def visit_literal_emphasis(self, node):
|
def visit_literal_emphasis(self, node):
|
||||||
return self.visit_emphasis(node)
|
return self.visit_emphasis(node)
|
||||||
|
Loading…
Reference in New Issue
Block a user